Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 74 additions & 1 deletion fpga_diff/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ PRJ_NAME = fpga_$(CPU)$(if $(strip $(SUFFIX)),-$(strip $(SUFFIX)),)
PRJ_DIR ?= $(ENV_SCRIPTS_HOME)/$(PRJ_NAME)
PRJ ?= $(PRJ_DIR)/$(PRJ_NAME).xpr

.PHONY: bitstream vivado dump_ila write_jtag_flash
.PHONY: bitstream route vivado dump_ila write_jtag_flash incremental-flow cpu-dcp-interface cpu-dcp-flow

# Get Vivado version
VIVADO_VERSION := $(shell vivado -version 2>/dev/null | head -1 | grep -o '[0-9]\{4\}\.[0-9]' || echo "unknown")
Expand All @@ -39,6 +39,10 @@ synth:
bitstream:
vivado -mode batch -source ./tools/gen_bitstream.tcl -tclargs $(PRJ) impl_1 $(VIVADO_JOBS)

# Run implementation through route_design without writing a bitstream
route:
vivado -mode batch -source ./tools/run_impl_route.tcl -tclargs $(PRJ) impl_1 $(VIVADO_JOBS)

# Update file list for core RTL files
update_core_flist:
rm -rf $(CORE_DIR)/rtl/verification
Expand Down Expand Up @@ -98,6 +102,75 @@ add_sys_option:
get_impl_log:
cat $(PRJ_DIR)/$(PRJ_NAME).runs/impl_1/runme.log

INCREMENTAL_BASELINE_RELEASE ?=
INCREMENTAL_MODIFIED_RELEASE ?=
INCREMENTAL_OUT_DIR ?=
INCREMENTAL_EXTRA_ARGS ?=

# Run whole-project incremental synthesis and implementation.
incremental-flow:
tools/cpu_dcp_split/run_incremental_flow.py \
--baseline-release "$(INCREMENTAL_BASELINE_RELEASE)" \
--modified-release "$(INCREMENTAL_MODIFIED_RELEASE)" \
--cpu "$(CPU)" \
$(if $(strip $(INCREMENTAL_OUT_DIR)),--out-dir "$(INCREMENTAL_OUT_DIR)",) \
$(if $(strip $(VIVADO_JOBS)),--jobs "$(VIVADO_JOBS)",) \
$(INCREMENTAL_EXTRA_ARGS)


CPU_DCP_MODIFIED_RELEASE ?=
CPU_DCP_CPU_MODULE ?=
CPU_DCP_PARTITION_MODULE ?=
CPU_DCP_INTERFACE_MODE ?= stub
CPU_DCP_INTERFACE_OUT ?=
CPU_DCP_INTERFACE_JSON ?=
CPU_DCP_BASELINE_RELEASE ?=
CPU_DCP_REFERENCE_DCP ?=
CPU_DCP_REFERENCE_SYNTH_DCP ?=
CPU_DCP_REFERENCE_FINGERPRINT ?=
CPU_DCP_CPU_CELL ?=
CPU_DCP_CPU_INSTANCE ?=
CPU_DCP_SUBPARTITION_PRESET ?=
CPU_DCP_DCP ?=
CPU_DCP_OUT_DIR ?=
CPU_DCP_STOP_AFTER ?= route
CPU_DCP_SYNTH_INCREMENTAL_MODE ?= default
CPU_DCP_EXTRA_ARGS ?=

