From 124878e7a0d2b24cdce730baf171c278810ea866 Mon Sep 17 00:00:00 2001 From: M Date: Sat, 23 May 2026 11:37:09 +0200 Subject: [PATCH] VGA working: DDR3-backed framebuffer via VDMA, solid red screen confirmed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix MIG AXI slave perpetual reset: add NOT gate on ui_clk_sync_rst to produce active-low aresetn for SmartConnect, MIG AXI slave, and VDMA - Fix vga_out stuck in reset: was driven by peripheral_reset (always HIGH); now tied to constant-0 via xlconstant_0 - Fix VDMA stream width: set c_m_axis_mm2s_tdata_width=16 to match 16-bit framebuffer pixel format - Fix VDMA register offsets in assemble.py (all were wrong); fix fill loop branch target; write VSIZE last to trigger DMA - Add tools/probe.py: periodic UART monitor (HALT→READ_PC→DUMP_STATE→UNHALT) - Add MEMORY_ERROR state to memory AXI state machine - Cleanup: remove fill_screen.s, ROM_PROGRAMS.md, mig_a.prj, bdelay tests, unused AXI_RESP_* constants; strip hardcoded paths from build.tcl; update docs and README to reflect working state Co-Authored-By: Claude Sonnet 4.6 --- .claude/rules/architecture/cpu.md | 83 ++ .claude/rules/architecture/memory.md | 65 + .claude/rules/architecture/mig-vivado.md | 138 ++ .claude/rules/debug/debug.md | 118 ++ .claude/rules/process.md | 126 ++ .claude/rules/testing/tests.md | 143 ++ .github/workflows/{tests.yml => test.yml} | 0 .gitignore | 6 + .vscode/mcp.json | 0 CLAUDE.md | 79 +- README.md | 42 +- assemble.py | 152 ++ assemble_pattern.py | 138 ++ build.tcl | 1196 ++++++++++++++++ config/arty-s7-50.xdc | 60 +- config/mig_b.prj | 159 ++ docs/architecture.md | 58 + docs/getting-started.md | 62 + hdl/cpu/cpu.v | 9 + .../instruction_memory_axi.v | 2 + hdl/cpu/memory/memory.vh | 1 + hdl/cpu/memory/memory_axi.v | 11 +- hdl/debug_peripheral/debug_peripheral.v | 33 + hdl/debug_peripheral/debug_peripheral.vh | 1 + hdl/vga_out/vga_out.v | 5 + ip_repo/component.xml | 1273 +++++++++++++++++ ip_repo/xgui/cpu_v1_0.tcl | 10 + rom.mem | 65 + tests/Makefile | 1 + tests/cpu/constants.py | 1 + .../test_debug_dump_state.py | 85 ++ tools/debugger/commands.go | 4 + tools/debugger/opcodes.go | 3 + tools/debugger/ui.go | 43 +- tools/probe.py | 152 ++ 35 files changed, 4221 insertions(+), 103 deletions(-) create mode 100644 .claude/rules/architecture/cpu.md create mode 100644 .claude/rules/architecture/memory.md create mode 100644 .claude/rules/architecture/mig-vivado.md create mode 100644 .claude/rules/debug/debug.md create mode 100644 .claude/rules/process.md create mode 100644 .claude/rules/testing/tests.md rename .github/workflows/{tests.yml => test.yml} (100%) create mode 100644 .vscode/mcp.json create mode 100644 assemble.py create mode 100644 assemble_pattern.py create mode 100644 build.tcl create mode 100755 config/mig_b.prj create mode 100644 docs/architecture.md create mode 100644 docs/getting-started.md create mode 100644 ip_repo/component.xml create mode 100644 ip_repo/xgui/cpu_v1_0.tcl create mode 100644 rom.mem create mode 100644 tests/cpu/integration_tests/test_debug_dump_state.py create mode 100644 tools/probe.py diff --git a/.claude/rules/architecture/cpu.md b/.claude/rules/architecture/cpu.md new file mode 100644 index 0000000..79e837f --- /dev/null +++ b/.claude/rules/architecture/cpu.md @@ -0,0 +1,83 @@ +--- +paths: hdl/cpu/** +--- + +# CPU Architecture + +**Last updated**: 2026-01-05 +**Sources**: [cpu.v](hdl/cpu/cpu.v), [cpu_core_params.vh](hdl/cpu/cpu_core_params.vh) + +RV32I soft core, 3-stage pipeline. No M/F/D extensions, no multiplication. + +## Pipeline Stages + +**Stage 1: Fetch/Decode/Execute** +- Fetch instruction (AXI), decode, execute ALU/comparator +- Outputs: `w_Alu_Result`, `w_Compare_Result`, `w_Instruction_Valid` + +**Stage 2: Memory/Wait** +- Issue AXI read/write for loads/stores +- Pipeline registers: `r_S2_*` (Valid, Alu_Result, Load_Data, Rd, Write_Enable) +- Stalls while memory operations complete + +**Stage 3: Writeback** +- Write ALU result, load data, immediate, or PC+4 to register file +- Writeback mux selects source based on `r_S3_Wb_Src` + +## Timing + +**Cycles per instruction**: Variable +- S1: 1 cycle (ALU/decode) +- S2: 0 cycles (no memory) or 2-4 cycles (load/store AXI transaction) +- S3: 1 cycle (writeback) + +Tests use `PIPELINE_CYCLES` from [tests/cpu/constants.py](tests/cpu/constants.py) as conservative wait. + +## Stall Logic + +```verilog +w_Stall_S1 = w_Debug_Stall + || !i_Init_Calib_Complete + || (r_S2_Valid && (w_S2_Is_Load || w_S2_Is_Store) + && !(w_Mem_Read_Done || w_Mem_Write_Done)); +``` + +CPU stalls when: +- `w_Debug_Stall`: Debug peripheral halted CPU +- `!i_Init_Calib_Complete`: DDR3 MIG not ready +- Memory op in progress: S2 has valid load/store waiting for AXI completion + +## Hazards + +**Status**: No hazard detection or forwarding implemented. + +**Workaround**: Tests insert NOPs or wait `PIPELINE_CYCLES` between dependent instructions. + +## PC (Program Counter) + +**Normal**: `PC += 4` after instruction completes +**Branch taken**: `PC = PC + immediate` +**Jump**: `PC = target address` +**Reset**: `PC = 0` + +Mux control: `w_Pc_Alu_Mux_Select` chooses between `PC+4` and `w_Alu_Result` + +## Register File + +32 registers × 32 bits (XLEN=32) +- Read ports: Rs1, Rs2 (from instruction[19:15], [24:20]) +- Write port: Rd (r_S3_Rd), enabled by `w_Wb_Enable` +- Sources: ALU, comparator, immediate, PC+4, load data +- Register 0 always reads 0 (RISC-V spec) + +See [register_file.v](hdl/cpu/register_file/register_file.v) + +## Memory Interface + +Two separate AXI4-Lite masters: +1. **Instruction memory**: Fetch-only (read) +2. **Data memory**: Loads/stores + +No error handling - assumes all transactions succeed. + +See [memory.md](memory.md) for AXI protocol details. diff --git a/.claude/rules/architecture/memory.md b/.claude/rules/architecture/memory.md new file mode 100644 index 0000000..0acc8e2 --- /dev/null +++ b/.claude/rules/architecture/memory.md @@ -0,0 +1,65 @@ +--- +paths: + - hdl/cpu/memory/** + - hdl/cpu/instruction_memory/** +--- + +# Memory Architecture + +**Last updated**: 2026-01-05 +**Sources**: [memory_axi.v](hdl/cpu/memory/memory_axi.v), [memory.vh](hdl/cpu/memory/memory.vh) + +AXI4-Lite memory interface for CPU instruction/data access. + +## Memory Map + +| Region | Start | End | Size | Backing | Notes | +|--------|-------|-----|------|---------|-------| +| ROM | `0x0000` | `0x0FFF` | 4 KB | BRAM | Bootstrap, read-only | +| RAM | `0x1000` | (varies) | 256 MB | DDR3 (MIG) | Main memory, stack, heap | +| Peripherals | TBD | TBD | TBD | Memory-mapped | Debug UART (future) | + +**ROM boundary**: `ROM_BOUNDARY_ADDR = 0x1000` - see [memory.vh](hdl/cpu/memory/memory.vh) and [tests/cpu/constants.py](tests/cpu/constants.py) + +## AXI State Machine + +**States**: `IDLE` → `READ_SUBMITTING` → `READ_AWAITING` → `READ_SUCCESS` +**Write**: `IDLE` → `WRITE_SUBMITTING` → `WRITE_AWAITING` → `WRITE_SUCCESS` + +**Latency**: 2-4 cycles (BRAM fast, DDR3 slower) + +## Load/Store Types + +**Supported**: +- `LW/SW`: 32-bit word +- `LH/LHU/SH`: 16-bit halfword (signed/unsigned) +- `LB/LBU/SB`: 8-bit byte (signed/unsigned) + +**Byte alignment**: AXI write strobes (`wstrb`) enable byte-level writes without read-modify-write. Load data extraction uses `i_Addr[1:0]` offset with sign-extension for LB/LH. + +See [memory_axi.v](hdl/cpu/memory/memory_axi.v) for alignment logic. + +## Access Patterns + +**Instruction fetch**: +- Address < 0x1000: Fast BRAM access +- Address >= 0x1000: AXI transaction to DDR3 +- Interface: `s_instruction_memory_axil_*` (read-only) + +**Data load/store**: +- Typically RAM (ROM is read-only) +- Interface: `s_data_memory_axil_*` (read/write) + +## Constants + +Constants defined in `.vh` files: +- [memory.vh](hdl/cpu/memory/memory.vh): `LS_TYPE_*`, state machine states, ROM boundary +- [cpu_core_params.vh](hdl/cpu/cpu_core_params.vh): Register widths, control signal widths + +Python mirror: [tests/cpu/constants.py](tests/cpu/constants.py) - must stay in sync with `.vh` files. + +## Current Status + +- DDR3 operational @ 81.25 MHz (MIG initialized 2026-01-04) +- No memory protection (CPU can write to ROM, slave may ignore) +- No alignment checks (misaligned loads/stores may behave unexpectedly) diff --git a/.claude/rules/architecture/mig-vivado.md b/.claude/rules/architecture/mig-vivado.md new file mode 100644 index 0000000..7bdc273 --- /dev/null +++ b/.claude/rules/architecture/mig-vivado.md @@ -0,0 +1,138 @@ +--- +paths: + - hdl/reset_timer.v + - config/arty-s7-50.xdc +--- + +# MIG DDR3 Configuration (Arty S7-50) + +**Last updated**: 2026-01-05 +**Status**: ✅ MIG CALIBRATION SUCCESSFUL - DDR3 functional @ 81.25 MHz + +## Critical Success Factors + +**MUST HAVE** for DDR3 calibration: +1. **200 MHz reference clock** to MIG `clk_ref_i` (MANDATORY for IDELAYCTRL - won't calibrate without it) +2. **Bank 34 only** for all DDR3 signals (SSTL135 @ 1.35V) +3. **200µs reset hold time** for MIG `sys_rst` (20,000 cycles @ 100 MHz) +4. CPU reset from `ui_clk_sync_rst`, NOT `peripheral_reset` (stays HIGH) + +**Vivado project**: NOT in repository (binary files, too large). Recreate from notes below if needed. + +## Working MIG Configuration + +**Memory part**: MT41K128M16XX-15E +- 16-bit DDR3L, 128 Mb, -15E speed grade, **1.35V operation** +- I/O standard: **SSTL135** (NOT SSTL15) +- Bank: **Bank 34 only** (all byte groups: DQ[0-15], Address/Ctrl) +- Internal Vref: ENABLED (0.675V for Bank 34) + +**MIG Parameters**: +- AXI interface: 128-bit data width (SmartConnect converts from CPU's 32-bit) +- Address width: 28-bit +- Input clock period: 10000 ps (100 MHz) → `sys_clk_i` +- Memory clock: 3077 ps (324.99 MHz, MIG-generated internally) +- Reference clock: **200 MHz (5000 ps)** → `clk_ref_i` ⚠️ CRITICAL +- PHY ratio: 4:1 +- **UI clock: 81.25 MHz** (324.99 MHz ÷ 4) - CPU runs at this speed + +## Clock Architecture + +**Input**: 12 MHz from board oscillator (pin F14, LVCMOS33) + +**Clock Wizard** (MMCM): +- VCO: 12 MHz × 50 = 600 MHz +- Output 1: **100 MHz** (÷6) → MIG `sys_clk_i` + reset_timer +- Output 2: **200 MHz** (÷3) → MIG `clk_ref_i` ⚠️ CRITICAL + +**MIG-generated**: +- Memory interface: 324.99 MHz (internal) +- UI clock: **81.25 MHz** (CPU domain) + +## Reset Architecture + +**Custom reset timer** ([reset_timer.v](hdl/reset_timer.v)): +- Counts **20,000 cycles @ 100 MHz = 200µs** +- Holds MIG `sys_rst` LOW during startup (ACTIVE-LOW reset) +- Releases when count completes +- Parameters: `COUNTER_WIDTH=15`, `HOLD_CYCLES=20000` + +**CPU reset**: +- Connected to MIG's `ui_clk_sync_rst` (ACTIVE-HIGH, synchronized to ui_clk) +- ❌ **NOT using** `proc_sys_reset_0/peripheral_reset` (stays perpetually HIGH - known issue) + +## Bank Selection - CRITICAL + +**Why Bank 34 only**: +- Bank 34: Powered at **1.35V** for DDR3L (SSTL135) +- Bank 15: Has RGB LEDs requiring **3.3V** (LVCMOS33) - voltage conflict with DDR3 +- Bank 14: UART signals (**3.3V** LVCMOS33) +- **Separate banks = independent VCCO rails** = no voltage conflict + +**All DDR3 signals must be on Bank 34**: +- DQ[0-7] (Byte Group T0) +- DQ[8-15] (Byte Group T1) +- Address/Control-0 (Byte Group T2) +- Address/Control-1 (Byte Group T3) + +## Key Lessons + +1. **200 MHz ref_clk is MANDATORY**: DDR3 WILL NOT calibrate without it (IDELAYCTRL requirement) +2. **Bank voltage isolation**: Check board schematic for VCCO rail voltages before assigning pins +3. **SSTL135 for DDR3L**: Use SSTL135 (1.35V), NOT SSTL15 (1.5V) - wrong I/O standard prevents calibration +4. **Reset timing matters**: MIG requires minimum 200µs reset hold time +5. **ui_clk_sync_rst for AXI resets**: Use inverted `ui_clk_sync_rst` (via NOT gate `util_vector_logic_1`) for SmartConnect `aresetn`, MIG `aresetn`, and VDMA `axi_resetn`. proc_sys_reset_0's `peripheral_aresetn` stays stuck LOW (never deaserts) so MIG AXI slave never responds. The NOT-gated `ui_clk_sync_rst` is already in the 81.25MHz domain (no CDC issue) and properly deaserts after MIG calibration. + +## Vivado Block Diagram Components + +**If recreating from scratch**: + +1. **Clock Wizard**: + - Input: 12 MHz + - Outputs: 100 MHz (sys_clk), 200 MHz (ref_clk) + +2. **Reset Timer** (custom Verilog): + - Input: 100 MHz clock, Clock Wizard `locked` + - Output: ACTIVE-LOW reset to MIG `sys_rst` + - Hold: 20,000 cycles + +3. **MIG 7-Series**: + - Part: MT41K128M16XX-15E + - Clocks: 100 MHz sys_clk_i, 200 MHz clk_ref_i + - AXI: 128-bit interface + - Bank: 34 (SSTL135) + - Internal Vref: ENABLED + +4. **AXI SmartConnect**: + - Masters: CPU instruction + data (32-bit each) + - Slave: MIG (128-bit) + - Handles width conversion + +5. **Processor System Reset**: + - Generates AXI reset signals for MIG/SmartConnect + - **Do NOT use for CPU reset** (use ui_clk_sync_rst instead) + +## Troubleshooting + +**Calibration fails**: +- Check 200 MHz ref_clk connected to MIG `clk_ref_i` +- Verify Bank 34 for all DDR3 pins +- Verify SSTL135 I/O standard (not SSTL15) +- Check reset hold time (minimum 200µs) + +**Wrong data/corruption**: +- Verify AXI connections (SmartConnect to MIG) +- Check ui_clk domain crossing +- Verify CPU reset from ui_clk_sync_rst + +**Build errors**: +- Vivado project not in repo - must recreate block diagram +- Constraint file: [arty-s7-50.xdc](config/arty-s7-50.xdc) has pin assignments + +## Reference + +**Board**: Arty S7-50 (xc7s50-csga324, speed grade -1) +**Memory**: 256 MB DDR3L @ 1.35V (MT41K128M16XX-15E) +**Oscillator**: 12 MHz (pin F14) + +See Arty S7 reference manual for schematic and VCCO rail assignments. diff --git a/.claude/rules/debug/debug.md b/.claude/rules/debug/debug.md new file mode 100644 index 0000000..4fe6bbd --- /dev/null +++ b/.claude/rules/debug/debug.md @@ -0,0 +1,118 @@ +--- +paths: + - hdl/debug_peripheral/** + - tools/debugger/** +--- + +# Debug Protocol + +**Last updated**: 2026-01-05 +**Sources**: [debug_peripheral.v](hdl/debug_peripheral/debug_peripheral.v), [debug_peripheral.vh](hdl/debug_peripheral/debug_peripheral.vh) + +UART debug peripheral for CPU control via serial commands (115200 baud, 8N1). + +## Overview + +**Module**: [debug_peripheral.v](hdl/debug_peripheral/debug_peripheral.v) + +**Ports**: +- `i_Uart_Tx_In` - UART RX from host (host → FPGA) +- `o_Uart_Rx_Out` - UART TX to host (FPGA → host) +- `o_Halt_Cpu` - Stops CPU when high +- `o_Reset_Cpu` - Holds CPU in reset when high +- `i_PC[31:0]` - Program counter (for READ_PC command) + +## Command Set + +Single-byte opcodes: + +| Opcode | Command | Action | Response | +|--------|---------|--------|----------| +| `0x00` | NOP | No operation | None | +| `0x01` | RESET | Assert CPU reset | None | +| `0x02` | UNRESET | Deassert CPU reset | None | +| `0x03` | HALT | Halt CPU | None | +| `0x04` | UNHALT | Resume CPU | None | +| `0x05` | PING | Test connectivity | `0xAA` | +| `0x06` | READ_PC | Read program counter | 4 bytes (little-endian) | +| `0x07` | WRITE_PC | Write PC (stub) | None | +| `0x08` | READ_REGISTER | Read register (stub) | TBD | +| `0x09` | WRITE_REGISTER | Write register (stub) | TBD | + +**Implemented**: NOP, RESET, UNRESET, HALT, UNHALT, PING, READ_PC +**Stubs**: WRITE_PC, READ_REGISTER, WRITE_REGISTER (opcodes defined, logic incomplete) + +## State Machine + +**States**: `IDLE` → `DECODE_AND_EXECUTE` → `IDLE` + +**Flow**: +1. IDLE: Wait for UART byte +2. DECODE_AND_EXECUTE: Execute opcode, queue response (if any), return to IDLE + +**Output buffer**: 256-byte FIFO for responses (PING → `0xAA`, READ_PC → 4 bytes, etc.) + +## UART Timing + +**Baud rate**: 115200 bps +**CPU clock**: 81.25 MHz (MIG ui_clk) +**Clocks per bit**: 81,250,000 / 115,200 ≈ **706 clocks** + +**Modules**: [uart_receiver.v](hdl/debug_peripheral/uart_receiver.v), [uart_transmitter.v](hdl/debug_peripheral/uart_transmitter.v) + +**Interface**: +- RX: `o_Rx_DV` pulses for 1 cycle when byte received, `o_Rx_Byte` contains data +- TX: Assert `i_Tx_DV` for 1 cycle with `i_Tx_Byte`, wait for `o_Tx_Done` pulse + +## Go Debugger Tool + +**Location**: [tools/debugger/](tools/debugger/) +**Run**: `go run tools/debugger/main.go` + +**Status**: +- ✓ Halt, Unhalt, Reset, Unreset, Ping implemented in Go tool +- ✗ Read PC, Write PC, Read/Write Register not yet in tool +- ✓ All basic commands work on FPGA (PING returns `0xAA`) + +**Opcode constants**: See [opcodes.go](tools/debugger/opcodes.go) - must match [debug_peripheral.vh](hdl/debug_peripheral/debug_peripheral.vh) + +## Testing + +**Integration tests**: See [tests/cpu/integration_tests/](tests/cpu/integration_tests/) +- [test_debug_ping.py](tests/cpu/integration_tests/test_debug_ping.py) - PING command verification +- [test_debug_read_pc.py](tests/cpu/integration_tests/test_debug_read_pc.py) - READ_PC command verification + +**Test pattern**: +```python +from cpu.utils import uart_send_byte, uart_wait_for_byte +from cpu.constants import DEBUG_OP_PING + +# Send PING +await uart_send_byte(dut.i_Clock, dut.i_Uart_Tx_In, dut.cpu.debug.uart_rx.o_Rx_DV, DEBUG_OP_PING) + +# Wait for response +response = await uart_wait_for_byte(dut.i_Clock, dut.o_Uart_Rx_Out, dut.cpu.debug.uart_tx.o_Tx_Done) + +assert response == 0xAA # PING_RESPONSE_BYTE +``` + +## Pin Assignments + +**UART**: See [arty-s7-50.xdc](config/arty-s7-50.xdc) +- TX (FPGA → host): Pin D10, Bank 14, LVCMOS33 +- RX (host → FPGA): Pin A9, Bank 14, LVCMOS33 + +**Bank 14**: 3.3V I/O (separate from Bank 34's 1.35V DDR3) + +## Future Extensions + +**Register access**: WRITE_PC, READ_REGISTER, WRITE_REGISTER need: +- Ports to CPU register file (`o_Reg_Write_Enable`, `o_Reg_Write_Addr`, `o_Reg_Write_Data`) +- Multi-byte command support (opcode + address + data) +- Currently commented out in [debug_peripheral.v](hdl/debug_peripheral/debug_peripheral.v) + +**Memory access**: Read/write arbitrary addresses +**Breakpoints**: Trigger halt on PC match +**Single-step**: Execute one instruction then halt + +See commented-out ports in [debug_peripheral.v](hdl/debug_peripheral/debug_peripheral.v) lines 144-176 for register access stubs. diff --git a/.claude/rules/process.md b/.claude/rules/process.md new file mode 100644 index 0000000..0ec7f18 --- /dev/null +++ b/.claude/rules/process.md @@ -0,0 +1,126 @@ +# Documentation Process + +**Last updated**: 2026-01-05 + +This document defines how to write and maintain documentation for this project. + +## Core Principle + +Update documentation **continuously as you learn**, without explicit instruction. When user corrects your understanding, STOP and update docs immediately before continuing. + +Proactive notification: Alert user when identifying opportunities for skills/agents/MCP servers, missing documentation, or structural improvements. + +## Key Guidelines + +**1. Specificity over vagueness** +- ✓ "Run `make test` from `/home/emma/gpu/tests/`" +- ✗ "You might want to run tests" + +**2. Keep it short** +- Target: ~200 words per section, ~2000 words per file +- Don't document granular details (individual test files, function implementations) +- Code should be self-documenting + +**3. Front-load the why** +- ✓ "Use Verilator for fast simulation + cocotb integration. See `tests/Makefile`." +- ✗ "Verilator is used. It has features." + +**4. Avoid over-constraint** +- ✓ "Prefer editing test files when debugging" +- ✗ "NEVER modify HDL without tests" +- Exception: Unsafe actions warrant clear prohibitions + +**5. Don't over-optimize for LLMs** +- Trust contextual understanding +- Skip pedantic rules that add verbosity without clarity +- Expand ambiguous acronyms only (not UART, DDR3, BRAM) + +## When to Update + +Update immediately when: +- Discovering patterns, gotchas, or state changes +- Fixing errors or ambiguities +- Adding new modules/tests/tools +- Learning why something works (or doesn't) +- **User corrects you** - STOP, update docs BEFORE continuing +- Realizing a guideline is wrong/pedantic - fix it + +Before commits: Verify doc timestamps match source file mtimes. + +## When to Reorganize + +Only if: +- Information is in wrong place +- Two docs overlap (consolidate) +- File exceeds ~2000 words (split with links) +- New logical groupings emerge + +Do NOT rewrite repeatedly for style - preserve learned context. + +## Evaluation Checklist + +After updates, verify: +1. **Specificity**: Can someone follow without questions? +2. **Clarity**: Is path to answer obvious? +3. **Brevity**: Could this be shorter without losing meaning? +4. **Structure**: Right place in hierarchy? +5. **Completeness**: Success and failure paths covered? + +If "no" to any, revise before finishing. + +## Language & Tone + +- **Imperative**: "Run tests" not "you can run tests" +- **Concrete**: "ALU doesn't handle SRA; add test" not "there might be issues" +- **Honest**: "Blocked on MIG initialization. Here's why." + +## Safe Editing + +✓ **Safe**: +- Update docs when learning +- Add sections for new modules +- Fix typos, clarify sentences +- Link to external resources +- Add test/command examples + +✗ **Unsafe**: +- Delete information (move/consolidate instead) +- Break links between docs +- Add outdated/speculative info + +## What to Document + +- **Patterns**: Cross-cutting behaviors, common approaches +- **Setup**: Environment, tools, commands +- **Architecture**: Module purposes, how they fit together +- **Constraints**: Critical requirements (DDR3 bank selection, timing) +- **Gotchas**: Non-obvious issues, known bugs + +Don't document: +- Individual test files (only testing patterns) +- Function-level implementations (read code) +- Lists of every file (use git ls-files) +- Obvious information Claude can infer + +## Path-Scoped Rules + +This project uses path-scoped rules in `.claude/rules/`: +- Files auto-load when working with matching paths +- Reduces token usage (only load relevant context) +- YAML frontmatter specifies paths: + +```yaml +--- +paths: hdl/cpu/** +--- +``` + +Keep rules focused and under word targets. + +## Critical: This Document Applies to Itself + +When revising this file: +1. Does new guidance conflict with existing rules? +2. Is example clear and actionable? +3. Could future Claude follow unambiguously? +4. Rewrite if unclear before committing. diff --git a/.claude/rules/testing/tests.md b/.claude/rules/testing/tests.md new file mode 100644 index 0000000..87b403a --- /dev/null +++ b/.claude/rules/testing/tests.md @@ -0,0 +1,143 @@ +--- +paths: tests/** +--- + +# Test Environment + +**Last updated**: 2026-01-05 +**Sources**: [Makefile](tests/Makefile), [utils.py](tests/cpu/utils.py), [constants.py](tests/cpu/constants.py) + +cocotb (Python) + Verilator (C++) test framework for CPU verification. + +## Running Tests + +```bash +cd tests +source ./test_env/bin/activate # CRITICAL: Activate venv first +make TEST_TYPE=unit # Unit tests only +make TEST_TYPE=integration # Integration tests only +make TEST_TYPE=all # Both (cleans between runs) +make TEST_TYPE=integration TEST_FILE=test_add_instruction # Single test +``` + +**Must activate venv** - tests fail with import errors otherwise. + +## Test Types + +**Unit tests** ([tests/cpu/unit_tests/](tests/cpu/unit_tests/)): +- Test individual modules (ALU, register file, control unit, memory) +- Harness: `cpu_unit_tests_harness.v` +- Examples: `test_arithmetic_logic_unit.py`, `test_comparator_unit.py` + +**Integration tests** ([tests/cpu/integration_tests/](tests/cpu/integration_tests/)): +- Test full CPU instruction execution (fetch → decode → execute → writeback) +- Harness: `cpu_integration_tests_harness.v` +- Examples: `test_add_instruction.py`, `test_beq_instruction.py`, `test_lw_instruction.py` + +## Common Test Pattern + +```python +import cocotb +from cocotb.clock import Clock +from cocotb.triggers import ClockCycles +from cpu.utils import gen_r_type_instruction, write_instructions +from cpu.constants import * + +@cocotb.test() +async def test_add_instruction(dut): + """Test ADD R-type instruction""" + + # Start clock + clock = Clock(dut.i_Clock, 1, "ns") + cocotb.start_soon(clock.start()) + + # Generate ADD instruction: rd=3, rs1=1, rs2=2 + add_instr = gen_r_type_instruction( + rd=3, funct3=FUNC3_ALU_ADD_SUB, rs1=1, rs2=2, funct7=0 + ) + + # Write to ROM + write_instructions(dut.cpu.rom_memory, 0x0, [add_instr]) + + # Set register values + dut.cpu.register_file.registers[1].value = 5 + dut.cpu.register_file.registers[2].value = 3 + + # Reset + await reset_cpu(dut) + + # Wait for instruction completion + await ClockCycles(dut.i_Clock, PIPELINE_CYCLES) + + # Verify result + assert dut.cpu.register_file.registers[3].value == 8 +``` + +## Utilities (tests/cpu/utils.py) + +**Instruction generators** - create RISC-V instruction encodings: +- `gen_r_type_instruction(rd, funct3, rs1, rs2, funct7)` - R-type (ADD, SUB, AND, OR, XOR, SLT, shifts) +- `gen_i_type_instruction(opcode, rd, funct3, rs1, imm)` - I-type (ADDI, loads, JALR) +- `gen_s_type_instruction(funct3, rs1, rs2, imm)` - S-type (stores) +- `gen_b_type_instruction(funct3, rs1, rs2, offset)` - B-type (branches) +- `gen_u_type_instruction(opcode, rd, imm)` - U-type (LUI, AUIPC) +- `gen_j_type_instruction(rd, imm)` - J-type (JAL) + +**Memory helpers**: +- `write_word_to_mem(mem_array, addr, value)` - 32-bit little-endian write +- `write_half_to_mem(mem_array, addr, value)` - 16-bit little-endian +- `write_byte_to_mem(mem_array, addr, value)` - 8-bit +- `write_instructions(mem_array, base_addr, instructions)` - Write instruction list +- `write_instructions_rom(mem_array, base_addr, instructions)` - ROM variant (word-indexed) + +**UART helpers**: +- `uart_send_byte(clock, i_rx_serial, o_rx_dv, data_byte)` - Send byte over UART RX +- `uart_send_bytes(clock, i_rx_serial, o_rx_dv, byte_array)` - Send multiple bytes +- `uart_wait_for_byte(clock, i_tx_serial, o_tx_done)` - Receive byte from UART TX + +**Reset/setup**: +- `reset_cpu(dut)` - Reset CPU and wait for DDR3 calibration +- `setup_cpu_test(dut)` - Clock + reset + +## Constants (tests/cpu/constants.py) + +**Don't duplicate constant values in docs** - reference the file instead. + +**Contains**: +- Opcodes: `OP_R_TYPE`, `OP_I_TYPE`, `OP_LOAD`, `OP_STORE`, `OP_B_TYPE`, `OP_J_TYPE`, etc. +- Function codes: `FUNC3_ALU_ADD_SUB`, `FUNC3_BRANCH_BEQ`, etc. +- ALU selectors: `ALU_SEL_ADD`, `ALU_SEL_SUB`, `ALU_SEL_AND`, etc. +- Debug opcodes: `DEBUG_OP_HALT`, `DEBUG_OP_PING`, `DEBUG_OP_READ_PC`, etc. +- Timing: `CLOCK_FREQUENCY`, `UART_BAUD_RATE`, `UART_CLOCKS_PER_BIT`, `PIPELINE_CYCLES` +- Memory: `ROM_BOUNDARY_ADDR = 0x1000` + +## UART Timing + +**Baud rate**: 115200 +**CPU clock**: 81.25 MHz (MIG ui_clk) +**Clocks per bit**: 81,250,000 / 115,200 ≈ **706 clocks** + +Use `uart_send_byte()` / `uart_wait_for_byte()` from [utils.py](tests/cpu/utils.py) - timing handled internally. + +## Makefile + +**Auto-discovery**: +- Finds all `.v` and `.vh` files: `find $(SRC_DIR) -name "*.v" -o -name "*.vh"` +- Adds all subdirectories as Verilator include paths + +**Key variables**: +- `SIM=verilator` - Simulator +- `TOPLEVEL` - Top-level module (set by TEST_TYPE) +- `MODULE` - Python test modules to run +- `VERILOG_SOURCES` - All Verilog files + +## Debugging Tests + +**Waveforms**: Verilator generates `.vcd` files - view with GTKWave +**Logging**: cocotb has built-in logging (`dut._log.info()`) +**ILA cores**: For FPGA debugging (not sim), see [arty-s7-50.xdc](config/arty-s7-50.xdc) + +**Common issues**: +- Import errors: Activate venv (`source test_env/bin/activate`) +- Timing failures: Increase wait cycles (`PIPELINE_CYCLES` is conservative) +- UART failures: Check clock frequency matches constant (`81.25 MHz`) diff --git a/.github/workflows/tests.yml b/.github/workflows/test.yml similarity index 100% rename from .github/workflows/tests.yml rename to .github/workflows/test.yml diff --git a/.gitignore b/.gitignore index db40ef4..21d7625 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,9 @@ tests/sim_build # Debugger tools/debugger/debugger tools/debugger/logs/ + +# Vivado logs (generated locally) +vivado.jou +vivado.log +vivado*.backup.jou +vivado*.backup.log diff --git a/.vscode/mcp.json b/.vscode/mcp.json new file mode 100644 index 0000000..e69de29 diff --git a/CLAUDE.md b/CLAUDE.md index 8d52a37..1416e83 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,50 +1,61 @@ # GPU FPGA Project -Minimal computer on Arty S7-50: RV32I CPU + VGA + UART debug. +**Last updated**: 2026-05-23 -## Commands +Minimal computer on Arty S7-50 FPGA: RISC-V RV32I soft core + VGA video + UART debug. + +## Current Status + +- **CPU**: RV32I (no M/F/D extensions), unit + integration tests passing +- **Memory**: DDR3 operational @ 81.25 MHz (MIG initialized 2026-01-04) +- **Video**: VGA working — DDR3-backed framebuffer via VDMA +- **Debug**: UART debug peripheral working (`tools/debugger`, `tools/probe.py`) +- **Blocker**: None + +## Quick Start ```bash -# Run tests (must activate venv first) +# Run tests cd tests && source test_env/bin/activate && make -# Test types: unit, integration, vga, all -make TEST_TYPE=unit -make TEST_TYPE=integration -make TEST_TYPE=vga -make TEST_TYPE=all +# Debug via UART +go run tools/debugger/main.go -# Single test file -make TEST_TYPE=integration TEST_FILE=test_add_instruction - -# Debug tool -cd tools && go run ./debugger +# Build (future - not yet set up) +# cd tools/compiler && make ``` -## Memory Map +## Key Directories -``` -0x80000000 - 0x80000FFF: Boot ROM (4KB BRAM) -0x80001000 - 0x87F1DFFF: RAM (~127MB DDR3) -0x87F1E000 - 0x87F8EFFF: Framebuffer 0 (640x480x12bpp) -0x87F8F000 - 0x87FFFFFF: Framebuffer 1 (640x480x12bpp) -``` +- `hdl/` - Verilog sources (cpu/, debug_peripheral/, vga_out/) +- `tests/` - Verilator + cocotb tests (unit_tests/, integration_tests/) +- `tools/` - debugger/ (Go UART CLI), probe.py (Python monitor) +- `config/` - arty-s7-50.xdc (pin constraints), mig_b.prj (MIG config) +- `ip_repo/` - Packaged CPU IP for Vivado block design +- `docs/` - Architecture and getting started guides + +## Documentation System + +This project uses **path-scoped rules** in `.claude/rules/` that auto-load when you work with matching files: + +- **Always loaded**: `.claude/rules/process.md` (documentation workflow) +- **When editing CPU**: `.claude/rules/architecture/cpu.md` +- **When editing memory**: `.claude/rules/architecture/memory.md` +- **When editing tests**: `.claude/rules/testing/tests.md` +- **When editing debug**: `.claude/rules/debug/debug.md` +- **When editing constraints**: `.claude/rules/architecture/mig-vivado.md` -- PC starts at 0x80000000 on reset -- ROM_BOUNDARY_ADDR = 0x80000FFF -- Framebuffers are 4K-aligned for DMA +You don't need to manually read docs - the relevant rules load automatically based on which files you're working with. -## Constraints +## Critical Constraints -- CPU runs at 81.25 MHz (MIG ui_clk) -- UART: 115200 baud, 706 clocks/bit -- 3-stage pipeline, no hazard detection - insert NOPs between dependent instructions -- DDR3 requires 200 MHz ref_clk, Bank 34 only (1.35V) +- **DDR3**: Requires 200 MHz ref_clk, Bank 34 only (voltage isolation) +- **UART**: 115200 baud @ 81.25 MHz ≈ 706 clocks/bit +- **Memory map**: CPU base 0x80000000, ROM 0x80000000-0x80000FFF, RAM 0x80001000+, FB at end +- **Pipeline**: 3-stage, no hazard detection (insert NOPs manually) -## Gotchas +## Next Steps -- Tests fail with import errors if venv not activated -- CPU reset must use MIG's `ui_clk_sync_rst`, NOT `peripheral_reset` -- No alignment checks - misaligned loads/stores behave unexpectedly -- Constants in `.vh` files must stay in sync with `tests/cpu/constants.py` -- Vivado project not in repo - recreate from `config/arty-s7-50.xdc` +1. Draw something more interesting than a solid color (shapes, sprites, text) +2. Add game controller peripheral +3. Network peripheral (TBD) diff --git a/README.md b/README.md index e2c0354..bbe7639 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # RISC-V FPGA Computer -[![Tests](https://github.com/DustTheory/computer/actions/workflows/tests.yml/badge.svg)](https://github.com/DustTheory/computer/actions/workflows/tests.yml) +[![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. @@ -10,21 +10,20 @@ A minimal computer system targeting the Arty S7-50 FPGA: - Custom RISC-V RV32I CPU core (no multiply/divide, no floating point) - VGA video output (640x480) - DDR3 memory interface +- Game-focused peripherals (TBD) This is a learning project to understand computer architecture from the ground up. ## Current Status -- **CPU**: RV32I core with 3-stage pipeline, no caches, no M extension yet -- **Memory**: DDR3 via AXI4-Lite (full AXI4 not implemented yet) -- **Video**: 640x480 VGA with double-buffered framebuffer, VDMA for display -- **Debug**: UART interface enables halting, stepping, register/memory inspection -- **Input**: Not implemented +- CPU core: RV32I implemented and passing tests +- Memory: DDR3 operational @ 81.25 MHz +- Testing: unit + integration tests passing +- Video: VGA works — DDR3-backed framebuffer via VDMA, 640x480@60Hz +- Debug: UART debug peripheral works (`tools/debugger/`) ## Development Approach -The core CPU is written manually in Verilog, for the love of the game. - **Stack:** - Hardware: Verilog (hand-written, no HLS) - Testing: Verilator + cocotb (Python) @@ -32,36 +31,33 @@ The core CPU is written manually in Verilog, for the love of the game. While auxiliary tools like the debugger are coded with AI assistance, the CPU itself is crafted by hand to deeply understand how processors work. -**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. +**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. There are separate unit and integration tests. -**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. +**Debug Tools:** A UART-based debugger (`tools/debugger/`) allows real-time inspection of the CPU on FPGA - halt/resume, read/write registers, jump through code, get extra debug information. ## Repository Contents - `hdl/` - Verilog source files (CPU, video, peripherals) - `tests/` - Verilator + cocotb tests - `tools/` - Debug utilities and toolchain +- `docs/` - Architecture docs and guides - `config/` - FPGA constraints - -## Setup - -**Dependencies**: Verilator, Python 3, Go - -```bash -# Create Python venv and install test dependencies -cd tests -python3 -m venv test_env -source test_env/bin/activate -pip install cocotb pytest -``` +- `build.tcl` - the build script ## Running Tests +Test dependencies: Verilator, Python 3, cocotb + ```bash cd tests source test_env/bin/activate make TEST_TYPE=unit # Run unit tests make TEST_TYPE=integration # Run integration tests -make TEST_TYPE=vga # Run VGA tests make TEST_TYPE=all # Run all tests ``` + +## Documentation + +- [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 diff --git a/assemble.py b/assemble.py new file mode 100644 index 0000000..cf3125d --- /dev/null +++ b/assemble.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python3 +"""RISC-V assembler: fill framebuffer, init VDMA, then test DDR3 load/store.""" + +def encode_r_type(opcode, rd, funct3, rs1, rs2, funct7): + return (funct7 << 25) | (rs2 << 20) | (rs1 << 15) | (funct3 << 12) | (rd << 7) | opcode + +def encode_i_type(opcode, rd, funct3, rs1, imm): + return ((imm & 0xFFF) << 20) | (rs1 << 15) | (funct3 << 12) | (rd << 7) | opcode + +def encode_s_type(opcode, funct3, rs1, rs2, imm): + imm_11_5 = (imm >> 5) & 0x7F + imm_4_0 = imm & 0x1F + return (imm_11_5 << 25) | (rs2 << 20) | (rs1 << 15) | (funct3 << 12) | (imm_4_0 << 7) | opcode + +def encode_b_type(opcode, funct3, rs1, rs2, imm): + imm_12 = (imm >> 12) & 0x1 + imm_11 = (imm >> 11) & 0x1 + imm_10_5 = (imm >> 5) & 0x3F + imm_4_1 = (imm >> 1) & 0xF + return (imm_12 << 31) | (imm_10_5 << 25) | (rs2 << 20) | (rs1 << 15) | (funct3 << 12) | (imm_4_1 << 8) | (imm_11 << 7) | opcode + +def encode_u_type(opcode, rd, imm): + return (imm << 12) | (rd << 7) | opcode + +def encode_j_type(opcode, rd, imm): + imm_20 = (imm >> 20) & 0x1 + imm_19_12 = (imm >> 12) & 0xFF + imm_11 = (imm >> 11) & 0x1 + imm_10_1 = (imm >> 1) & 0x3FF + return (imm_20 << 31) | (imm_10_1 << 21) | (imm_11 << 20) | (imm_19_12 << 12) | (rd << 7) | opcode + +def tc(value, bits): + """Two's complement encoding for negative immediates.""" + if value < 0: + return (1 << bits) + value + return value + +# Register numbers +t0, t1, t2, t3, t4, t5 = 5, 6, 7, 8, 9, 10 +zero = 0 + +OP_LUI = 0b0110111 +OP_JAL = 0b1101111 +OP_BRANCH = 0b1100011 +OP_LOAD = 0b0000011 +OP_STORE = 0b0100011 +OP_ALU_I = 0b0010011 +OP_ALU_R = 0b0110011 + +program = [] + +# ── Fill framebuffer ────────────────────────────────────────────────────────── +# t0 = 0x87F1E000 (framebuffer base in DDR3) +# t2 = 0xF000F000 (two red pixels: R=0xF, G=0, B=0 in R[15:12]/G[10:7]/B[4:1]) +# t1 = 153600 (640×480×2 bytes / 4 bytes per SW = word count) + +# 0x00 +program.append(encode_u_type(OP_LUI, t0, 0x87F1E)) # lui t0, 0x87F1E +# 0x04 +program.append(encode_u_type(OP_LUI, t2, 0xF000F)) # lui t2, 0xF000F (= 0xF000F000) +# 0x08 +program.append(encode_u_type(OP_LUI, t1, 0x26)) # lui t1, 0x26000 +# 0x0C +program.append(encode_i_type(OP_ALU_I, t1, 0, t1, tc(-0x800, 12))) # addi t1, t1, -2048 → 153600 + +# fill_loop: offset 0x10 +# 0x10 +program.append(encode_s_type(OP_STORE, 2, t0, t2, 0)) # sw t2, 0(t0) +# 0x14 +program.append(encode_i_type(OP_ALU_I, t0, 0, t0, 4)) # addi t0, t0, 4 +# 0x18 +program.append(encode_i_type(OP_ALU_I, t1, 0, t1, tc(-1, 12))) # addi t1, t1, -1 +# 0x1C branch back to fill_loop (offset 0x10), delta = -12 +program.append(encode_b_type(OP_BRANCH, 1, t1, zero, tc(-12, 13))) # bne t1, zero, -12 + +# ── Configure VDMA (correct offsets from PG020 / component.xml) ─────────────── +# Register map (base = 0x88000000): +# 0x00 MM2S_VDMACR - control (RS=1 bit0, Circular=1 bit1) +# 0x54 MM2S_HSIZE - horizontal size in bytes +# 0x58 MM2S_FRMDLY_STRIDE - [15:0]=stride bytes +# 0x5C MM2S_SA1 - frame buffer start address (frame 1) +# 0x60 MM2S_SA2 - frame buffer start address (frame 2, same for single-buf) +# 0x50 MM2S_VSIZE - vertical lines ← WRITING THIS TRIGGERS DMA, must be last + +# 0x20 +program.append(encode_u_type(OP_LUI, t3, 0x88000)) # lui t3, 0x88000 (= 0x88000000) +# 0x24 +program.append(encode_i_type(OP_ALU_I, t4, 0, zero, 3)) # addi t4, zero, 3 (RS|Circular) +# 0x28 +program.append(encode_s_type(OP_STORE, 2, t3, t4, 0x00)) # sw t4, 0(t3) VDMA[0x00]=0x3 +# 0x2C +program.append(encode_u_type(OP_LUI, t4, 0x87F1E)) # lui t4, 0x87F1E (framebuf addr) +# 0x30 +program.append(encode_s_type(OP_STORE, 2, t3, t4, 0x5C)) # sw t4, 0x5C(t3) SA1 +# 0x34 +program.append(encode_s_type(OP_STORE, 2, t3, t4, 0x60)) # sw t4, 0x60(t3) SA2 (same addr) +# 0x38 +program.append(encode_i_type(OP_ALU_I, t4, 0, zero, 1280)) # addi t4, zero, 1280 +# 0x3C +program.append(encode_s_type(OP_STORE, 2, t3, t4, 0x58)) # sw t4, 0x58(t3) STRIDE +# 0x40 +program.append(encode_s_type(OP_STORE, 2, t3, t4, 0x54)) # sw t4, 0x54(t3) HSIZE +# 0x44 +program.append(encode_i_type(OP_ALU_I, t4, 0, zero, 480)) # addi t4, zero, 480 +# 0x48 VSIZE last — triggers DMA +program.append(encode_s_type(OP_STORE, 2, t3, t4, 0x50)) # sw t4, 0x50(t3) VSIZE → start! + +# ── DDR3 load/store test ────────────────────────────────────────────────────── +# Store 0xABCD0000 to first DDR3 RAM address (0x80001000), then load it back. +# PASS: PC stuck at 0x80000070 +# FAIL: PC stuck at 0x8000006C + +# 0x4C +program.append(encode_u_type(OP_LUI, t0, 0x80001)) # lui t0, 0x80001 (= 0x80001000) +# 0x50 +program.append(encode_u_type(OP_LUI, t1, 0xABCD0)) # lui t1, 0xABCD0 (= 0xABCD0000) +# 0x54 +program.append(encode_s_type(OP_STORE, 2, t0, t1, 0)) # sw t1, 0(t0) +# 0x58 filler ops (pipeline flushers) +program.append(encode_i_type(OP_ALU_I, t2, 0, zero, 42)) # addi t2, zero, 42 +# 0x5C +program.append(encode_i_type(OP_ALU_I, t3, 0, t2, 100)) # addi t3, t2, 100 +# 0x60 +program.append(encode_r_type(OP_ALU_R, t4, 0, t2, t3, 0)) # add t4, t2, t3 +# 0x64 +program.append(encode_i_type(OP_LOAD, t5, 2, t0, 0)) # lw t5, 0(t0) +# 0x68 branch to PASS if t5 == t1, else fall through to FAIL +program.append(encode_b_type(OP_BRANCH, 0, t5, t1, 8)) # beq t5, t1, +8 + +# FAIL — PC = 0x8000006C +# 0x6C +program.append(encode_j_type(OP_JAL, zero, 0)) # jal zero, 0 (infinite loop) + +# PASS — PC = 0x80000070 +# 0x70 +program.append(encode_j_type(OP_JAL, zero, 0)) # jal zero, 0 (infinite loop) + +# ── Output ──────────────────────────────────────────────────────────────────── +print("Assembled program:") +for i, instr in enumerate(program): + print(f" 0x{i*4:04X} (PC=0x{0x80000000+i*4:08X}): {instr:08x}") + +print(f"\nTotal: {len(program)} instructions ({len(program)*4} bytes)") +print(f"\nDDR3 test results (read PC via debugger):") +print(f" PASS = PC stuck at 0x80000070") +print(f" FAIL = PC stuck at 0x8000006C") + +with open('rom.mem', 'w') as f: + for instr in program: + f.write(f"{instr:08x}\n") + +print(f"\nWrote rom.mem") diff --git a/assemble_pattern.py b/assemble_pattern.py new file mode 100644 index 0000000..3ee4a67 --- /dev/null +++ b/assemble_pattern.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python3 +"""Simple RISC-V assembler for a pattern fill program.""" + +def encode_r_type(opcode, rd, funct3, rs1, rs2, funct7): + return (funct7 << 25) | (rs2 << 20) | (rs1 << 15) | (funct3 << 12) | (rd << 7) | opcode + +def encode_i_type(opcode, rd, funct3, rs1, imm): + return ((imm & 0xFFF) << 20) | (rs1 << 15) | (funct3 << 12) | (rd << 7) | opcode + +def encode_s_type(opcode, funct3, rs1, rs2, imm): + imm_11_5 = (imm >> 5) & 0x7F + imm_4_0 = imm & 0x1F + return (imm_11_5 << 25) | (rs2 << 20) | (rs1 << 15) | (funct3 << 12) | (imm_4_0 << 7) | opcode + +def encode_b_type(opcode, funct3, rs1, rs2, imm): + imm_12 = (imm >> 12) & 0x1 + imm_11 = (imm >> 11) & 0x1 + imm_10_5 = (imm >> 5) & 0x3F + imm_4_1 = (imm >> 1) & 0xF + return (imm_12 << 31) | (imm_10_5 << 25) | (rs2 << 20) | (rs1 << 15) | (funct3 << 12) | (imm_4_1 << 8) | (imm_11 << 7) | opcode + +def encode_u_type(opcode, rd, imm): + return (imm << 12) | (rd << 7) | opcode + +def encode_j_type(opcode, rd, imm): + imm_20 = (imm >> 20) & 0x1 + imm_19_12 = (imm >> 12) & 0xFF + imm_11 = (imm >> 11) & 0x1 + imm_10_1 = (imm >> 1) & 0x3FF + return (imm_20 << 31) | (imm_10_1 << 21) | (imm_11 << 20) | (imm_19_12 << 12) | (rd << 7) | opcode + +# Register mapping +regs = { + 'zero': 0, 'ra': 1, 'sp': 2, 'gp': 3, 'tp': 4, + 't0': 5, 't1': 6, 't2': 7, 't3': 8, 't4': 9, 't5': 10, 't6': 11, + 's0': 8, 's1': 9, 's2': 18, 's3': 19, 's4': 20, 's5': 21, 's6': 22, 's7': 23, 's8': 24, 's9': 25, 's10': 26, 's11': 27, + 'a0': 10, 'a1': 11, 'a2': 12, 'a3': 13, 'a4': 14, 'a5': 15, 'a6': 16, 'a7': 17, +} + +# Opcodes +OP_LUI = 0b0110111 +OP_AUIPC = 0b0010111 +OP_JAL = 0b1101111 +OP_JALR = 0b1100111 +OP_BRANCH = 0b1100011 +OP_LOAD = 0b0000011 +OP_STORE = 0b0100011 +OP_ALU_I = 0b0010011 +OP_ALU_R = 0b0110011 + +# Two's complement for negative immediates +def to_twos_complement(value, bits): + if value < 0: + return (1 << bits) + value + return value + +# Assemble the program - creates a horizontal gradient pattern +program = [] + +# lui t0, 0x87F1E # t0 = framebuffer base +program.append(encode_u_type(OP_LUI, regs['t0'], 0x87F1E)) + +# addi t2, zero, 0 # t2 = pattern value (starts at 0) +program.append(encode_i_type(OP_ALU_I, regs['t2'], 0, regs['zero'], 0)) + +# lui t5, 0x0 # t5 = pattern increment +# addi t5, t5, 0x111 # increment by 0x111 each word (creates gradient) +program.append(encode_u_type(OP_LUI, regs['t5'], 0)) +program.append(encode_i_type(OP_ALU_I, regs['t5'], 0, regs['t5'], 0x111)) + +# lui t1, 0x26 +# addi t1, t1, -0x800 # t1 = 153600 (loop counter) +program.append(encode_u_type(OP_LUI, regs['t1'], 0x26)) +program.append(encode_i_type(OP_ALU_I, regs['t1'], 0, regs['t1'], to_twos_complement(-0x800, 12))) + +# fill_loop: +# sw t2, 0(t0) # Store pattern to framebuffer +program.append(encode_s_type(OP_STORE, 2, regs['t0'], regs['t2'], 0)) + +# add t2, t2, t5 # Increment pattern (R-type: add) +program.append(encode_r_type(OP_ALU_R, regs['t2'], 0, regs['t2'], regs['t5'], 0)) + +# addi t0, t0, 4 # Increment address +program.append(encode_i_type(OP_ALU_I, regs['t0'], 0, regs['t0'], 4)) + +# addi t1, t1, -1 # Decrement counter +program.append(encode_i_type(OP_ALU_I, regs['t1'], 0, regs['t1'], to_twos_complement(-1, 12))) + +# bne t1, zero, fill_loop # Loop if counter != 0 +program.append(encode_b_type(OP_BRANCH, 1, regs['t1'], regs['zero'], to_twos_complement(-20, 13))) + +# configure_vdma: +# lui t3, 0x88000 # t3 = VDMA base +program.append(encode_u_type(OP_LUI, regs['t3'], 0x88000 & 0xFFFFF)) + +# lui t4, 0x87F1E # t4 = framebuffer address +program.append(encode_u_type(OP_LUI, regs['t4'], 0x87F1E)) + +# sw t4, 0x18(t3) # MM2S_START_ADDRESS +program.append(encode_s_type(OP_STORE, 2, regs['t3'], regs['t4'], 0x18)) + +# addi t4, zero, 0x500 # t4 = 1280 (HSIZE) +program.append(encode_i_type(OP_ALU_I, regs['t4'], 0, regs['zero'], 0x500)) + +# sw t4, 0x24(t3) # MM2S_HSIZE +program.append(encode_s_type(OP_STORE, 2, regs['t3'], regs['t4'], 0x24)) + +# sw t4, 0x28(t3) # MM2S_STRIDE +program.append(encode_s_type(OP_STORE, 2, regs['t3'], regs['t4'], 0x28)) + +# addi t4, zero, 0x1E0 # t4 = 480 (VSIZE) +program.append(encode_i_type(OP_ALU_I, regs['t4'], 0, regs['zero'], 0x1E0)) + +# sw t4, 0x20(t3) # MM2S_VSIZE +program.append(encode_s_type(OP_STORE, 2, regs['t3'], regs['t4'], 0x20)) + +# addi t4, zero, 0x13 # t4 = 0x13 (control register value) +program.append(encode_i_type(OP_ALU_I, regs['t4'], 0, regs['zero'], 0x13)) + +# sw t4, 0x00(t3) # MM2S_VDMACR (start VDMA) +program.append(encode_s_type(OP_STORE, 2, regs['t3'], regs['t4'], 0x00)) + +# done: jal zero, start # Jump back to beginning for infinite loop +# Offset = 0 - (len(program) * 4) = -84 +program.append(encode_j_type(OP_JAL, regs['zero'], to_twos_complement(-(len(program) * 4), 21))) + +# Print the program +print("Assembled pattern program:") +for i, instr in enumerate(program): + print(f"0x{i*4:04X}: 0x{instr:08X}") + +# Write to hex file +with open('fill_pattern.rom', 'w') as f: + for instr in program: + f.write(f"{instr:08x}\n") + +print(f"\nWrote {len(program)} instructions to fill_pattern.rom") +print(f"Program size: {len(program) * 4} bytes") diff --git a/build.tcl b/build.tcl new file mode 100644 index 0000000..7585d7e --- /dev/null +++ b/build.tcl @@ -0,0 +1,1196 @@ +#***************************************************************************************** +# Vivado (TM) v2024.2 (64-bit) +# +# build.tcl: Tcl script for re-creating project 'computer' +# +# Generated by Vivado on Mon May 18 21:13:04 CEST 2026 +# IP Build 5239520 on Sun Nov 10 16:12:51 MST 2024 +# +# This file contains the Vivado Tcl commands for re-creating the project to the state* +# when this script was generated. In order to re-create the project, please source this +# file in the Vivado Tcl Shell. +# +# * Note that the runs in the created project will be configured the same way as the +# original project, however they will not be launched automatically. To regenerate the +# run results please launch the synthesis/implementation runs as needed. +# +#***************************************************************************************** +#***************************************************************************************** + +# Check file required for this script exists +proc checkRequiredFiles { origin_dir} { + set status true + set files [list \ + "[file normalize "$origin_dir/config/mig_b.prj"]"\ + ] + foreach ifile $files { + if { ![file isfile $ifile] } { + puts " Could not find local file $ifile " + set status false + } + } + + set files [list \ + "[file normalize "$origin_dir/hdl/reset_timer.v"]"\ + "[file normalize "$origin_dir/hdl/vga_out/vga_out.v"]"\ + "[file normalize "$origin_dir/hdl/cpu/cpu_core_params.vh"]"\ + "[file normalize "$origin_dir/hdl/cpu/arithmetic_logic_unit/arithmetic_logic_unit.vh"]"\ + "[file normalize "$origin_dir/hdl/cpu/comparator_unit/comparator_unit.vh"]"\ + "[file normalize "$origin_dir/hdl/cpu/immediate_unit/immediate_unit.vh"]"\ + "[file normalize "$origin_dir/hdl/cpu/memory/memory.vh"]"\ + "[file normalize "$origin_dir/hdl/cpu/control_unit/control_unit.vh"]"\ + "[file normalize "$origin_dir/ip_repo/component.xml"]"\ + "[file normalize "$origin_dir/rom.mem"]"\ + "[file normalize "$origin_dir/config/arty-s7-50.xdc"]"\ + ] + foreach ifile $files { + if { ![file isfile $ifile] } { + puts " Could not find remote file $ifile " + set status false + } + } + + set paths [list \ + "[file normalize "$origin_dir/[file normalize "$origin_dir/ip_repo"]"]"\ + ] + foreach ipath $paths { + if { ![file isdirectory $ipath] } { + puts " Could not access $ipath " + set status false + } + } + + return $status +} +# Set the reference directory for source file relative paths (by default the value is script directory path) +set origin_dir [file dirname [file normalize [info script]]] + +# Use origin directory path location variable, if specified in the tcl shell +if { [info exists ::origin_dir_loc] } { + set origin_dir $::origin_dir_loc +} + +# Set the project name +set _xil_proj_name_ "computer" + +# Use project name variable, if specified in the tcl shell +if { [info exists ::user_project_name] } { + set _xil_proj_name_ $::user_project_name +} + +variable script_file +set script_file "build.tcl" + +# Help information for this script +proc print_help {} { + variable script_file + puts "\nDescription:" + puts "Recreate a Vivado project from this script. The created project will be" + puts "functionally equivalent to the original project for which this script was" + puts "generated. The script contains commands for creating a project, filesets," + puts "runs, adding/importing sources and setting properties on various objects.\n" + puts "Syntax:" + puts "$script_file" + puts "$script_file -tclargs \[--origin_dir \]" + puts "$script_file -tclargs \[--project_name \]" + puts "$script_file -tclargs \[--help\]\n" + puts "Usage:" + puts "Name Description" + puts "-------------------------------------------------------------------------" + puts "\[--origin_dir \] Determine source file paths wrt this path. Default" + puts " origin_dir path value is \".\", otherwise, the value" + puts " that was set with the \"-paths_relative_to\" switch" + puts " when this script was generated.\n" + puts "\[--project_name \] Create project with the specified name. Default" + puts " name is the name of the project from where this" + puts " script was generated.\n" + puts "\[--help\] Print help information for this script" + puts "-------------------------------------------------------------------------\n" + exit 0 +} + +if { $::argc > 0 } { + for {set i 0} {$i < $::argc} {incr i} { + set option [string trim [lindex $::argv $i]] + switch -regexp -- $option { + "--origin_dir" { incr i; set origin_dir [lindex $::argv $i] } + "--project_name" { incr i; set _xil_proj_name_ [lindex $::argv $i] } + "--help" { print_help } + default { + if { [regexp {^-} $option] } { + puts "ERROR: Unknown option '$option' specified, please type '$script_file -tclargs --help' for usage info.\n" + return 1 + } + } + } + } +} + +# Set the directory path for the original project from where this script was exported +set orig_proj_dir "[file normalize "$origin_dir/../computer"]" + +# Check for paths and files needed for project creation +set validate_required 0 +if { $validate_required } { + if { [checkRequiredFiles $origin_dir] } { + puts "Tcl file $script_file is valid. All files required for project creation is accesable. " + } else { + puts "Tcl file $script_file is not valid. Not all files required for project creation is accesable. " + return + } +} + +# Create project +create_project -force ${_xil_proj_name_} ./${_xil_proj_name_} -part xc7s50csga324-1 + +# Set the directory path for the new project +set proj_dir [get_property directory [current_project]] + +# Reconstruct message rules +set_msg_config -id {IP_Flow 19-3667} -suppress -ruleid {1} -source 8 +set_msg_config -id {IP_Flow 19-3667} -suppress -ruleid {2} -source 8 + + +# Set project properties +set obj [current_project] +catch { set_property -name "board_part" -value "digilentinc.com:arty-s7-50:part0:1.1" -objects $obj } +set_property -name "default_lib" -value "xil_defaultlib" -objects $obj +set_property -name "enable_resource_estimation" -value "0" -objects $obj +set_property -name "enable_vhdl_2008" -value "1" -objects $obj +set_property -name "ip_cache_permissions" -value "read write" -objects $obj +set_property -name "ip_output_repo" -value "$proj_dir/${_xil_proj_name_}.cache/ip" -objects $obj +set_property -name "mem.enable_memory_map_generation" -value "1" -objects $obj +set_property -name "platform.board_id" -value "arty-s7-50" -objects $obj +set_property -name "revised_directory_structure" -value "1" -objects $obj +set_property -name "sim.central_dir" -value "$proj_dir/${_xil_proj_name_}.ip_user_files" -objects $obj +set_property -name "sim.ip.auto_export_scripts" -value "1" -objects $obj +set_property -name "simulator_language" -value "Mixed" -objects $obj +set_property -name "sim_compile_state" -value "1" -objects $obj +set_property -name "use_inline_hdl_ip" -value "1" -objects $obj +set_property -name "webtalk.modelsim_export_sim" -value "67" -objects $obj +set_property -name "webtalk.questa_export_sim" -value "67" -objects $obj +set_property -name "webtalk.riviera_export_sim" -value "67" -objects $obj +set_property -name "webtalk.vcs_export_sim" -value "67" -objects $obj +set_property -name "webtalk.xsim_export_sim" -value "67" -objects $obj +set_property -name "xpm_libraries" -value "XPM_CDC XPM_FIFO XPM_MEMORY" -objects $obj + +# Create 'sources_1' fileset (if not found) +if {[string equal [get_filesets -quiet sources_1] ""]} { + create_fileset -srcset sources_1 +} + +# Set IP repository paths +set obj [get_filesets sources_1] +if { $obj != {} } { + set_property "ip_repo_paths" "[file normalize "$origin_dir/ip_repo"]" $obj + + # Rebuild user ip_repo's index before adding any source files + update_ip_catalog -rebuild +} + +# Set 'sources_1' fileset object +set obj [get_filesets sources_1] +set files [list \ + [file normalize "${origin_dir}/hdl/reset_timer.v"] \ + [file normalize "${origin_dir}/hdl/vga_out/vga_out.v"] \ + [file normalize "${origin_dir}/hdl/cpu/cpu_core_params.vh"] \ + [file normalize "${origin_dir}/hdl/cpu/arithmetic_logic_unit/arithmetic_logic_unit.vh"] \ + [file normalize "${origin_dir}/hdl/cpu/comparator_unit/comparator_unit.vh"] \ + [file normalize "${origin_dir}/hdl/cpu/immediate_unit/immediate_unit.vh"] \ + [file normalize "${origin_dir}/hdl/cpu/memory/memory.vh"] \ + [file normalize "${origin_dir}/hdl/cpu/control_unit/control_unit.vh"] \ + [file normalize "${origin_dir}/rom.mem"] \ +] +add_files -norecurse -fileset $obj $files + +# Set 'sources_1' fileset file properties for remote files +set file "$origin_dir/hdl/cpu/cpu_core_params.vh" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "Verilog Header" -objects $file_obj + +set file "$origin_dir/hdl/cpu/arithmetic_logic_unit/arithmetic_logic_unit.vh" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "Verilog Header" -objects $file_obj + +set file "$origin_dir/hdl/cpu/comparator_unit/comparator_unit.vh" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "Verilog Header" -objects $file_obj + +set file "$origin_dir/hdl/cpu/immediate_unit/immediate_unit.vh" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "Verilog Header" -objects $file_obj + +set file "$origin_dir/hdl/cpu/memory/memory.vh" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "Verilog Header" -objects $file_obj + +set file "$origin_dir/hdl/cpu/control_unit/control_unit.vh" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "Verilog Header" -objects $file_obj + +set file "$origin_dir/rom.mem" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "Memory File" -objects $file_obj + + +# Set 'sources_1' fileset properties +set obj [get_filesets sources_1] +set_property -name "dataflow_viewer_settings" -value "min_width=16" -objects $obj +set_property -name "top" -value "computer_wrapper" -objects $obj +set_property -name "top_auto_set" -value "0" -objects $obj + +# Create 'constrs_1' fileset (if not found) +if {[string equal [get_filesets -quiet constrs_1] ""]} { + create_fileset -constrset constrs_1 +} + +# Set 'constrs_1' fileset object +set obj [get_filesets constrs_1] + +# Add/Import constrs file and set constrs file properties +set file "[file normalize "$origin_dir/config/arty-s7-50.xdc"]" +set file_added [add_files -norecurse -fileset $obj [list $file]] +set file "$origin_dir/config/arty-s7-50.xdc" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets constrs_1] [list "*$file"]] +set_property -name "file_type" -value "XDC" -objects $file_obj + +# Set 'constrs_1' fileset properties +set obj [get_filesets constrs_1] +set_property -name "target_constrs_file" -value "[file normalize "$origin_dir/config/arty-s7-50.xdc"]" -objects $obj +set_property -name "target_ucf" -value "[file normalize "$origin_dir/config/arty-s7-50.xdc"]" -objects $obj + +# Create 'sim_1' fileset (if not found) +if {[string equal [get_filesets -quiet sim_1] ""]} { + create_fileset -simset sim_1 +} + +# Set 'sim_1' fileset object +set obj [get_filesets sim_1] +# Empty (no sources present) + +# Set 'sim_1' fileset properties +set obj [get_filesets sim_1] +set_property -name "sim_wrapper_top" -value "1" -objects $obj +set_property -name "top" -value "computer_wrapper" -objects $obj +set_property -name "top_lib" -value "xil_defaultlib" -objects $obj + +# Set 'utils_1' fileset properties +set obj [get_filesets utils_1] + + +# Adding sources referenced in BDs, if not already added +if { [get_files [list reset_timer.v]] == "" } { + import_files -quiet -fileset sources_1 [file normalize "${origin_dir}/hdl/reset_timer.v"] +} +if { [get_files [list vga_out.v]] == "" } { + import_files -quiet -fileset sources_1 [file normalize "${origin_dir}/hdl/vga_out/vga_out.v"] +} + + +# Proc to create BD computer +proc cr_bd_computer { parentCell } { +# The design that will be created by this Tcl proc contains the following +# module references: +# reset_timer, vga_out + + + + # CHANGE DESIGN NAME HERE + set design_name computer + + common::send_gid_msg -ssname BD::TCL -id 2010 -severity "INFO" "Currently there is no design <$design_name> in project, so creating one..." + + create_bd_design $design_name + + set bCheckIPsPassed 1 + ################################################################## + # CHECK IPs + ################################################################## + set bCheckIPs 1 + if { $bCheckIPs == 1 } { + set list_check_ips "\ + xilinx.com:ip:mig_7series:4.2\ + xilinx.com:ip:clk_wiz:6.0\ + xilinx.com:ip:proc_sys_reset:5.0\ + xilinx.com:ip:smartconnect:1.0\ + user.org:user:cpu:1.0\ + xilinx.com:ip:util_vector_logic:2.0\ + xilinx.com:ip:xlconstant:1.1\ + xilinx.com:ip:axi_vdma:6.3\ + xilinx.com:ip:axis_dwidth_converter:1.1\ + " + + set list_ips_missing "" + common::send_gid_msg -ssname BD::TCL -id 2011 -severity "INFO" "Checking if the following IPs exist in the project's IP catalog: $list_check_ips ." + + foreach ip_vlnv $list_check_ips { + set ip_obj [get_ipdefs -all $ip_vlnv] + if { $ip_obj eq "" } { + lappend list_ips_missing $ip_vlnv + } + } + + if { $list_ips_missing ne "" } { + catch {common::send_gid_msg -ssname BD::TCL -id 2012 -severity "ERROR" "The following IPs are not found in the IP Catalog:\n $list_ips_missing\n\nResolution: Please add the repository containing the IP(s) to the project." } + set bCheckIPsPassed 0 + } + + } + + ################################################################## + # CHECK Modules + ################################################################## + set bCheckModules 1 + if { $bCheckModules == 1 } { + set list_check_mods "\ + reset_timer\ + vga_out\ + " + + set list_mods_missing "" + common::send_gid_msg -ssname BD::TCL -id 2020 -severity "INFO" "Checking if the following modules exist in the project's sources: $list_check_mods ." + + foreach mod_vlnv $list_check_mods { + if { [can_resolve_reference $mod_vlnv] == 0 } { + lappend list_mods_missing $mod_vlnv + } + } + + if { $list_mods_missing ne "" } { + catch {common::send_gid_msg -ssname BD::TCL -id 2021 -severity "ERROR" "The following module(s) are not found in the project: $list_mods_missing" } + common::send_gid_msg -ssname BD::TCL -id 2022 -severity "INFO" "Please add source files for the missing module(s) above." + set bCheckIPsPassed 0 + } +} + + if { $bCheckIPsPassed != 1 } { + common::send_gid_msg -ssname BD::TCL -id 2023 -severity "WARNING" "Will not continue with creation of design due to the error(s) above." + return 3 + } + + +################################################################## +# MIG PRJ FILE TCL PROCs +################################################################## + +proc write_mig_file_computer_mig_7series_0_0 { str_mig_prj_filepath } { + + file mkdir [ file dirname "$str_mig_prj_filepath" ] + set mig_prj_file [open $str_mig_prj_filepath w+] + + puts $mig_prj_file {} + puts $mig_prj_file {} + puts $mig_prj_file { } + puts $mig_prj_file {} + puts $mig_prj_file { computer_mig_7series_0_0} + puts $mig_prj_file { 1} + puts $mig_prj_file { 1} + puts $mig_prj_file { OFF} + puts $mig_prj_file { 1024} + puts $mig_prj_file { ON} + puts $mig_prj_file { Enabled} + puts $mig_prj_file { xc7s50-csga324/-1} + puts $mig_prj_file { 4.2} + puts $mig_prj_file { Single-Ended} + puts $mig_prj_file { No Buffer} + puts $mig_prj_file { ACTIVE LOW} + puts $mig_prj_file { FALSE} + puts $mig_prj_file { 1} + puts $mig_prj_file { 50 Ohms} + puts $mig_prj_file { 0} + puts $mig_prj_file { } + puts $mig_prj_file { DDR3_SDRAM/Components/MT41K128M16XX-15E} + puts $mig_prj_file { 3077} + puts $mig_prj_file { 1.8V} + puts $mig_prj_file { 4:1} + puts $mig_prj_file { 99.997} + puts $mig_prj_file { 0} + puts $mig_prj_file { 649} + puts $mig_prj_file { 1.000} + puts $mig_prj_file { 1} + puts $mig_prj_file { 1} + puts $mig_prj_file { 1} + puts $mig_prj_file { 1} + puts $mig_prj_file { 16} + puts $mig_prj_file { 1} + puts $mig_prj_file { 1} + puts $mig_prj_file { Disabled} + puts $mig_prj_file { Strict} + puts $mig_prj_file { 2} + puts $mig_prj_file { FALSE} + puts $mig_prj_file { } + puts $mig_prj_file { 14} + puts $mig_prj_file { 10} + puts $mig_prj_file { 3} + puts $mig_prj_file { 1.35V} + puts $mig_prj_file { 268435456} + puts $mig_prj_file { BANK_ROW_COLUMN} + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { 8 - Fixed} + puts $mig_prj_file { Sequential} + puts $mig_prj_file { 5} + puts $mig_prj_file { Normal} + puts $mig_prj_file { No} + puts $mig_prj_file { Slow Exit} + puts $mig_prj_file { Enable} + puts $mig_prj_file { RZQ/6} + puts $mig_prj_file { Disable} + puts $mig_prj_file { Enable} + puts $mig_prj_file { RZQ/6} + puts $mig_prj_file { 0} + puts $mig_prj_file { Disabled} + puts $mig_prj_file { Enabled} + puts $mig_prj_file { Output Buffer Enabled} + puts $mig_prj_file { Full Array} + puts $mig_prj_file { 5} + puts $mig_prj_file { Enabled} + puts $mig_prj_file { Normal} + puts $mig_prj_file { Dynamic ODT off} + puts $mig_prj_file { AXI} + puts $mig_prj_file { } + puts $mig_prj_file { RD_PRI_REG} + puts $mig_prj_file { 28} + puts $mig_prj_file { 128} + puts $mig_prj_file { 4} + puts $mig_prj_file { 0} + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file {} + + close $mig_prj_file +} +# End of write_mig_file_computer_mig_7series_0_0() + + + + variable script_folder + + if { $parentCell eq "" } { + set parentCell [get_bd_cells /] + } + + # Get object for parentCell + set parentObj [get_bd_cells $parentCell] + if { $parentObj == "" } { + catch {common::send_gid_msg -ssname BD::TCL -id 2090 -severity "ERROR" "Unable to find parent cell <$parentCell>!"} + return + } + + # Make sure parentObj is hier blk + set parentType [get_property TYPE $parentObj] + if { $parentType ne "hier" } { + catch {common::send_gid_msg -ssname BD::TCL -id 2091 -severity "ERROR" "Parent <$parentObj> has TYPE = <$parentType>. Expected to be ."} + return + } + + # Save current instance; Restore later + set oldCurInst [current_bd_instance .] + + # Set parent object as current + current_bd_instance $parentObj + + + # Create interface ports + set DDR3_0 [ create_bd_intf_port -mode Master -vlnv xilinx.com:interface:ddrx_rtl:1.0 DDR3_0 ] + + + # Create ports + set clk_in1_0 [ create_bd_port -dir I -type clk -freq_hz 12000000 clk_in1_0 ] + set ext_reset_in_0 [ create_bd_port -dir I -type rst ext_reset_in_0 ] + set_property -dict [ list \ + CONFIG.POLARITY {ACTIVE_LOW} \ + ] $ext_reset_in_0 + set i_Uart_Tx_In_0 [ create_bd_port -dir I i_Uart_Tx_In_0 ] + set o_Uart_Rx_Out_0 [ create_bd_port -dir O o_Uart_Rx_Out_0 ] + set o_Blue_1 [ create_bd_port -dir O -from 3 -to 0 o_Blue_1 ] + set o_Green_1 [ create_bd_port -dir O -from 3 -to 0 o_Green_1 ] + set o_Horizontal_Sync_1 [ create_bd_port -dir O o_Horizontal_Sync_1 ] + set o_Red_1 [ create_bd_port -dir O -from 3 -to 0 o_Red_1 ] + set o_Vertical_Sync_1 [ create_bd_port -dir O o_Vertical_Sync_1 ] + + # Create instance: mig_7series_0, and set properties + set mig_7series_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:mig_7series:4.2 mig_7series_0 ] + + # Generate the PRJ File for MIG + set str_mig_folder [get_property IP_DIR [ get_ips [ get_property CONFIG.Component_Name $mig_7series_0 ] ] ] + set str_mig_file_name mig_b.prj + set str_mig_file_path ${str_mig_folder}/${str_mig_file_name} + write_mig_file_computer_mig_7series_0_0 $str_mig_file_path + + set_property -dict [list \ + CONFIG.BOARD_MIG_PARAM {Custom} \ + CONFIG.MIG_DONT_TOUCH_PARAM {Custom} \ + CONFIG.RESET_BOARD_INTERFACE {Custom} \ + CONFIG.XML_INPUT_FILE {mig_b.prj} \ + ] $mig_7series_0 + + + # Create instance: clk_wiz_0, and set properties + set clk_wiz_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:clk_wiz:6.0 clk_wiz_0 ] + set_property -dict [list \ + CONFIG.CLKOUT1_JITTER {571.161} \ + CONFIG.CLKOUT1_PHASE_ERROR {613.025} \ + CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {100} \ + CONFIG.CLKOUT1_USED {true} \ + CONFIG.CLKOUT2_JITTER {522.440} \ + CONFIG.CLKOUT2_PHASE_ERROR {613.025} \ + CONFIG.CLKOUT2_REQUESTED_OUT_FREQ {200} \ + CONFIG.CLKOUT2_USED {true} \ + CONFIG.CLKOUT3_JITTER {754.542} \ + CONFIG.CLKOUT3_PHASE_ERROR {613.025} \ + CONFIG.CLKOUT3_REQUESTED_OUT_FREQ {25} \ + CONFIG.CLKOUT3_USED {false} \ + CONFIG.CLK_OUT1_PORT {CLK_100} \ + CONFIG.CLK_OUT2_PORT {CLK_200} \ + CONFIG.CLK_OUT3_PORT {CLK_25} \ + CONFIG.MMCM_CLKFBOUT_MULT_F {50.000} \ + CONFIG.MMCM_CLKIN1_PERIOD {83.333} \ + CONFIG.MMCM_CLKIN2_PERIOD {10.0} \ + CONFIG.MMCM_CLKOUT0_DIVIDE_F {6.000} \ + CONFIG.MMCM_CLKOUT1_DIVIDE {3} \ + CONFIG.MMCM_CLKOUT2_DIVIDE {1} \ + CONFIG.MMCM_DIVCLK_DIVIDE {1} \ + CONFIG.NUM_OUT_CLKS {2} \ + ] $clk_wiz_0 + + + # Create instance: proc_sys_reset_0, and set properties + set proc_sys_reset_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:proc_sys_reset:5.0 proc_sys_reset_0 ] + set_property -dict [list \ + CONFIG.C_AUX_RST_WIDTH {16} \ + CONFIG.C_EXT_RST_WIDTH {16} \ + ] $proc_sys_reset_0 + + + # Create instance: smartconnect_0, and set properties + set smartconnect_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:smartconnect:1.0 smartconnect_0 ] + set_property -dict [list \ + CONFIG.NUM_MI {2} \ + CONFIG.NUM_SI {3} \ + ] $smartconnect_0 + + + # Create instance: cpu, and set properties + set cpu [ create_bd_cell -type ip -vlnv user.org:user:cpu:1.0 cpu ] + + # Create instance: util_vector_logic_0, and set properties + set util_vector_logic_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:util_vector_logic:2.0 util_vector_logic_0 ] + set_property -dict [list \ + CONFIG.C_OPERATION {not} \ + CONFIG.C_SIZE {1} \ + ] $util_vector_logic_0 + + # Create instance: util_vector_logic_1 - inverts ui_clk_sync_rst to produce aresetn for AXI interfaces + set util_vector_logic_1 [ create_bd_cell -type ip -vlnv xilinx.com:ip:util_vector_logic:2.0 util_vector_logic_1 ] + set_property -dict [list \ + CONFIG.C_OPERATION {not} \ + CONFIG.C_SIZE {1} \ + ] $util_vector_logic_1 + + + # Create instance: reset_timer_0, and set properties + set block_name reset_timer + set block_cell_name reset_timer_0 + if { [catch {set reset_timer_0 [create_bd_cell -type module -reference $block_name $block_cell_name] } errmsg] } { + catch {common::send_gid_msg -ssname BD::TCL -id 2095 -severity "ERROR" "Unable to add referenced block <$block_name>. Please add the files for ${block_name}'s definition into the project."} + return 1 + } elseif { $reset_timer_0 eq "" } { + catch {common::send_gid_msg -ssname BD::TCL -id 2096 -severity "ERROR" "Unable to referenced block <$block_name>. Please add the files for ${block_name}'s definition into the project."} + return 1 + } + + # Create instance: xlconstant_0, and set properties + set xlconstant_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:xlconstant:1.1 xlconstant_0 ] + set_property CONFIG.CONST_VAL {0} $xlconstant_0 + + + # Create instance: axi_vdma_0, and set properties + set axi_vdma_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_vdma:6.3 axi_vdma_0 ] + set_property -dict [list \ + CONFIG.c_include_mm2s_dre {0} \ + CONFIG.c_include_s2mm {0} \ + CONFIG.c_m_axi_mm2s_data_width {128} \ + CONFIG.c_m_axis_mm2s_tdata_width {16} \ + CONFIG.c_mm2s_genlock_mode {0} \ + CONFIG.c_mm2s_linebuffer_depth {2048} \ + CONFIG.c_mm2s_max_burst_length {4} \ + CONFIG.c_num_fstores {2} \ + CONFIG.c_use_mm2s_fsync {1} \ + ] $axi_vdma_0 + + + # Create instance: vga_out_0, and set properties + set block_name vga_out + set block_cell_name vga_out_0 + if { [catch {set vga_out_0 [create_bd_cell -type module -reference $block_name $block_cell_name] } errmsg] } { + catch {common::send_gid_msg -ssname BD::TCL -id 2095 -severity "ERROR" "Unable to add referenced block <$block_name>. Please add the files for ${block_name}'s definition into the project."} + return 1 + } elseif { $vga_out_0 eq "" } { + catch {common::send_gid_msg -ssname BD::TCL -id 2096 -severity "ERROR" "Unable to referenced block <$block_name>. Please add the files for ${block_name}'s definition into the project."} + return 1 + } + + # Create instance: axis_dwidth_converter_0, and set properties + set axis_dwidth_converter_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_dwidth_converter:1.1 axis_dwidth_converter_0 ] + + # Create interface connections + connect_bd_intf_net -intf_net axi_vdma_0_M_AXIS_MM2S [get_bd_intf_pins axis_dwidth_converter_0/S_AXIS] [get_bd_intf_pins axi_vdma_0/M_AXIS_MM2S] + connect_bd_intf_net -intf_net axi_vdma_0_M_AXI_MM2S [get_bd_intf_pins axi_vdma_0/M_AXI_MM2S] [get_bd_intf_pins smartconnect_0/S02_AXI] + connect_bd_intf_net -intf_net axis_dwidth_converter_0_M_AXIS [get_bd_intf_pins axis_dwidth_converter_0/M_AXIS] [get_bd_intf_pins vga_out_0/s_axis] + connect_bd_intf_net -intf_net cpu_0_s_data_memory_axil [get_bd_intf_pins cpu/s_data_memory_axil] [get_bd_intf_pins smartconnect_0/S00_AXI] + connect_bd_intf_net -intf_net cpu_0_s_instruction_memory_axil [get_bd_intf_pins cpu/s_instruction_memory_axil] [get_bd_intf_pins smartconnect_0/S01_AXI] + connect_bd_intf_net -intf_net mig_7series_0_DDR3 [get_bd_intf_ports DDR3_0] [get_bd_intf_pins mig_7series_0/DDR3] + connect_bd_intf_net -intf_net smartconnect_0_M00_AXI [get_bd_intf_pins smartconnect_0/M00_AXI] [get_bd_intf_pins mig_7series_0/S_AXI] + connect_bd_intf_net -intf_net smartconnect_0_M01_AXI [get_bd_intf_pins smartconnect_0/M01_AXI] [get_bd_intf_pins axi_vdma_0/S_AXI_LITE] + + # Create port connections + connect_bd_net -net clk_in1_0_1 [get_bd_ports clk_in1_0] \ + [get_bd_pins clk_wiz_0/clk_in1] + connect_bd_net -net clk_wiz_0_CLK_100 [get_bd_pins clk_wiz_0/CLK_100] \ + [get_bd_pins mig_7series_0/sys_clk_i] \ + [get_bd_pins proc_sys_reset_0/slowest_sync_clk] \ + [get_bd_pins reset_timer_0/i_Clock] \ + [get_bd_pins axi_vdma_0/m_axis_mm2s_aclk] \ + [get_bd_pins axis_dwidth_converter_0/aclk] \ + [get_bd_pins vga_out_0/i_Clock] + connect_bd_net -net clk_wiz_0_CLK_200 [get_bd_pins clk_wiz_0/CLK_200] \ + [get_bd_pins mig_7series_0/clk_ref_i] + connect_bd_net -net clk_wiz_0_locked [get_bd_pins clk_wiz_0/locked] \ + [get_bd_pins proc_sys_reset_0/dcm_locked] \ + [get_bd_pins reset_timer_0/i_Enable] + connect_bd_net -net cpu_0_s_data_memory_axil_araddr [get_bd_pins cpu/s_data_memory_axil_araddr] \ + [get_bd_pins smartconnect_0/S00_AXI_araddr] + connect_bd_net -net cpu_0_s_data_memory_axil_arvalid [get_bd_pins cpu/s_data_memory_axil_arvalid] \ + [get_bd_pins smartconnect_0/S00_AXI_arvalid] + connect_bd_net -net cpu_0_s_data_memory_axil_awaddr [get_bd_pins cpu/s_data_memory_axil_awaddr] \ + [get_bd_pins smartconnect_0/S00_AXI_awaddr] + connect_bd_net -net cpu_0_s_data_memory_axil_awvalid [get_bd_pins cpu/s_data_memory_axil_awvalid] \ + [get_bd_pins smartconnect_0/S00_AXI_awvalid] + connect_bd_net -net cpu_0_s_data_memory_axil_bready [get_bd_pins cpu/s_data_memory_axil_bready] \ + [get_bd_pins smartconnect_0/S00_AXI_bready] + connect_bd_net -net cpu_0_s_data_memory_axil_rready [get_bd_pins cpu/s_data_memory_axil_rready] \ + [get_bd_pins smartconnect_0/S00_AXI_rready] + connect_bd_net -net cpu_0_s_data_memory_axil_wdata [get_bd_pins cpu/s_data_memory_axil_wdata] \ + [get_bd_pins smartconnect_0/S00_AXI_wdata] + connect_bd_net -net cpu_0_s_data_memory_axil_wstrb [get_bd_pins cpu/s_data_memory_axil_wstrb] \ + [get_bd_pins smartconnect_0/S00_AXI_wstrb] + connect_bd_net -net cpu_0_s_data_memory_axil_wvalid [get_bd_pins cpu/s_data_memory_axil_wvalid] \ + [get_bd_pins smartconnect_0/S00_AXI_wvalid] + connect_bd_net -net cpu_0_s_instruction_memory_axil_araddr [get_bd_pins cpu/s_instruction_memory_axil_araddr] \ + [get_bd_pins smartconnect_0/S01_AXI_araddr] + connect_bd_net -net cpu_0_s_instruction_memory_axil_arvalid [get_bd_pins cpu/s_instruction_memory_axil_arvalid] \ + [get_bd_pins smartconnect_0/S01_AXI_arvalid] + connect_bd_net -net cpu_0_s_instruction_memory_axil_awaddr [get_bd_pins cpu/s_instruction_memory_axil_awaddr] \ + [get_bd_pins smartconnect_0/S01_AXI_awaddr] + connect_bd_net -net cpu_0_s_instruction_memory_axil_awvalid [get_bd_pins cpu/s_instruction_memory_axil_awvalid] \ + [get_bd_pins smartconnect_0/S01_AXI_awvalid] + connect_bd_net -net cpu_0_s_instruction_memory_axil_bready [get_bd_pins cpu/s_instruction_memory_axil_bready] \ + [get_bd_pins smartconnect_0/S01_AXI_bready] + set_property HDL_ATTRIBUTE.DEBUG {true} [get_bd_nets cpu_0_s_instruction_memory_axil_bready] + connect_bd_net -net cpu_0_s_instruction_memory_axil_rready [get_bd_pins cpu/s_instruction_memory_axil_rready] \ + [get_bd_pins smartconnect_0/S01_AXI_rready] + connect_bd_net -net cpu_0_s_instruction_memory_axil_wdata [get_bd_pins cpu/s_instruction_memory_axil_wdata] \ + [get_bd_pins smartconnect_0/S01_AXI_wdata] + connect_bd_net -net cpu_0_s_instruction_memory_axil_wstrb [get_bd_pins cpu/s_instruction_memory_axil_wstrb] \ + [get_bd_pins smartconnect_0/S01_AXI_wstrb] + connect_bd_net -net cpu_0_s_instruction_memory_axil_wvalid [get_bd_pins cpu/s_instruction_memory_axil_wvalid] \ + [get_bd_pins smartconnect_0/S01_AXI_wvalid] + connect_bd_net -net cpu_o_Uart_Rx_Out [get_bd_pins cpu/o_Uart_Rx_Out] \ + [get_bd_ports o_Uart_Rx_Out_0] + connect_bd_net -net ext_reset_in_0_1 [get_bd_ports ext_reset_in_0] \ + [get_bd_pins util_vector_logic_0/Op1] + connect_bd_net -net i_Uart_Tx_In_0_1 [get_bd_ports i_Uart_Tx_In_0] \ + [get_bd_pins cpu/i_Uart_Tx_In] + connect_bd_net -net mig_7series_0_init_calib_complete [get_bd_pins mig_7series_0/init_calib_complete] \ + [get_bd_pins cpu/i_Init_Calib_Complete] + connect_bd_net -net mig_7series_0_ui_clk [get_bd_pins mig_7series_0/ui_clk] \ + [get_bd_pins smartconnect_0/aclk] \ + [get_bd_pins axi_vdma_0/m_axi_mm2s_aclk] \ + [get_bd_pins axi_vdma_0/s_axi_lite_aclk] \ + [get_bd_pins cpu/i_Clock] + connect_bd_net -net mig_7series_0_ui_clk_sync_rst [get_bd_pins mig_7series_0/ui_clk_sync_rst] \ + [get_bd_pins cpu/i_Reset] \ + [get_bd_pins util_vector_logic_1/Op1] + connect_bd_net -net ui_clk_sync_rst_n [get_bd_pins util_vector_logic_1/Res] \ + [get_bd_pins smartconnect_0/aresetn] \ + [get_bd_pins mig_7series_0/aresetn] \ + [get_bd_pins axi_vdma_0/axi_resetn] \ + [get_bd_pins axis_dwidth_converter_0/aresetn] + connect_bd_net -net proc_sys_reset_0_peripheral_reset [get_bd_pins proc_sys_reset_0/peripheral_reset] + connect_bd_net -net reset_timer_0_o_Timer_Expired [get_bd_pins reset_timer_0/o_Mig_Reset] \ + [get_bd_pins mig_7series_0/sys_rst] + connect_bd_net -net smartconnect_0_S00_AXI_arready [get_bd_pins smartconnect_0/S00_AXI_arready] \ + [get_bd_pins cpu/s_data_memory_axil_arready] + connect_bd_net -net smartconnect_0_S00_AXI_awready [get_bd_pins smartconnect_0/S00_AXI_awready] \ + [get_bd_pins cpu/s_data_memory_axil_awready] + connect_bd_net -net smartconnect_0_S00_AXI_bresp [get_bd_pins smartconnect_0/S00_AXI_bresp] \ + [get_bd_pins cpu/s_data_memory_axil_bresp] + connect_bd_net -net smartconnect_0_S00_AXI_bvalid [get_bd_pins smartconnect_0/S00_AXI_bvalid] \ + [get_bd_pins cpu/s_data_memory_axil_bvalid] + connect_bd_net -net smartconnect_0_S00_AXI_rdata [get_bd_pins smartconnect_0/S00_AXI_rdata] \ + [get_bd_pins cpu/s_data_memory_axil_rdata] + connect_bd_net -net smartconnect_0_S00_AXI_rvalid [get_bd_pins smartconnect_0/S00_AXI_rvalid] \ + [get_bd_pins cpu/s_data_memory_axil_rvalid] + connect_bd_net -net smartconnect_0_S00_AXI_wready [get_bd_pins smartconnect_0/S00_AXI_wready] \ + [get_bd_pins cpu/s_data_memory_axil_wready] + connect_bd_net -net smartconnect_0_S01_AXI_arready [get_bd_pins smartconnect_0/S01_AXI_arready] \ + [get_bd_pins cpu/s_instruction_memory_axil_arready] + connect_bd_net -net smartconnect_0_S01_AXI_awready [get_bd_pins smartconnect_0/S01_AXI_awready] \ + [get_bd_pins cpu/s_instruction_memory_axil_awready] + connect_bd_net -net smartconnect_0_S01_AXI_bresp [get_bd_pins smartconnect_0/S01_AXI_bresp] \ + [get_bd_pins cpu/s_instruction_memory_axil_bresp] + set_property HDL_ATTRIBUTE.DEBUG {true} [get_bd_nets smartconnect_0_S01_AXI_bresp] + connect_bd_net -net smartconnect_0_S01_AXI_bvalid [get_bd_pins smartconnect_0/S01_AXI_bvalid] \ + [get_bd_pins cpu/s_instruction_memory_axil_bvalid] + set_property HDL_ATTRIBUTE.DEBUG {true} [get_bd_nets smartconnect_0_S01_AXI_bvalid] + connect_bd_net -net smartconnect_0_S01_AXI_rdata [get_bd_pins smartconnect_0/S01_AXI_rdata] \ + [get_bd_pins cpu/s_instruction_memory_axil_rdata] + connect_bd_net -net smartconnect_0_S01_AXI_rvalid [get_bd_pins smartconnect_0/S01_AXI_rvalid] \ + [get_bd_pins cpu/s_instruction_memory_axil_rvalid] + connect_bd_net -net smartconnect_0_S01_AXI_wready [get_bd_pins smartconnect_0/S01_AXI_wready] \ + [get_bd_pins cpu/s_instruction_memory_axil_wready] + connect_bd_net -net util_vector_logic_0_Res [get_bd_pins util_vector_logic_0/Res] \ + [get_bd_pins clk_wiz_0/reset] \ + [get_bd_pins proc_sys_reset_0/ext_reset_in] + connect_bd_net -net vga_out_0_o_Blue [get_bd_pins vga_out_0/o_Blue] \ + [get_bd_ports o_Blue_1] + connect_bd_net -net vga_out_0_o_Green [get_bd_pins vga_out_0/o_Green] \ + [get_bd_ports o_Green_1] + connect_bd_net -net vga_out_0_o_Horizontal_Sync [get_bd_pins vga_out_0/o_Horizontal_Sync] \ + [get_bd_ports o_Horizontal_Sync_1] + connect_bd_net -net vga_out_0_o_Red [get_bd_pins vga_out_0/o_Red] \ + [get_bd_ports o_Red_1] + connect_bd_net -net vga_out_0_o_Vertical_Sync [get_bd_pins vga_out_0/o_Vertical_Sync] \ + [get_bd_ports o_Vertical_Sync_1] + connect_bd_net -net vga_out_0_o_mm2s_fsync [get_bd_pins vga_out_0/o_mm2s_fsync] \ + [get_bd_pins axi_vdma_0/mm2s_fsync] + connect_bd_net -net xlconstant_0_dout [get_bd_pins xlconstant_0/dout] \ + [get_bd_pins proc_sys_reset_0/aux_reset_in] \ + [get_bd_pins vga_out_0/i_Reset] + + # Create address segments + assign_bd_address -offset 0x88000000 -range 0x00010000 -target_address_space [get_bd_addr_spaces cpu/s_data_memory_axil] [get_bd_addr_segs axi_vdma_0/S_AXI_LITE/Reg] -force + assign_bd_address -offset 0x80000000 -range 0x08000000 -target_address_space [get_bd_addr_spaces cpu/s_data_memory_axil] [get_bd_addr_segs mig_7series_0/memmap/memaddr] -force + assign_bd_address -offset 0x80000000 -range 0x08000000 -target_address_space [get_bd_addr_spaces cpu/s_instruction_memory_axil] [get_bd_addr_segs mig_7series_0/memmap/memaddr] -force + assign_bd_address -offset 0x80000000 -range 0x08000000 -target_address_space [get_bd_addr_spaces axi_vdma_0/Data_MM2S] [get_bd_addr_segs mig_7series_0/memmap/memaddr] -force + + # Exclude Address Segments + exclude_bd_addr_seg -offset 0x88000000 -range 0x00010000 -target_address_space [get_bd_addr_spaces axi_vdma_0/Data_MM2S] [get_bd_addr_segs axi_vdma_0/S_AXI_LITE/Reg] + exclude_bd_addr_seg -offset 0x88000000 -range 0x00010000 -target_address_space [get_bd_addr_spaces cpu/s_instruction_memory_axil] [get_bd_addr_segs axi_vdma_0/S_AXI_LITE/Reg] + + + # Restore current instance + current_bd_instance $oldCurInst + + validate_bd_design + save_bd_design + close_bd_design $design_name +} +# End of cr_bd_computer() + +cr_bd_computer "" +set_property GENERATE_SYNTH_CHECKPOINT "0" [get_files computer.bd ] +set_property REGISTERED_WITH_MANAGER "1" [get_files computer.bd ] + +#call make_wrapper to create wrapper files +if { [get_property IS_LOCKED [ get_files -norecurse [list computer.bd]] ] == 1 } { + import_files -fileset sources_1 [file normalize "${origin_dir}/../computer/computer.gen/sources_1/bd/computer/hdl/computer_wrapper.v" ] +} else { + set wrapper_path [make_wrapper -fileset sources_1 -files [ get_files -norecurse [list computer.bd]] -top] + add_files -norecurse -fileset sources_1 $wrapper_path +} + + +set idrFlowPropertiesConstraints "" +catch { + set idrFlowPropertiesConstraints [get_param runs.disableIDRFlowPropertyConstraints] + set_param runs.disableIDRFlowPropertyConstraints 1 +} + +# Create 'synth_1' run (if not found) +if {[string equal [get_runs -quiet synth_1] ""]} { + create_run -name synth_1 -part xc7s50csga324-1 -flow {Vivado Synthesis 2024} -strategy "Vivado Synthesis Defaults" -report_strategy {No Reports} -constrset constrs_1 +} else { + set_property strategy "Vivado Synthesis Defaults" [get_runs synth_1] + set_property flow "Vivado Synthesis 2024" [get_runs synth_1] +} +set obj [get_runs synth_1] +set_property set_report_strategy_name 1 $obj +set_property report_strategy {Vivado Synthesis Default Reports} $obj +set_property set_report_strategy_name 0 $obj +# Create 'synth_1_synth_report_utilization_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs synth_1] synth_1_synth_report_utilization_0] "" ] } { + create_report_config -report_name synth_1_synth_report_utilization_0 -report_type report_utilization:1.0 -steps synth_design -runs synth_1 +} +set obj [get_report_configs -of_objects [get_runs synth_1] synth_1_synth_report_utilization_0] +if { $obj != "" } { + +} +set obj [get_runs synth_1] +set_property -name "strategy" -value "Vivado Synthesis Defaults" -objects $obj + +# set the current synth run +current_run -synthesis [get_runs synth_1] + +# Create 'impl_1' run (if not found) +if {[string equal [get_runs -quiet impl_1] ""]} { + create_run -name impl_1 -part xc7s50csga324-1 -flow {Vivado Implementation 2024} -strategy "Vivado Implementation Defaults" -report_strategy {No Reports} -constrset constrs_1 -parent_run synth_1 +} else { + set_property strategy "Vivado Implementation Defaults" [get_runs impl_1] + set_property flow "Vivado Implementation 2024" [get_runs impl_1] +} +set obj [get_runs impl_1] +set_property set_report_strategy_name 1 $obj +set_property report_strategy {Vivado Implementation Default Reports} $obj +set_property set_report_strategy_name 0 $obj +# Create 'impl_1_init_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_init_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_init_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps init_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_init_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "options.max_paths" -value "10" -objects $obj +set_property -name "options.report_unconstrained" -value "1" -objects $obj + +} +# Create 'impl_1_opt_report_drc_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_drc_0] "" ] } { + create_report_config -report_name impl_1_opt_report_drc_0 -report_type report_drc:1.0 -steps opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_drc_0] +if { $obj != "" } { + +} +# Create 'impl_1_opt_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "options.max_paths" -value "10" -objects $obj +set_property -name "options.report_unconstrained" -value "1" -objects $obj + +} +# Create 'impl_1_power_opt_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_power_opt_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_power_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps power_opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_power_opt_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "options.max_paths" -value "10" -objects $obj +set_property -name "options.report_unconstrained" -value "1" -objects $obj + +} +# Create 'impl_1_place_report_io_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_io_0] "" ] } { + create_report_config -report_name impl_1_place_report_io_0 -report_type report_io:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_io_0] +if { $obj != "" } { + +} +# Create 'impl_1_place_report_utilization_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_utilization_0] "" ] } { + create_report_config -report_name impl_1_place_report_utilization_0 -report_type report_utilization:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_utilization_0] +if { $obj != "" } { + +} +# Create 'impl_1_place_report_control_sets_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_control_sets_0] "" ] } { + create_report_config -report_name impl_1_place_report_control_sets_0 -report_type report_control_sets:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_control_sets_0] +if { $obj != "" } { +set_property -name "options.verbose" -value "1" -objects $obj + +} +# Create 'impl_1_place_report_incremental_reuse_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_0] "" ] } { + create_report_config -report_name impl_1_place_report_incremental_reuse_0 -report_type report_incremental_reuse:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj + +} +# Create 'impl_1_place_report_incremental_reuse_1' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_1] "" ] } { + create_report_config -report_name impl_1_place_report_incremental_reuse_1 -report_type report_incremental_reuse:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_1] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj + +} +# Create 'impl_1_place_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_place_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "options.max_paths" -value "10" -objects $obj +set_property -name "options.report_unconstrained" -value "1" -objects $obj + +} +# Create 'impl_1_post_place_power_opt_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_place_power_opt_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_post_place_power_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps post_place_power_opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_place_power_opt_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "options.max_paths" -value "10" -objects $obj +set_property -name "options.report_unconstrained" -value "1" -objects $obj + +} +# Create 'impl_1_phys_opt_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_phys_opt_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_phys_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps phys_opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_phys_opt_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "options.max_paths" -value "10" -objects $obj +set_property -name "options.report_unconstrained" -value "1" -objects $obj + +} +# Create 'impl_1_route_report_drc_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_drc_0] "" ] } { + create_report_config -report_name impl_1_route_report_drc_0 -report_type report_drc:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_drc_0] +if { $obj != "" } { + +} +# Create 'impl_1_route_report_methodology_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_methodology_0] "" ] } { + create_report_config -report_name impl_1_route_report_methodology_0 -report_type report_methodology:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_methodology_0] +if { $obj != "" } { + +} +# Create 'impl_1_route_report_power_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_power_0] "" ] } { + create_report_config -report_name impl_1_route_report_power_0 -report_type report_power:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_power_0] +if { $obj != "" } { + +} +# Create 'impl_1_route_report_route_status_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_route_status_0] "" ] } { + create_report_config -report_name impl_1_route_report_route_status_0 -report_type report_route_status:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_route_status_0] +if { $obj != "" } { + +} +# Create 'impl_1_route_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_route_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_timing_summary_0] +if { $obj != "" } { +set_property -name "options.max_paths" -value "10" -objects $obj +set_property -name "options.report_unconstrained" -value "1" -objects $obj + +} +# Create 'impl_1_route_report_incremental_reuse_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_incremental_reuse_0] "" ] } { + create_report_config -report_name impl_1_route_report_incremental_reuse_0 -report_type report_incremental_reuse:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_incremental_reuse_0] +if { $obj != "" } { + +} +# Create 'impl_1_route_report_clock_utilization_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_clock_utilization_0] "" ] } { + create_report_config -report_name impl_1_route_report_clock_utilization_0 -report_type report_clock_utilization:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_clock_utilization_0] +if { $obj != "" } { + +} +# Create 'impl_1_route_report_bus_skew_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_bus_skew_0] "" ] } { + create_report_config -report_name impl_1_route_report_bus_skew_0 -report_type report_bus_skew:1.1 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_bus_skew_0] +if { $obj != "" } { +set_property -name "options.warn_on_violation" -value "1" -objects $obj + +} +# Create 'impl_1_post_route_phys_opt_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_post_route_phys_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps post_route_phys_opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_timing_summary_0] +if { $obj != "" } { +set_property -name "options.max_paths" -value "10" -objects $obj +set_property -name "options.report_unconstrained" -value "1" -objects $obj +set_property -name "options.warn_on_violation" -value "1" -objects $obj + +} +# Create 'impl_1_post_route_phys_opt_report_bus_skew_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_bus_skew_0] "" ] } { + create_report_config -report_name impl_1_post_route_phys_opt_report_bus_skew_0 -report_type report_bus_skew:1.1 -steps post_route_phys_opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_bus_skew_0] +if { $obj != "" } { +set_property -name "options.warn_on_violation" -value "1" -objects $obj + +} +set obj [get_runs impl_1] +set_property -name "strategy" -value "Vivado Implementation Defaults" -objects $obj +set_property -name "steps.write_bitstream.args.readback_file" -value "0" -objects $obj +set_property -name "steps.write_bitstream.args.verbose" -value "0" -objects $obj + +# set the current impl run +current_run -implementation [get_runs impl_1] +catch { + if { $idrFlowPropertiesConstraints != {} } { + set_param runs.disableIDRFlowPropertyConstraints $idrFlowPropertiesConstraints + } +} + +puts "INFO: Project created:${_xil_proj_name_}" +# Create 'drc_1' gadget (if not found) +if {[string equal [get_dashboard_gadgets [ list "drc_1" ] ] ""]} { +create_dashboard_gadget -name {drc_1} -type drc +} +set obj [get_dashboard_gadgets [ list "drc_1" ] ] +set_property -name "reports" -value "impl_1#impl_1_route_report_drc_0" -objects $obj + +# Create 'methodology_1' gadget (if not found) +if {[string equal [get_dashboard_gadgets [ list "methodology_1" ] ] ""]} { +create_dashboard_gadget -name {methodology_1} -type methodology +} +set obj [get_dashboard_gadgets [ list "methodology_1" ] ] +set_property -name "reports" -value "impl_1#impl_1_route_report_methodology_0" -objects $obj + +# Create 'power_1' gadget (if not found) +if {[string equal [get_dashboard_gadgets [ list "power_1" ] ] ""]} { +create_dashboard_gadget -name {power_1} -type power +} +set obj [get_dashboard_gadgets [ list "power_1" ] ] +set_property -name "reports" -value "impl_1#impl_1_route_report_power_0" -objects $obj + +# Create 'timing_1' gadget (if not found) +if {[string equal [get_dashboard_gadgets [ list "timing_1" ] ] ""]} { +create_dashboard_gadget -name {timing_1} -type timing +} +set obj [get_dashboard_gadgets [ list "timing_1" ] ] +set_property -name "reports" -value "impl_1#impl_1_route_report_timing_summary_0" -objects $obj + +# Create 'utilization_1' gadget (if not found) +if {[string equal [get_dashboard_gadgets [ list "utilization_1" ] ] ""]} { +create_dashboard_gadget -name {utilization_1} -type utilization +} +set obj [get_dashboard_gadgets [ list "utilization_1" ] ] +set_property -name "reports" -value "synth_1#synth_1_synth_report_utilization_0" -objects $obj +set_property -name "run.step" -value "synth_design" -objects $obj +set_property -name "run.type" -value "synthesis" -objects $obj + +# Create 'utilization_2' gadget (if not found) +if {[string equal [get_dashboard_gadgets [ list "utilization_2" ] ] ""]} { +create_dashboard_gadget -name {utilization_2} -type utilization +} +set obj [get_dashboard_gadgets [ list "utilization_2" ] ] +set_property -name "reports" -value "impl_1#impl_1_place_report_utilization_0" -objects $obj + +move_dashboard_gadget -name {utilization_1} -row 0 -col 0 +move_dashboard_gadget -name {power_1} -row 1 -col 0 +move_dashboard_gadget -name {drc_1} -row 2 -col 0 +move_dashboard_gadget -name {timing_1} -row 0 -col 1 +move_dashboard_gadget -name {utilization_2} -row 1 -col 1 +move_dashboard_gadget -name {methodology_1} -row 2 -col 1 + +# Launch full build to bitstream +launch_runs synth_1 -jobs 6 +wait_on_run synth_1 +if {[get_property PROGRESS [get_runs synth_1]] != "100%"} { + error "Synthesis failed" +} + +launch_runs impl_1 -to_step write_bitstream -jobs 6 +wait_on_run impl_1 +if {[get_property PROGRESS [get_runs impl_1]] != "100%"} { + error "Implementation failed" +} + +puts "Build complete. Bitstream: [get_property DIRECTORY [get_runs impl_1]]/computer_wrapper.bit" diff --git a/config/arty-s7-50.xdc b/config/arty-s7-50.xdc index 915bc2d..18fe75d 100644 --- a/config/arty-s7-50.xdc +++ b/config/arty-s7-50.xdc @@ -11,47 +11,21 @@ set_property IOSTANDARD LVCMOS33 [get_ports i_Uart_Tx_In_0] set_property IOSTANDARD LVCMOS33 [get_ports o_Uart_Rx_Out_0] set_property PACKAGE_PIN R12 [get_ports o_Uart_Rx_Out_0] -connect_debug_port u_ila_0/probe3 [get_nets [list {computer_i/proc_sys_reset_0/peripheral_reset[0]}]] +## Pmod Header JA +set_property -dict {PACKAGE_PIN L17 IOSTANDARD LVCMOS33} [get_ports {o_Red_1[0]}] +set_property -dict {PACKAGE_PIN L18 IOSTANDARD LVCMOS33} [get_ports {o_Red_1[1]}] +set_property -dict {PACKAGE_PIN M14 IOSTANDARD LVCMOS33} [get_ports {o_Red_1[2]}] +set_property -dict {PACKAGE_PIN N14 IOSTANDARD LVCMOS33} [get_ports {o_Red_1[3]}] +set_property -dict {PACKAGE_PIN M16 IOSTANDARD LVCMOS33} [get_ports {o_Green_1[0]}] +set_property -dict {PACKAGE_PIN M17 IOSTANDARD LVCMOS33} [get_ports {o_Green_1[1]}] +set_property -dict {PACKAGE_PIN M18 IOSTANDARD LVCMOS33} [get_ports {o_Green_1[2]}] +set_property -dict {PACKAGE_PIN N18 IOSTANDARD LVCMOS33} [get_ports {o_Green_1[3]}] + +## Pmod Header JB +set_property -dict {PACKAGE_PIN P17 IOSTANDARD LVCMOS33} [get_ports {o_Blue_1[0]}] +set_property -dict {PACKAGE_PIN P18 IOSTANDARD LVCMOS33} [get_ports {o_Blue_1[1]}] +set_property -dict {PACKAGE_PIN R18 IOSTANDARD LVCMOS33} [get_ports {o_Blue_1[2]}] +set_property -dict {PACKAGE_PIN T18 IOSTANDARD LVCMOS33} [get_ports {o_Blue_1[3]}] +set_property -dict {PACKAGE_PIN P14 IOSTANDARD LVCMOS33} [get_ports o_Horizontal_Sync_1] +set_property -dict {PACKAGE_PIN P15 IOSTANDARD LVCMOS33} [get_ports o_Vertical_Sync_1] - - - - -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] -set_property C_ADV_TRIGGER false [get_debug_cores u_ila_0] -set_property C_DATA_DEPTH 1024 [get_debug_cores u_ila_0] -set_property C_EN_STRG_QUAL false [get_debug_cores u_ila_0] -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/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/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/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_0_CLK_100] diff --git a/config/mig_b.prj b/config/mig_b.prj new file mode 100755 index 0000000..ed29859 --- /dev/null +++ b/config/mig_b.prj @@ -0,0 +1,159 @@ + + + + + + + + computer_mig_7series_0_0 + + 1 + + 1 + + OFF + + 1024 + + ON + + Enabled + + xc7s50-csga324/-1 + + 4.2 + + Single-Ended + + No Buffer + + ACTIVE LOW + + FALSE + + 1 + + 50 Ohms + + 0 + + + DDR3_SDRAM/Components/MT41K128M16XX-15E + 3077 + 1.8V + 4:1 + 99.997 + 0 + 649 + 1.000 + 1 + 1 + 1 + 1 + 16 + 1 + 1 + Disabled + Strict + 2 + FALSE + + 14 + 10 + 3 + 1.35V + 268435456 + BANK_ROW_COLUMN + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 8 - Fixed + Sequential + 5 + Normal + No + Slow Exit + Enable + RZQ/6 + Disable + Enable + RZQ/6 + 0 + Disabled + Enabled + Output Buffer Enabled + Full Array + 5 + Enabled + Normal + Dynamic ODT off + AXI + + RD_PRI_REG + 28 + 128 + 4 + 0 + + + + + diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..0a79df1 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,58 @@ +# Architecture Overview + +## CPU Core (RV32I) + +- 32-bit RISC-V base integer instruction set (RV32I) +- No M/F/D extensions (no multiply/divide/float) +- 3-stage pipeline: Fetch/Decode/Execute → Memory/Wait → Writeback +- No hazard detection — insert NOPs manually between dependent instructions +- Two AXI4-Lite masters: instruction fetch (read-only) and data load/store + +## Memory Map + +``` +0x80000000 - 0x80000FFF: Boot ROM (4KB BRAM, internal to CPU) +0x80001000 - 0x87F1DFFF: General RAM (~127MB DDR3 via MIG) +0x87F1E000 - 0x87F8EFFF: Framebuffer 0 (614,400 bytes, 640x480x16bpp) +0x87F8F000 - 0x87FFFFFF: Framebuffer 1 +0x88000000 - 0x8800FFFF: VDMA Control Registers (AXI-Lite) +``` + +- CPU_BASE_ADDR: 0x80000000 (PC starts here on reset) +- ROM_BOUNDARY_ADDR: 0x80000FFF (last ROM address) +- RAM_START_ADDR: 0x80001000 (first DDR3 address) + +## Video System + +- VGA output: 640x480 @ 60Hz, 16-bit pixels (R[15:12], G[10:7], B[4:1]) +- VDMA (AXI VDMA v6.3) reads framebuffer from DDR3, streams to vga_out module +- vga_out runs at 100 MHz with ÷4 divider for 25 MHz pixel clock +- External fsync from vga_out → VDMA synchronizes frame reads +- 2 frame store addresses configured (both pointing to same buffer for single-buffered mode) + +### VDMA Register Map (base 0x88000000) + +| Offset | Register | Notes | +|--------|----------|-------| +| 0x00 | MM2S_VDMACR | RS=bit0, Circular=bit1 | +| 0x04 | MM2S_VDMASR | Halted=bit0 | +| 0x50 | MM2S_VSIZE | Write last — triggers DMA | +| 0x54 | MM2S_HSIZE | Horizontal size in bytes | +| 0x58 | MM2S_FRMDLY_STRIDE | Stride in bytes [15:0] | +| 0x5C | MM2S_SA1 | Frame 1 start address | +| 0x60 | MM2S_SA2 | Frame 2 start address | + +## Clock Domains + +- **ui_clk (81.25 MHz)**: CPU, SmartConnect, MIG AXI interface, VDMA AXI master +- **CLK_100 (100 MHz)**: VDMA AXI-Stream output, axis_dwidth_converter, vga_out +- **CLK_200 (200 MHz)**: MIG IDELAYCTRL reference clock (mandatory for DDR3 calibration) + +Resets: `ui_clk_sync_rst` (active-high, from MIG) drives CPU reset directly. Inverted via NOT gate (`util_vector_logic_1`) to produce active-low `aresetn` for SmartConnect, MIG AXI slave, and VDMA. `vga_out/i_Reset` tied to constant-0 (runs freely after bitstream load). + +## Debug Interface + +- Protocol: 115200 baud, 8N1, single-byte opcodes +- Commands: halt, resume, reset, ping, read PC, dump pipeline state +- Tool: `tools/debugger/` (Go CLI), `tools/probe.py` (Python periodic monitor) +- See `.claude/rules/debug/debug.md` for full command set diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 0000000..6d4cbc3 --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,62 @@ +# Getting Started + +## Prerequisites + +1. **Verilator** — `sudo apt-get install verilator` (Ubuntu) or `brew install verilator` (macOS) +2. **Python 3** — `sudo apt-get install python3 python3-pip` +3. **cocotb** — `pip3 install cocotb pytest` +4. **Go** (optional, for debug tools) — `sudo apt-get install golang` + +## Running Tests + +```bash +cd tests +source test_env/bin/activate +make # run all tests +make TEST_TYPE=unit # unit tests only +make TEST_TYPE=integration # integration tests only +make clean # clean build artifacts +``` + +## Project Structure + +``` +hdl/ # Verilog sources +├── cpu/ # CPU core (pipeline, ALU, memory interface) +├── debug_peripheral/ # UART debug peripheral +└── vga_out/ # VGA output module + +tests/ +├── cpu/unit_tests/ # Per-module tests +└── cpu/integration_tests/ # Full instruction execution tests + +tools/ +├── debugger/ # Go UART debug CLI +└── probe.py # Python periodic board monitor + +config/ +├── arty-s7-50.xdc # Pin constraints +└── mig_b.prj # MIG DDR3 configuration + +ip_repo/ # Packaged CPU IP (required by Vivado block design) +build.tcl # Vivado block design reconstruction script +assemble.py # RISC-V assembler for boot ROM programs +``` + +## Flashing the FPGA + +1. Open Vivado, source `build.tcl` to recreate the block design +2. Run synthesis → implementation → generate bitstream +3. Flash via Vivado Hardware Manager +4. The CPU starts executing from `rom.mem` (generated by `assemble.py`) + +## Debug Tools + +```bash +# Go CLI debugger +go run tools/debugger/main.go + +# Python periodic monitor (auto-detects serial port) +python3 tools/probe.py +python3 tools/probe.py /dev/ttyUSB1 0.5 # explicit port + 0.5s interval +``` diff --git a/hdl/cpu/cpu.v b/hdl/cpu/cpu.v index c7e28ac..ed0532e 100644 --- a/hdl/cpu/cpu.v +++ b/hdl/cpu/cpu.v @@ -199,6 +199,7 @@ module cpu ( .i_Instruction_Addr(r_PC), .o_Instruction(w_Instruction), .o_Instruction_Valid(w_Instruction_Valid), + .o_State(w_Instruction_Memory_State), .s_axil_araddr(s_instruction_memory_axil_araddr), .s_axil_arvalid(s_instruction_memory_axil_arvalid), .s_axil_arready(s_instruction_memory_axil_arready), @@ -221,6 +222,7 @@ module cpu ( /*----------------PIPELINE STAGE 2----------------*/ wire [MEMORY_STATE_WIDTH:0] w_Memory_State; + wire [1:0] w_Instruction_Memory_State; function reg f_Is_Load(input [LS_SEL_WIDTH:0] v); begin @@ -380,6 +382,13 @@ module cpu ( .i_PC(r_PC), .i_Pipeline_Flushed(w_Pipeline_Flushed), + .i_Mem_AXI_State(w_Memory_State), + .i_Stall_S1(w_Stall_S1), + .i_Enable_Instruction_Fetch(w_Enable_Instruction_Fetch), + .i_S2_Valid(r_S2_Valid), + .i_S3_Valid(r_S3_Valid), + .i_Instr_Mem_AXI_State(w_Instruction_Memory_State), + .i_Init_Calib_Complete(i_Init_Calib_Complete), .o_Uart_Rx_Out(o_Uart_Rx_Out), .o_Halt_Cpu(w_Debug_Stall), diff --git a/hdl/cpu/instruction_memory/instruction_memory_axi.v b/hdl/cpu/instruction_memory/instruction_memory_axi.v index 3e78c90..8a9570d 100644 --- a/hdl/cpu/instruction_memory/instruction_memory_axi.v +++ b/hdl/cpu/instruction_memory/instruction_memory_axi.v @@ -8,6 +8,7 @@ module instruction_memory_axi ( input [XLEN-1:0] i_Instruction_Addr, output reg [XLEN-1:0] o_Instruction, output o_Instruction_Valid, + output [1:0] o_State, // AXI INTERFACE output [31:0] s_axil_araddr, @@ -76,6 +77,7 @@ module instruction_memory_axi ( end assign o_Instruction_Valid = (r_State == READ_SUCCESS); + assign o_State = r_State; // assign o_Fetch_Busy = (r_State != IDLE); // Calculate offset from CPU base address for ROM indexing diff --git a/hdl/cpu/memory/memory.vh b/hdl/cpu/memory/memory.vh index 48ce201..53f8ec5 100644 --- a/hdl/cpu/memory/memory.vh +++ b/hdl/cpu/memory/memory.vh @@ -21,6 +21,7 @@ parameter [MEMORY_STATE_WIDTH:0] READ_SUCCESS = 3'b011; parameter [MEMORY_STATE_WIDTH:0] WRITE_SUBMITTING = 3'b100; parameter [MEMORY_STATE_WIDTH:0] WRITE_AWAITING = 3'b101; parameter [MEMORY_STATE_WIDTH:0] WRITE_SUCCESS = 3'b110; +parameter [MEMORY_STATE_WIDTH:0] MEMORY_ERROR = 3'b111; `endif // MEMORY_PARAMS_VH diff --git a/hdl/cpu/memory/memory_axi.v b/hdl/cpu/memory/memory_axi.v index d952599..88e491b 100644 --- a/hdl/cpu/memory/memory_axi.v +++ b/hdl/cpu/memory/memory_axi.v @@ -118,7 +118,11 @@ module memory_axi ( end WRITE_SUBMITTING: begin if (s_axil_awready && s_axil_wready) begin - r_State <= s_axil_bvalid ? WRITE_SUCCESS : WRITE_AWAITING; + if (s_axil_bvalid) begin + r_State <= WRITE_SUCCESS; + end else begin + r_State <= WRITE_AWAITING; + end end end WRITE_AWAITING: begin @@ -129,6 +133,9 @@ module memory_axi ( WRITE_SUCCESS: begin r_State <= IDLE; end + MEMORY_ERROR: begin + // Get stuck for now + end default: begin r_State <= IDLE; end @@ -177,7 +184,7 @@ module memory_axi ( assign s_axil_wvalid = r_State == WRITE_SUBMITTING; assign s_axil_wdata = r_State == WRITE_SUBMITTING ? w_Prepared_WData : 0; assign s_axil_wstrb = r_State == WRITE_SUBMITTING ? w_Prepared_WStrb : 0; - assign s_axil_bready = r_State == WRITE_SUBMITTING; + assign s_axil_bready = r_State == WRITE_SUBMITTING || r_State == WRITE_AWAITING; assign o_State = r_State; diff --git a/hdl/debug_peripheral/debug_peripheral.v b/hdl/debug_peripheral/debug_peripheral.v index f6f11ec..01944ea 100644 --- a/hdl/debug_peripheral/debug_peripheral.v +++ b/hdl/debug_peripheral/debug_peripheral.v @@ -11,6 +11,13 @@ module debug_peripheral ( input [31:0] i_PC, input i_Pipeline_Flushed, + input [2:0] i_Mem_AXI_State, + input i_Stall_S1, + input i_Enable_Instruction_Fetch, + input i_S2_Valid, + input i_S3_Valid, + input [1:0] i_Instr_Mem_AXI_State, + input i_Init_Calib_Complete, output reg o_Halt_Cpu, output reg o_Reset_Cpu, @@ -217,6 +224,32 @@ module debug_peripheral ( r_State <= s_IDLE; end end + op_DUMP_STATE: begin + case (r_Exec_Counter) + 0: begin + output_buffer[output_buffer_head] <= { + i_Mem_AXI_State, + i_Pipeline_Flushed, + i_Stall_S1, + i_Enable_Instruction_Fetch, + i_S2_Valid, + i_S3_Valid + }; + output_buffer_head <= output_buffer_head + 1; + end + 1: begin + output_buffer[output_buffer_head] <= { + i_Instr_Mem_AXI_State, + i_Init_Calib_Complete, + 5'b0 + }; + output_buffer_head <= output_buffer_head + 1; + end + default: begin + r_State <= s_IDLE; + end + endcase + end default: begin r_State <= s_IDLE; end diff --git a/hdl/debug_peripheral/debug_peripheral.vh b/hdl/debug_peripheral/debug_peripheral.vh index 44351ce..0e3c64f 100644 --- a/hdl/debug_peripheral/debug_peripheral.vh +++ b/hdl/debug_peripheral/debug_peripheral.vh @@ -15,6 +15,7 @@ localparam op_READ_PC = 8'h06; localparam op_WRITE_PC = 8'h07; localparam op_READ_REGISTER = 8'h08; localparam op_WRITE_REGISTER = 8'h09; +localparam op_DUMP_STATE = 8'h0A; localparam PING_RESPONSE_BYTE = 8'hAA; diff --git a/hdl/vga_out/vga_out.v b/hdl/vga_out/vga_out.v index f495a16..7ae75c9 100644 --- a/hdl/vga_out/vga_out.v +++ b/hdl/vga_out/vga_out.v @@ -4,11 +4,16 @@ module vga_out #( parameter BITS_PER_COLOR_CHANNEL = 4 ) ( input i_Reset, + + (* X_INTERFACE_PARAMETER = "ASSOCIATED_BUSIF s_axis, ASSOCIATED_RESET i_Reset" *) input i_Clock, // AXI-Stream Interface + (* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 s_axis TDATA" *) input [15:0] s_axis_tdata, + (* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 s_axis TVALID" *) input s_axis_tvalid, + (* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 s_axis TREADY" *) output s_axis_tready, output o_mm2s_fsync, diff --git a/ip_repo/component.xml b/ip_repo/component.xml new file mode 100644 index 0000000..97a9e0b --- /dev/null +++ b/ip_repo/component.xml @@ -0,0 +1,1273 @@ + + + user.org + user + cpu + 1.0 + + + s_data_memory_axil + + + + + + + + + AWADDR + + + s_data_memory_axil_awaddr + + + + + AWVALID + + + s_data_memory_axil_awvalid + + + + + AWREADY + + + s_data_memory_axil_awready + + + + + WDATA + + + s_data_memory_axil_wdata + + + + + WSTRB + + + s_data_memory_axil_wstrb + + + + + WVALID + + + s_data_memory_axil_wvalid + + + + + WREADY + + + s_data_memory_axil_wready + + + + + BRESP + + + s_data_memory_axil_bresp + + + + + BVALID + + + s_data_memory_axil_bvalid + + + + + BREADY + + + s_data_memory_axil_bready + + + + + ARADDR + + + s_data_memory_axil_araddr + + + + + ARVALID + + + s_data_memory_axil_arvalid + + + + + ARREADY + + + s_data_memory_axil_arready + + + + + RDATA + + + s_data_memory_axil_rdata + + + + + RVALID + + + s_data_memory_axil_rvalid + + + + + RREADY + + + s_data_memory_axil_rready + + + + + + s_instruction_memory_axil + + + + + + + + + AWADDR + + + s_instruction_memory_axil_awaddr + + + + + AWVALID + + + s_instruction_memory_axil_awvalid + + + + + AWREADY + + + s_instruction_memory_axil_awready + + + + + WDATA + + + s_instruction_memory_axil_wdata + + + + + WSTRB + + + s_instruction_memory_axil_wstrb + + + + + WVALID + + + s_instruction_memory_axil_wvalid + + + + + WREADY + + + s_instruction_memory_axil_wready + + + + + BRESP + + + s_instruction_memory_axil_bresp + + + + + BVALID + + + s_instruction_memory_axil_bvalid + + + + + BREADY + + + s_instruction_memory_axil_bready + + + + + ARADDR + + + s_instruction_memory_axil_araddr + + + + + ARVALID + + + s_instruction_memory_axil_arvalid + + + + + ARREADY + + + s_instruction_memory_axil_arready + + + + + RDATA + + + s_instruction_memory_axil_rdata + + + + + RVALID + + + s_instruction_memory_axil_rvalid + + + + + RREADY + + + s_instruction_memory_axil_rready + + + + + + i_Reset + + + + + + + RST + + + i_Reset + + + + + + i_Clock + + + + + + + CLK + + + i_Clock + + + + + + ASSOCIATED_RESET + i_Reset + + + ASSOCIATED_BUSIF + s_data_memory_axil:s_instruction_memory_axil + + + + + + + s_data_memory_axil + s_data_memory_axil + 0x100000000 + 32 + + + s_instruction_memory_axil + s_instruction_memory_axil + 0x100000000 + 32 + + + + + + xilinx_anylanguagesynthesis + Synthesis + :vivado.xilinx.com:synthesis + Verilog + cpu + + xilinx_anylanguagesynthesis_view_fileset + + + + viewChecksum + 0ca72e08 + + + + + xilinx_anylanguagebehavioralsimulation + Simulation + :vivado.xilinx.com:simulation + Verilog + cpu + + xilinx_anylanguagebehavioralsimulation_view_fileset + + + + viewChecksum + 0ca72e08 + + + + + xilinx_xpgui + UI Layout + :vivado.xilinx.com:xgui.ui + + xilinx_xpgui_view_fileset + + + + viewChecksum + f92e9879 + + + + + + + i_Reset + + in + + + std_logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + i_Clock + + in + + + std_logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + i_Init_Calib_Complete + + in + + + std_logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + i_Uart_Tx_In + + in + + + std_logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + o_Uart_Rx_Out + + out + + + std_logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_data_memory_axil_araddr + + out + + 31 + 0 + + + + std_logic_vector + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_data_memory_axil_arvalid + + out + + + std_logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_data_memory_axil_arready + + in + + + std_logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + 0 + + + + + s_data_memory_axil_rdata + + in + + 31 + 0 + + + + std_logic_vector + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + 0 + + + + + s_data_memory_axil_rvalid + + in + + + std_logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + 0 + + + + + s_data_memory_axil_rready + + out + + + std_logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_data_memory_axil_awaddr + + out + + 31 + 0 + + + + std_logic_vector + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_data_memory_axil_awvalid + + out + + + std_logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_data_memory_axil_awready + + in + + + std_logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + 0 + + + + + s_data_memory_axil_wdata + + out + + 31 + 0 + + + + std_logic_vector + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_data_memory_axil_wstrb + + out + + 3 + 0 + + + + std_logic_vector + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_data_memory_axil_wvalid + + out + + + std_logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_data_memory_axil_wready + + in + + + std_logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + 0 + + + + + s_data_memory_axil_bresp + + in + + 1 + 0 + + + + std_logic_vector + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + 0 + + + + + s_data_memory_axil_bvalid + + in + + + std_logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + 0 + + + + + s_data_memory_axil_bready + + out + + + std_logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_instruction_memory_axil_araddr + + out + + 31 + 0 + + + + std_logic_vector + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_instruction_memory_axil_arvalid + + out + + + std_logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_instruction_memory_axil_arready + + in + + + std_logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + 0 + + + + + s_instruction_memory_axil_rdata + + in + + 31 + 0 + + + + std_logic_vector + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + 0 + + + + + s_instruction_memory_axil_rvalid + + in + + + std_logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + 0 + + + + + s_instruction_memory_axil_rready + + out + + + std_logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_instruction_memory_axil_awaddr + + out + + 31 + 0 + + + + std_logic_vector + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_instruction_memory_axil_awvalid + + out + + + std_logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_instruction_memory_axil_awready + + in + + + std_logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + 0 + + + + + s_instruction_memory_axil_wdata + + out + + 31 + 0 + + + + std_logic_vector + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_instruction_memory_axil_wstrb + + out + + 3 + 0 + + + + std_logic_vector + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_instruction_memory_axil_wvalid + + out + + + std_logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_instruction_memory_axil_wready + + in + + + std_logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + 0 + + + + + s_instruction_memory_axil_bresp + + in + + 1 + 0 + + + + std_logic_vector + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + 0 + + + + + s_instruction_memory_axil_bvalid + + in + + + std_logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + 0 + + + + + s_instruction_memory_axil_bready + + out + + + std_logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + + + + xilinx_anylanguagesynthesis_view_fileset + + ../hdl/debug_peripheral/debug_peripheral.vh + verilogSource + true + + + ../hdl/cpu/memory/memory.vh + verilogSource + true + + + ../hdl/cpu/immediate_unit/immediate_unit.vh + verilogSource + true + + + ../hdl/cpu/control_unit/control_unit.vh + verilogSource + true + + + ../hdl/cpu/comparator_unit/comparator_unit.vh + verilogSource + true + + + ../hdl/cpu/arithmetic_logic_unit/arithmetic_logic_unit.vh + verilogSource + true + + + ../hdl/cpu/cpu_core_params.vh + verilogSource + true + + + ../hdl/debug_peripheral/uart_transmitter.v + verilogSource + IMPORTED_FILE + + + ../hdl/cpu/cpu_core_params.vh + verilogSource + true + + + ../hdl/cpu/arithmetic_logic_unit/arithmetic_logic_unit.vh + verilogSource + true + + + ../hdl/cpu/arithmetic_logic_unit/arithmetic_logic_unit.v + verilogSource + + + ../hdl/cpu/comparator_unit/comparator_unit.vh + verilogSource + true + + + ../hdl/cpu/comparator_unit/comparator_unit.v + verilogSource + + + ../hdl/cpu/immediate_unit/immediate_unit.vh + verilogSource + true + + + ../hdl/cpu/memory/memory.vh + verilogSource + true + + + ../hdl/cpu/control_unit/control_unit.vh + verilogSource + true + + + ../hdl/cpu/control_unit/control_unit.v + verilogSource + + + ../hdl/debug_peripheral/debug_peripheral.vh + verilogSource + true + + + ../hdl/debug_peripheral/debug_peripheral.v + verilogSource + + + ../hdl/cpu/immediate_unit/immediate_unit.v + verilogSource + + + ../hdl/cpu/instruction_memory/instruction_memory_axi.v + verilogSource + + + ../hdl/cpu/memory/memory_axi.v + verilogSource + + + ../hdl/cpu/register_file/register_file.v + verilogSource + + + ../hdl/debug_peripheral/uart_receiver.v + verilogSource + + + ../hdl/cpu/cpu.v + verilogSource + CHECKSUM_96d9a8df + + + ../rom.mem + mem + + + + xilinx_anylanguagebehavioralsimulation_view_fileset + + ../hdl/debug_peripheral/debug_peripheral.vh + verilogSource + true + + + ../hdl/cpu/memory/memory.vh + verilogSource + true + + + ../hdl/cpu/immediate_unit/immediate_unit.vh + verilogSource + true + + + ../hdl/cpu/control_unit/control_unit.vh + verilogSource + true + + + ../hdl/cpu/comparator_unit/comparator_unit.vh + verilogSource + true + + + ../hdl/cpu/arithmetic_logic_unit/arithmetic_logic_unit.vh + verilogSource + true + + + ../hdl/cpu/cpu_core_params.vh + verilogSource + true + + + ../hdl/debug_peripheral/uart_transmitter.v + verilogSource + IMPORTED_FILE + + + ../hdl/cpu/cpu_core_params.vh + verilogSource + true + + + ../hdl/cpu/arithmetic_logic_unit/arithmetic_logic_unit.vh + verilogSource + true + + + ../hdl/cpu/arithmetic_logic_unit/arithmetic_logic_unit.v + verilogSource + + + ../hdl/cpu/comparator_unit/comparator_unit.vh + verilogSource + true + + + ../hdl/cpu/comparator_unit/comparator_unit.v + verilogSource + + + ../hdl/cpu/immediate_unit/immediate_unit.vh + verilogSource + true + + + ../hdl/cpu/memory/memory.vh + verilogSource + true + + + ../hdl/cpu/control_unit/control_unit.vh + verilogSource + true + + + ../hdl/cpu/control_unit/control_unit.v + verilogSource + + + ../hdl/debug_peripheral/debug_peripheral.vh + verilogSource + true + + + ../hdl/debug_peripheral/debug_peripheral.v + verilogSource + + + ../hdl/cpu/immediate_unit/immediate_unit.v + verilogSource + + + ../hdl/cpu/instruction_memory/instruction_memory_axi.v + verilogSource + + + ../hdl/cpu/memory/memory_axi.v + verilogSource + + + ../hdl/cpu/register_file/register_file.v + verilogSource + + + ../hdl/debug_peripheral/uart_receiver.v + verilogSource + + + ../hdl/cpu/cpu.v + verilogSource + + + ../rom.mem + mem + + + + xilinx_xpgui_view_fileset + + xgui/cpu_v1_0.tcl + tclSource + CHECKSUM_f92e9879 + XGUI_VERSION_2 + + + + cpu_v1_0 + + + Component_Name + cpu_v1_0 + + + + + + virtex7 + qvirtex7 + versal + kintex7 + kintex7l + qkintex7 + qkintex7l + akintex7 + artix7 + artix7l + aartix7 + qartix7 + zynq + qzynq + azynq + spartan7 + aspartan7 + virtexu + zynquplus + virtexuplus + virtexuplusHBM + virtexuplus58g + kintexuplus + artixuplus + kintexu + + + /UserIP + + cpu_v1_0 + package_project + 9 + 2026-04-04T22:37:23Z + + + 2024.2 + + + + + + + + diff --git a/ip_repo/xgui/cpu_v1_0.tcl b/ip_repo/xgui/cpu_v1_0.tcl new file mode 100644 index 0000000..0db18e9 --- /dev/null +++ b/ip_repo/xgui/cpu_v1_0.tcl @@ -0,0 +1,10 @@ +# Definitional proc to organize widgets for parameters. +proc init_gui { IPINST } { + ipgui::add_param $IPINST -name "Component_Name" + #Adding Page + ipgui::add_page $IPINST -name "Page 0" + + +} + + diff --git a/rom.mem b/rom.mem new file mode 100644 index 0000000..03f9e75 --- /dev/null +++ b/rom.mem @@ -0,0 +1,65 @@ +800012b7 +abcd0337 +0062a023 +02a00393 +06438413 +008384b3 +0002a503 +02650263 +0000006f +0000006f +0000006f +0000006f +0000006f +0000006f +0000006f +0000006f +880002b7 +00300313 +0062a023 +00000393 +00000413 +00000493 +0002a503 +02650263 +0000006f +0000006f +0000006f +0000006f +0000006f +0000006f +0000006f +0000006f +880002b7 +0042a303 +00000393 +00000413 +00000493 +00100513 +00a37333 +02030263 +0000006f +0000006f +0000006f +0000006f +0000006f +0000006f +0000006f +0000006f +880002b7 +0502a303 +00000393 +00000413 +00000493 +1e000513 +02a30463 +0000006f +0000006f +0000006f +0000006f +0000006f +0000006f +0000006f +0000006f +0000006f +0000006f diff --git a/tests/Makefile b/tests/Makefile index 7f7a1a4..10b8ad4 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -107,6 +107,7 @@ ifeq ($(TEST_TYPE),vga) VERILOG_SOURCES += ./vga/unit_tests/vga_unit_tests_harness.v endif + export SIM TOPLEVEL_LANG VERILOG_SOURCES TOPLEVEL MODULE EXTRA_ARGS PYTHONPATH include $(shell cocotb-config --makefiles)/Makefile.sim diff --git a/tests/cpu/constants.py b/tests/cpu/constants.py index 998cbce..7c13058 100644 --- a/tests/cpu/constants.py +++ b/tests/cpu/constants.py @@ -114,5 +114,6 @@ DEBUG_OP_WRITE_PC = 0x07 DEBUG_OP_READ_REGISTER = 0x08 DEBUG_OP_WRITE_REGISTER = 0x09 +DEBUG_OP_DUMP_STATE = 0x0A PING_RESPONSE_BYTE = 0xAA \ No newline at end of file diff --git a/tests/cpu/integration_tests/test_debug_dump_state.py b/tests/cpu/integration_tests/test_debug_dump_state.py new file mode 100644 index 0000000..0cd6c00 --- /dev/null +++ b/tests/cpu/integration_tests/test_debug_dump_state.py @@ -0,0 +1,85 @@ +import cocotb +from cpu.utils import uart_send_byte, uart_wait_for_byte +from cpu.constants import DEBUG_OP_HALT, DEBUG_OP_DUMP_STATE +from cocotb.clock import Clock +from cocotb.triggers import ClockCycles + +wait_ns = 1 + +@cocotb.test() +async def test_dump_state_command(dut): + """Test DUMP_STATE returns correct 2-byte encoding of pipeline/memory state""" + + clock = Clock(dut.i_Clock, wait_ns, "ns") + cocotb.start_soon(clock.start()) + + dut.i_Reset.value = 1 + await ClockCycles(dut.i_Clock, 1) + dut.i_Reset.value = 0 + await ClockCycles(dut.i_Clock, 1) + + # Halt CPU so pipeline state is stable + await uart_send_byte(dut.i_Clock, dut.cpu.i_Uart_Tx_In, dut.cpu.debug_peripheral.uart_receiver.o_Rx_DV, DEBUG_OP_HALT) + await ClockCycles(dut.i_Clock, 20) + + # Sample expected signal values directly from DUT + mem_axi_state = dut.cpu.w_Memory_State.value.integer + pipeline_flushed = dut.cpu.w_Pipeline_Flushed.value.integer + stall_s1 = dut.cpu.w_Stall_S1.value.integer + enable_fetch = dut.cpu.w_Enable_Instruction_Fetch.value.integer + s2_valid = dut.cpu.r_S2_Valid.value.integer + s3_valid = dut.cpu.r_S3_Valid.value.integer + instr_mem_axi_state = dut.cpu.w_Instruction_Memory_State.value.integer + init_calib_complete = dut.cpu.i_Init_Calib_Complete.value.integer + + expected_byte0 = ( + ((mem_axi_state & 0x7) << 5) | + ((pipeline_flushed & 0x1) << 4) | + ((stall_s1 & 0x1) << 3) | + ((enable_fetch & 0x1) << 2) | + ((s2_valid & 0x1) << 1) | + (s3_valid & 0x1) + ) + expected_byte1 = ( + ((instr_mem_axi_state & 0x3) << 6) | + ((init_calib_complete & 0x1) << 5) + ) + + # Send DUMP_STATE command + await uart_send_byte(dut.i_Clock, dut.cpu.i_Uart_Tx_In, dut.cpu.debug_peripheral.uart_receiver.o_Rx_DV, DEBUG_OP_DUMP_STATE) + await ClockCycles(dut.i_Clock, 6) + + # Receive 2-byte response + byte0 = await uart_wait_for_byte( + dut.i_Clock, + dut.cpu.o_Uart_Rx_Out, + dut.cpu.debug_peripheral.uart_transmitter.o_Tx_Done + ) + byte1 = await uart_wait_for_byte( + dut.i_Clock, + dut.cpu.o_Uart_Rx_Out, + dut.cpu.debug_peripheral.uart_transmitter.o_Tx_Done + ) + + assert byte0 == expected_byte0, ( + f"DUMP_STATE byte0 mismatch. Expected 0x{expected_byte0:02X}, got 0x{byte0:02X}\n" + f" mem_axi={mem_axi_state}, pipeline_flushed={pipeline_flushed}, " + f"stall_s1={stall_s1}, enable_fetch={enable_fetch}, " + f"s2_valid={s2_valid}, s3_valid={s3_valid}" + ) + assert byte1 == expected_byte1, ( + f"DUMP_STATE byte1 mismatch. Expected 0x{expected_byte1:02X}, got 0x{byte1:02X}\n" + f" instr_mem_axi={instr_mem_axi_state}, init_calib_complete={init_calib_complete}" + ) + + # Verify individual fields from byte0 + assert ((byte0 >> 5) & 0x7) == mem_axi_state, "data mem_axi_state mismatch" + assert ((byte0 >> 4) & 0x1) == pipeline_flushed, "pipeline_flushed mismatch" + assert ((byte0 >> 3) & 0x1) == stall_s1, "stall_s1 mismatch" + assert ((byte0 >> 2) & 0x1) == enable_fetch, "enable_fetch mismatch" + assert ((byte0 >> 1) & 0x1) == s2_valid, "s2_valid mismatch" + assert (byte0 & 0x1) == s3_valid, "s3_valid mismatch" + + # Verify individual fields from byte1 + assert ((byte1 >> 6) & 0x3) == instr_mem_axi_state, "instr_mem_axi_state mismatch" + assert ((byte1 >> 5) & 0x1) == init_calib_complete, "init_calib_complete mismatch" diff --git a/tools/debugger/commands.go b/tools/debugger/commands.go index 710a14a..0534c2f 100644 --- a/tools/debugger/commands.go +++ b/tools/debugger/commands.go @@ -18,6 +18,7 @@ const ( CmdStatsDump CmdReadMemory CmdWriteMemory + CmdDumpState ) // CommandInfo holds display information about a command @@ -42,6 +43,7 @@ var commands = map[Command]CommandInfo{ CmdStatsDump: {"Read Stats", "Read CPU statistics", false}, CmdReadMemory: {"Read Memory", "Read memory at address", false}, CmdWriteMemory: {"Write Memory", "Write to memory address", false}, + CmdDumpState: {"Dump State", "Read CPU pipeline and memory AXI state", true}, } // GetOpCode returns the opcode for a command @@ -65,6 +67,8 @@ func (c Command) GetOpCode() (OpCode, bool) { return op_WRITE_REGISTER, true case CmdJumpToAddress: return op_WRITE_PC, true + case CmdDumpState: + return op_DUMP_STATE, true default: return 0, false } diff --git a/tools/debugger/opcodes.go b/tools/debugger/opcodes.go index 7a9e8f9..867774d 100644 --- a/tools/debugger/opcodes.go +++ b/tools/debugger/opcodes.go @@ -14,6 +14,7 @@ const ( op_WRITE_PC OpCode = 0x7 op_READ_REGISTER OpCode = 0x8 op_WRITE_REGISTER OpCode = 0x9 + op_DUMP_STATE OpCode = 0xA ) // String returns the human-readable name of the opcode @@ -39,6 +40,8 @@ func (o OpCode) String() string { return "READ_REGISTER" case op_WRITE_REGISTER: return "WRITE_REGISTER" + case op_DUMP_STATE: + return "DUMP_STATE" default: return "UNKNOWN" } diff --git a/tools/debugger/ui.go b/tools/debugger/ui.go index 22f6f94..092b759 100644 --- a/tools/debugger/ui.go +++ b/tools/debugger/ui.go @@ -119,7 +119,7 @@ func initialModel(serialMgr *SerialManager) model { cmdList := []Command{ CmdHalt, CmdUnhalt, CmdReset, CmdUnreset, CmdPing, CmdReadPC, CmdReadRegister, CmdSetRegister, - CmdJumpToAddress, CmdReadMemory, CmdWriteMemory, + CmdJumpToAddress, CmdDumpState, CmdReadMemory, CmdWriteMemory, CmdFullDump, CmdStatsDump, CmdLoadProgram, } @@ -456,6 +456,47 @@ func (m model) executeCommand(cmd Command) tea.Cmd { } } + // For DUMP_STATE, wait for 2-byte response and parse pipeline/memory fields + if cmd == CmdDumpState { + time.Sleep(300 * time.Millisecond) + + responses := m.serialMgr.GetResponses() + if len(responses) > 0 { + lastResp := responses[len(responses)-1] + if len(lastResp.Data) >= 2 { + b0 := lastResp.Data[0] + b1 := lastResp.Data[1] + dataMemStateNames := []string{ + "IDLE", "READ_SUBMITTING", "READ_AWAITING", "READ_SUCCESS", + "WRITE_SUBMITTING", "WRITE_AWAITING", "WRITE_SUCCESS", "MEMORY_ERROR", + } + instrMemStateNames := []string{ + "IDLE", "READ_SUBMITTING", "READ_AWAITING", "READ_SUCCESS", + } + dataMemState := (b0 >> 5) & 0x7 + pipelineFlushed := (b0 >> 4) & 0x1 + stallS1 := (b0 >> 3) & 0x1 + enableFetch := (b0 >> 2) & 0x1 + s2Valid := (b0 >> 1) & 0x1 + s3Valid := b0 & 0x1 + instrMemState := (b1 >> 6) & 0x3 + initCalibComplete := (b1 >> 5) & 0x1 + msg := fmt.Sprintf( + "✓ State dump:\n data_mem_axi: %s\n instr_mem_axi: %s\n init_calib: %d\n pipeline_flushed: %d\n stall_s1: %d\n enable_fetch: %d\n s2_valid: %d\n s3_valid: %d", + dataMemStateNames[dataMemState], instrMemStateNames[instrMemState], + initCalibComplete, pipelineFlushed, stallS1, enableFetch, s2Valid, s3Valid, + ) + return commandCompleteMsg{success: true, message: msg, cmd: cmd} + } + } + + return commandCompleteMsg{ + success: false, + message: "Failed to read state dump", + cmd: cmd, + } + } + // Wait a bit for response time.Sleep(150 * time.Millisecond) diff --git a/tools/probe.py b/tools/probe.py new file mode 100644 index 0000000..2df0c08 --- /dev/null +++ b/tools/probe.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python3 +"""Periodically probe the FPGA board via UART debug protocol.""" + +import serial +import time +import sys +import glob + +# Opcodes +OP_HALT = 0x03 +OP_UNHALT = 0x04 +OP_PING = 0x05 +OP_READ_PC = 0x06 +OP_DUMP_STATE = 0x0A + +# Data memory AXI states +DATA_MEM_STATES = {0: "IDLE", 1: "RD_SUBMIT", 2: "RD_AWAIT", 3: "RD_OK", + 4: "WR_SUBMIT", 5: "WR_AWAIT", 6: "WR_OK", 7: "MEM_ERR"} +INSTR_MEM_STATES = {0: "IDLE", 1: "RD_SUBMIT", 2: "RD_AWAIT", 3: "RD_OK"} + +PC_LABELS = { + 0x80000010: "fill_loop", + 0x80000014: "fill_loop+4", + 0x80000018: "fill_loop+8", + 0x8000001C: "fill_loop+C (branch)", + 0x80000020: "vdma_init", + 0x80000028: "vdma_ctrl_write", + 0x80000048: "vdma_vsize (trigger)", + 0x8000004C: "ddr3_test", + 0x8000006C: "*** FAIL ***", + 0x80000070: "*** PASS ***", +} + +def find_port(): + candidates = glob.glob("/dev/ttyUSB*") + glob.glob("/dev/ttyACM*") + if not candidates: + return None + # prefer USB1 if multiple + for p in candidates: + if "USB1" in p: + return p + return candidates[0] + +def send_byte(ser, b): + ser.write(bytes([b])) + +def read_bytes(ser, n, timeout=0.5): + ser.timeout = timeout + data = ser.read(n) + return data + +def ping(ser): + send_byte(ser, OP_PING) + r = read_bytes(ser, 1) + return len(r) == 1 and r[0] == 0xAA + +def read_pc(ser): + send_byte(ser, OP_READ_PC) + r = read_bytes(ser, 4) + if len(r) != 4: + return None + return int.from_bytes(r, "little") + +def dump_state(ser): + send_byte(ser, OP_DUMP_STATE) + r = read_bytes(ser, 2) + if len(r) != 2: + return None + b0, b1 = r[0], r[1] + return { + "data_mem": DATA_MEM_STATES.get((b0 >> 5) & 0x7, "?"), + "pipeline_flushed": bool(b0 & 0x10), + "stall_s1": bool(b0 & 0x08), + "enable_fetch": bool(b0 & 0x04), + "s2_valid": bool(b0 & 0x02), + "s3_valid": bool(b0 & 0x01), + "instr_mem": INSTR_MEM_STATES.get((b1 >> 6) & 0x3, "?"), + "init_calib": bool(b1 & 0x20), + } + +def probe_once(ser): + send_byte(ser, OP_HALT) + time.sleep(0.01) + + pc = read_pc(ser) + state = dump_state(ser) + + send_byte(ser, OP_UNHALT) + + return pc, state + +def main(): + port = sys.argv[1] if len(sys.argv) > 1 else find_port() + if not port: + print("No serial port found. Usage: probe.py [/dev/ttyUSBx]") + sys.exit(1) + + interval = float(sys.argv[2]) if len(sys.argv) > 2 else 1.0 + + print(f"Opening {port} @ 115200 baud") + ser = serial.Serial(port, 115200, timeout=0.5) + time.sleep(0.1) + + # flush + ser.reset_input_buffer() + + if not ping(ser): + print("PING failed — check connection") + ser.close() + sys.exit(1) + print("PING OK\n") + + prev_pc = None + while True: + try: + pc, state = probe_once(ser) + ts = time.strftime("%H:%M:%S") + + if pc is None or state is None: + print(f"[{ts}] read error") + else: + label = PC_LABELS.get(pc, "") + pc_str = f"0x{pc:08X}" + if label: + pc_str += f" ({label})" + + changed = pc != prev_pc + prev_pc = pc + + calib = "CAL" if state["init_calib"] else "no-cal" + dm = state["data_mem"] + im = state["instr_mem"] + flags = "" + if state["pipeline_flushed"]: flags += " FLUSHED" + if state["stall_s1"]: flags += " STALL" + if not state["enable_fetch"]: flags += " no-fetch" + + marker = ">>>" if changed else " " + print(f"[{ts}] {marker} PC={pc_str} dm={dm:8s} im={im:8s} {calib}{flags}") + + time.sleep(interval) + except KeyboardInterrupt: + print("\nDone.") + break + except Exception as e: + print(f"Error: {e}") + time.sleep(interval) + + ser.close() + +if __name__ == "__main__": + main()