# Copy the generated CPU RTL port contract onto a CpuDcpTop-style partition
# module. This is useful for inspecting or regenerating only the DCP shell
# interface without running Vivado.
cpu-dcp-interface:
tools/cpu_dcp_split/sync_cpu_dcp_interface.py \
--release "$(CPU_DCP_MODIFIED_RELEASE)" \
$(if $(strip $(CPU_DCP_CPU_MODULE)),--cpu-module "$(CPU_DCP_CPU_MODULE)",) \
--partition-module "$(or $(strip $(CPU_DCP_PARTITION_MODULE)),CpuDcpTop)" \
--mode "$(CPU_DCP_INTERFACE_MODE)" \
$(if $(strip $(CPU_DCP_INTERFACE_OUT)),--out "$(CPU_DCP_INTERFACE_OUT)" --force,) \
$(if $(strip $(CPU_DCP_INTERFACE_JSON)),--json-out "$(CPU_DCP_INTERFACE_JSON)",)


# Run the DiffTest hot path with CPU fixed as a DCP partition. If no routed
# reference is provided, the flow builds one from the baseline release.
cpu-dcp-flow:
tools/cpu_dcp_split/run_cpu_dcp_flow.py \
--baseline-release "$(CPU_DCP_BASELINE_RELEASE)" \
--modified-release "$(CPU_DCP_MODIFIED_RELEASE)" \
$(if $(strip $(CPU)),--cpu "$(CPU)",) \
$(if $(strip $(CPU_DCP_REFERENCE_DCP)),--reference-routed-dcp "$(CPU_DCP_REFERENCE_DCP)",) \
$(if $(strip $(CPU_DCP_REFERENCE_SYNTH_DCP)),--reference-synth-dcp "$(CPU_DCP_REFERENCE_SYNTH_DCP)",) \
$(if $(strip $(CPU_DCP_REFERENCE_FINGERPRINT)),--reference-fingerprint "$(CPU_DCP_REFERENCE_FINGERPRINT)",) \
$(if $(strip $(CPU_DCP_CPU_CELL)),--cpu-cell "$(CPU_DCP_CPU_CELL)",) \
$(if $(strip $(CPU_DCP_CPU_MODULE)),--module "$(CPU_DCP_CPU_MODULE)",) \
$(if $(strip $(CPU_DCP_CPU_INSTANCE)),--cpu-instance "$(CPU_DCP_CPU_INSTANCE)",) \
$(if $(strip $(CPU_DCP_SUBPARTITION_PRESET)),--subpartition-preset "$(CPU_DCP_SUBPARTITION_PRESET)",--partition-module "$(or $(strip $(CPU_DCP_PARTITION_MODULE)),CpuDcpTop)") \
$(if $(strip $(CPU_DCP_DCP)),--cpu-dcp "$(CPU_DCP_DCP)",) \
$(if $(strip $(CPU_DCP_REFERENCE_DCP)),,--build-reference) \
$(if $(strip $(CPU_DCP_OUT_DIR)),--out-dir "$(CPU_DCP_OUT_DIR)",) \
--stop-after "$(CPU_DCP_STOP_AFTER)" \
--synth-incremental-mode "$(CPU_DCP_SYNTH_INCREMENTAL_MODE)" \
$(if $(strip $(VIVADO_JOBS)),--jobs "$(VIVADO_JOBS)",) \
$(CPU_DCP_EXTRA_ARGS)
# Display synthesis log
get_synth_log:
cat $(PRJ_DIR)/$(PRJ_NAME).runs/synth_1/runme.log
Expand Down
46 changes: 46 additions & 0 deletions fpga_diff/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,50 @@ FPGA_DDR_LOAD_CMD="bash -lc ' \
./fpga-host --diff <nemu> -i <workload>.bin
```

## Incremental Vivado Flows

The incremental drivers consume generated release directories containing
`build/rtl` and write checkpoints, logs, and manifests outside the release.

### Whole Project

```sh
make incremental-flow \
CPU=nutshell \
INCREMENTAL_BASELINE_RELEASE=/path/to/baseline-release \
INCREMENTAL_MODIFIED_RELEASE=/path/to/modified-release \
INCREMENTAL_OUT_DIR=/path/to/output \
VIVADO_JOBS=8
```

Use `INCREMENTAL_EXTRA_ARGS` for `--stop-after route`,
`--synth-incremental-mode quick`, `--impl-directive RuntimeOptimized`, or
`--dry-run`. Inspect `<output>/manifest.env`, checkpoint files, incremental
reuse reports, timing, and route status before accepting a result.

Both flows also write `implementation-fingerprint.json`. It hashes the release
build inputs, implementation Tcl/Make inputs, CPU and partition interfaces, and
the Vivado/implementation settings. Its `decision.recommended_action` states
whether no implementation changed, the CPU DCP is reusable, or a whole-project
incremental route is required.

### CPU-DCP

```sh
make cpu-dcp-flow \
CPU=nutshell \
CPU_DCP_BASELINE_RELEASE=/path/to/baseline-release \
CPU_DCP_MODIFIED_RELEASE=/path/to/modified-release \
CPU_DCP_OUT_DIR=/path/to/output \
VIVADO_JOBS=8
```

This flow checks release compatibility, prepares an OOC CPU checkpoint, imports
it into the top-level partition, then performs incremental implementation. Use
`make cpu-dcp-interface` to generate or validate only a `CpuDcpTop` interface.
When a routed reference is supplied, inspect `report_incremental_reuse`,
`timing_summary.rpt`, and `route_status.rpt` under the output directory.
For an externally retained routed DCP, also pass its prior fingerprint through
`CPU_DCP_REFERENCE_FINGERPRINT=/path/to/implementation-fingerprint.json`; the
flow rejects reuse if the reference baseline, interface, or implementation
context no longer matches.
192 changes: 102 additions & 90 deletions fpga_diff/src/rtl/nutshell/SimTop_wrapper.sv
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,18 @@ SimTop u_SimTop (
.clock (inter_soc_clk),
.reset (~sys_rstn_i),

.difftest_exit (),
.difftest_step (),
.difftest_perfCtrl_clean (1'b0),
.difftest_perfCtrl_dump (1'b0),
.difftest_logCtrl_begin (64'b0),
.difftest_logCtrl_end (64'hFFFFFFFFFFFFFFFF),
.difftest_logCtrl_level (64'b0),
.difftest_uart_out_valid (),
.difftest_uart_out_ch (),
.difftest_uart_in_valid (),
.difftest_uart_in_ch (8'b0),

// AXI4 MEMORY (flattened port names)
.difftest_mem_awready (mem_core_awready),
.difftest_mem_awvalid (mem_core_awvalid),
Expand Down Expand Up @@ -234,98 +246,98 @@ SimTop u_SimTop (
.difftest_mem_ruser ('b0),

// AXI4 MMIO
.io_mmio_awready (peri_awready),
.io_mmio_awvalid (peri_awvalid),
.io_mmio_awaddr (peri_awaddr),
.io_mmio_awprot (peri_awprot),
.io_mmio_awid (peri_awid),
.io_mmio_awuser (/* TODO */),
.io_mmio_awlen (peri_awlen),
.io_mmio_awsize (peri_awsize),
.io_mmio_awburst (peri_awburst),
.io_mmio_awlock (peri_awlock),
.io_mmio_awcache (peri_awcache),
.io_mmio_awqos (peri_awqos),

.io_mmio_wready (peri_wready),
.io_mmio_wvalid (peri_wvalid),
.io_mmio_wdata (peri_wdata),
.io_mmio_wstrb (peri_wstrb),
.io_mmio_wlast (peri_wlast),

.io_mmio_bready (peri_bready),
.io_mmio_bvalid (peri_bvalid),
.io_mmio_bresp (peri_bresp),
.io_mmio_bid (peri_bid),
.io_mmio_buser (/* TODO */),

.io_mmio_arready (peri_arready),
.io_mmio_arvalid (peri_arvalid),
.io_mmio_araddr (peri_araddr),
.io_mmio_arprot (peri_arprot),
.io_mmio_arid (peri_arid),
.io_mmio_aruser (/* TODO */),
.io_mmio_arlen (peri_arlen),
.io_mmio_arsize (peri_arsize),
.io_mmio_arburst (peri_arburst),
.io_mmio_arlock (peri_arlock),
.io_mmio_arcache (peri_arcache),
.io_mmio_arqos (peri_arqos),

.io_mmio_rready (peri_rready),
.io_mmio_rvalid (peri_rvalid),
.io_mmio_rresp (peri_rresp),
.io_mmio_rdata (peri_rdata),
.io_mmio_rlast (peri_rlast),
.io_mmio_rid (peri_rid),
.io_mmio_ruser (/* TODO */),
.io_mmio_aw_ready (peri_awready),
.io_mmio_aw_valid (peri_awvalid),
.io_mmio_aw_bits_addr (peri_awaddr),
.io_mmio_aw_bits_prot (peri_awprot),
.io_mmio_aw_bits_id (peri_awid),
.io_mmio_aw_bits_user (),
.io_mmio_aw_bits_len (peri_awlen),
.io_mmio_aw_bits_size (peri_awsize),
.io_mmio_aw_bits_burst (peri_awburst),
.io_mmio_aw_bits_lock (peri_awlock),
.io_mmio_aw_bits_cache (peri_awcache),
.io_mmio_aw_bits_qos (peri_awqos),

.io_mmio_w_ready (peri_wready),
.io_mmio_w_valid (peri_wvalid),
.io_mmio_w_bits_data (peri_wdata),
.io_mmio_w_bits_strb (peri_wstrb),
.io_mmio_w_bits_last (peri_wlast),

.io_mmio_b_ready (peri_bready),
.io_mmio_b_valid (peri_bvalid),
.io_mmio_b_bits_resp (peri_bresp),
.io_mmio_b_bits_id (peri_bid),
.io_mmio_b_bits_user (1'b0),

.io_mmio_ar_ready (peri_arready),
.io_mmio_ar_valid (peri_arvalid),
.io_mmio_ar_bits_addr (peri_araddr),
.io_mmio_ar_bits_prot (peri_arprot),
.io_mmio_ar_bits_id (peri_arid),
.io_mmio_ar_bits_user (),
.io_mmio_ar_bits_len (peri_arlen),
.io_mmio_ar_bits_size (peri_arsize),
.io_mmio_ar_bits_burst (peri_arburst),
.io_mmio_ar_bits_lock (peri_arlock),
.io_mmio_ar_bits_cache (peri_arcache),
.io_mmio_ar_bits_qos (peri_arqos),

.io_mmio_r_ready (peri_rready),
.io_mmio_r_valid (peri_rvalid),
.io_mmio_r_bits_resp (peri_rresp),
.io_mmio_r_bits_data (peri_rdata),
.io_mmio_r_bits_last (peri_rlast),
.io_mmio_r_bits_id (peri_rid),
.io_mmio_r_bits_user (1'b0),

// AXI4 DMA / FRONTEND
.io_frontend_awready (dma_core_awready),
.io_frontend_awvalid (dma_core_awvalid),
.io_frontend_awaddr (dma_core_awaddr[31:0]),
.io_frontend_awprot (dma_core_awprot),
.io_frontend_awid (dma_core_awid),
.io_frontend_awuser (/* TODO */),
.io_frontend_awlen (dma_core_awlen),
.io_frontend_awsize (dma_core_awsize),
.io_frontend_awburst (dma_core_awburst),
.io_frontend_awlock (dma_core_awlock),
.io_frontend_awcache (dma_core_awcache),
.io_frontend_awqos (dma_core_awqos),

.io_frontend_wready (dma_core_wready),
.io_frontend_wvalid (dma_core_wvalid),
.io_frontend_wdata (dma_core_wdata[63:0]),
.io_frontend_wstrb (dma_core_wstrb[7:0]),
.io_frontend_wlast (dma_core_wlast),

.io_frontend_bready (dma_core_bready),
.io_frontend_bvalid (dma_core_bvalid),
.io_frontend_bresp (dma_core_bresp),
.io_frontend_bid (dma_core_bid),
.io_frontend_buser (/* TODO */),

.io_frontend_arready (dma_core_arready),
.io_frontend_arvalid (dma_core_arvalid),
.io_frontend_araddr (dma_core_araddr[31:0]),
.io_frontend_arprot (dma_core_arprot),
.io_frontend_arid (dma_core_arid),
.io_frontend_aruser (/* TODO */),
.io_frontend_arlen (dma_core_arlen),
.io_frontend_arsize (dma_core_arsize),
.io_frontend_arburst (dma_core_arburst),
.io_frontend_arlock (dma_core_arlock),
.io_frontend_arcache (dma_core_arcache),
.io_frontend_arqos (dma_core_arqos),

.io_frontend_rready (dma_core_rready),
.io_frontend_rvalid (dma_core_rvalid),
.io_frontend_rresp (dma_core_rresp),
.io_frontend_rdata (dma_core_rdata[63:0]),
.io_frontend_rlast (dma_core_rlast),
.io_frontend_rid (dma_core_rid),
.io_frontend_ruser (/* TODO */),
.io_frontend_aw_ready (dma_core_awready),
.io_frontend_aw_valid (dma_core_awvalid),
.io_frontend_aw_bits_addr (dma_core_awaddr[31:0]),
.io_frontend_aw_bits_prot (dma_core_awprot),
.io_frontend_aw_bits_id (dma_core_awid),
.io_frontend_aw_bits_user (1'b0),
.io_frontend_aw_bits_len (dma_core_awlen),
.io_frontend_aw_bits_size (dma_core_awsize),
.io_frontend_aw_bits_burst (dma_core_awburst),
.io_frontend_aw_bits_lock (dma_core_awlock),
.io_frontend_aw_bits_cache (dma_core_awcache),
.io_frontend_aw_bits_qos (dma_core_awqos),

.io_frontend_w_ready (dma_core_wready),
.io_frontend_w_valid (dma_core_wvalid),
.io_frontend_w_bits_data (dma_core_wdata[63:0]),
.io_frontend_w_bits_strb (dma_core_wstrb[7:0]),
.io_frontend_w_bits_last (dma_core_wlast),

.io_frontend_b_ready (dma_core_bready),
.io_frontend_b_valid (dma_core_bvalid),
.io_frontend_b_bits_resp (dma_core_bresp),
.io_frontend_b_bits_id (dma_core_bid),
.io_frontend_b_bits_user (),

.io_frontend_ar_ready (dma_core_arready),
.io_frontend_ar_valid (dma_core_arvalid),
.io_frontend_ar_bits_addr (dma_core_araddr[31:0]),
.io_frontend_ar_bits_prot (dma_core_arprot),
.io_frontend_ar_bits_id (dma_core_arid),
.io_frontend_ar_bits_user (1'b0),
.io_frontend_ar_bits_len (dma_core_arlen),
.io_frontend_ar_bits_size (dma_core_arsize),
.io_frontend_ar_bits_burst (dma_core_arburst),
.io_frontend_ar_bits_lock (dma_core_arlock),
.io_frontend_ar_bits_cache (dma_core_arcache),
.io_frontend_ar_bits_qos (dma_core_arqos),

.io_frontend_r_ready (dma_core_rready),
.io_frontend_r_valid (dma_core_rvalid),
.io_frontend_r_bits_resp (dma_core_rresp),
.io_frontend_r_bits_data (dma_core_rdata[63:0]),
.io_frontend_r_bits_last (dma_core_rlast),
.io_frontend_r_bits_id (dma_core_rid),
.io_frontend_r_bits_user (),

// MIP
.io_meip (io_extIntrs[1:0]),
Expand Down
Loading