From 2beb05f95dc2c1fbed112454b4c031d84666d40e Mon Sep 17 00:00:00 2001 From: aottaviano Date: Thu, 4 Jan 2024 23:43:13 +0100 Subject: [PATCH 1/5] hw: Use parameter for number of targets in irq router --- hw/carfield_pkg.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/carfield_pkg.sv b/hw/carfield_pkg.sv index 4c3d6479..109ad9d9 100644 --- a/hw/carfield_pkg.sv +++ b/hw/carfield_pkg.sv @@ -269,7 +269,7 @@ localparam cheshire_cfg_t CarfieldCfgDefault = '{ NumExtIrqHarts : CarfieldNumInterruptibleHarts, NumExtInIntrs : CarfieldNumExtIntrs, NumExtClicIntrs : CarfieldNumExtIntrs, - NumExtOutIntrTgts : 1, + NumExtOutIntrTgts : CarfieldNumRouterTargets, NumExtOutIntrs : CarfieldNumExtIntrs+$bits(cheshire_int_intr_t), ClicIntCtlBits : 8, ClicUseSMode : 1, From 85ced100cdc9d40321a08cca7244f9595aabf504 Mon Sep 17 00:00:00 2001 From: aottaviano Date: Fri, 22 Dec 2023 14:44:09 +0100 Subject: [PATCH 2/5] treewide: Refactor tree structure * Rename `scripts` to `env` * Move simulation environment to dedicated `target/sim/` directory * Move `lint` in `utils` directory --- .gitignore | 7 - Bender.yml | 13 +- carfield.mk | 484 ++++++++---------- {scripts => env}/env-iis.sh | 0 {scripts => env}/pulpd-env.sh | 0 {scripts => env}/safed-env.sh | 0 {scripts => env}/spatzd-env.sh | 0 hw/carfield.sv | 2 +- scripts/spyglass/src/carfield_wrap.sv | 137 ----- stdout/.gitkeep | 0 sw/sw.mk | 8 +- ...p-offload.c => pulpd_offloader_blocking.c} | 0 target/.gitignore | 6 + target/sim/sim.mk | 147 ++++++ {tb => target/sim/src}/carfield_fix.sv | 0 {tb => target/sim/src}/carfield_tb.sv | 0 {tb => target/sim/src}/vip_carfield_soc.sv | 2 +- .../sim/vsim/start.carfield_soc.tcl | 0 target/synth/{ => src}/carfield_synth_wrap.sv | 0 target/xilinx/xilinx.mk | 21 +- scripts/Makefile => utils/lint/lint.mk | 0 .../lint}/spyglass/scripts/run_lint.tcl | 0 .../lint}/spyglass/sgdc/func.sgdc | 0 23 files changed, 405 insertions(+), 422 deletions(-) rename {scripts => env}/env-iis.sh (100%) rename {scripts => env}/pulpd-env.sh (100%) rename {scripts => env}/safed-env.sh (100%) rename {scripts => env}/spatzd-env.sh (100%) delete mode 100644 scripts/spyglass/src/carfield_wrap.sv delete mode 100644 stdout/.gitkeep rename sw/tests/bare-metal/hostd/{pulp-offload.c => pulpd_offloader_blocking.c} (100%) create mode 100644 target/.gitignore create mode 100644 target/sim/sim.mk rename {tb => target/sim/src}/carfield_fix.sv (100%) rename {tb => target/sim/src}/carfield_tb.sv (100%) rename {tb => target/sim/src}/vip_carfield_soc.sv (99%) rename scripts/start_carfield.tcl => target/sim/vsim/start.carfield_soc.tcl (100%) rename target/synth/{ => src}/carfield_synth_wrap.sv (100%) rename scripts/Makefile => utils/lint/lint.mk (100%) rename {scripts => utils/lint}/spyglass/scripts/run_lint.tcl (100%) rename {scripts => utils/lint}/spyglass/sgdc/func.sgdc (100%) diff --git a/.gitignore b/.gitignore index f2888c03..fa91a155 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,11 @@ .bender cheshire spatz -modelsim.ini -scripts/carfield_compile.tcl -tb/hyp_vip -transcript -work/ *.log *.wlf /.venv/ /logs/ /working_dir/ -/uart /stdout # sw auto-generated @@ -155,7 +149,6 @@ celerybeat.pid # Environments .env .venv -env/ venv/ ENV/ env.bak/ diff --git a/Bender.yml b/Bender.yml index 4788e056..01f6ef29 100644 --- a/Bender.yml +++ b/Bender.yml @@ -28,7 +28,6 @@ dependencies: pulp-ethernet: { git: https://github.com/pulp-platform/pulp-ethernet.git, rev: bdc8031ab270a49da28df269266ce9ab9a133636 } # branch: carfield riscv-dbg: { git: https://github.com/pulp-platform/riscv-dbg.git, version: =0.8.0 } - workspace: package_links: cheshire: cheshire @@ -55,18 +54,18 @@ sources: - target: test files: - - tb/hyp_vip/s27ks0641.v - - tb/vip_carfield_soc.sv - - tb/carfield_fix.sv - - tb/carfield_tb.sv + - target/sim/src/hyp_vip/s27ks0641.v + - target/sim/src/vip_carfield_soc.sv + - target/sim/src/carfield_fix.sv + - target/sim/src/carfield_tb.sv - target: spyglass files: - - scripts/spyglass/src/carfield_wrap.sv + - utils/lint/spyglass/src/carfield_wrap.sv - target: all(synthesis, not(fpga)) files: - - target/synth/carfield_synth_wrap.sv + - target/synth/src/carfield_synth_wrap.sv - target: all(xilinx, fpga, xilinx_vanilla) files: diff --git a/carfield.mk b/carfield.mk index 7d7be6ab..1e7371de 100644 --- a/carfield.mk +++ b/carfield.mk @@ -8,237 +8,125 @@ # Robert Balas # Manuel Eggimann +# Carfield main make fragment + +# Note: this makefrag uses autodocumentation, hence it follows rules for the comment style. See +# `utils/help.mk` for more information. + +################################### +# Generic variable initialization # +################################### + CAR_ROOT ?= $(shell $(BENDER) path carfield) -CAR_SW_DIR := $(CAR_ROOT)/sw -CAR_XIL_DIR := $(CAR_ROOT)/target/xilinx CAR_HW_DIR := $(CAR_ROOT)/hw +CAR_SW_DIR := $(CAR_ROOT)/sw +CAR_TGT_DIR := $(CAR_ROOT)/target/ +CAR_XIL_DIR := $(CAR_TGT_DIR)/xilinx +CAR_SIM_DIR := $(CAR_TGT_DIR)/sim +# Questasim +CAR_VSIM_DIR := $(CAR_TGT_DIR)/sim/vsim -BENDER ?= bender -QUESTA ?= questa-2022.3 -VIVADO ?= vitis-2020.2 vivado - +BENDER ?= bender BENDER_ROOT ?= $(CAR_ROOT)/.bender +BENDER_PATH ?= $(shell which $(BENDER)) -# Interrupt configuration in cheshire -# CLINT interruptible harts -CLINTCORES := 4 -# PLIC interruptible harts -PLICCORES := 8 -# PLIC number of input interrupts -PLIC_NUM_INTRS := 89 +# Include mandatory bender targets and defines for multiple targets (sim, fpga, synth) +include $(CAR_ROOT)/bender-common.mk +include $(CAR_ROOT)/bender-sim.mk +include $(CAR_ROOT)/bender-synth.mk +include $(CAR_ROOT)/bender-xilinx.mk +include $(CAR_ROOT)/bender-safed.mk -# Serial Link configuration in cheshire -SERIAL_LINK_NUM_BITS := 16 +###################### +# Nonfree components # +###################### -# AXI Real-Time unit configuration in Carfield -AXIRT_NUM_MGRS := 10 -AXIRT_NUM_SUBS := 2 +CAR_NONFREE_REMOTE ?= git@iis-git.ee.ethz.ch:carfield/carfield-nonfree.git +CAR_NONFREE_COMMIT ?= f18bbb8 -# Cheshire +## @section Carfield platform nonfree components +## Clone the non-free verification IP for Carfield. Some components such as CI scripts and ASIC +## implementations with tech-specific resources are not open-sourced and contained in a `nonfree` +## folder cloned from a remote location, whose access is restricted. If you do not have access, this +## step will be skipped and the usage of the repository will **not** be compromised. +car-nonfree-init: + git clone $(CAR_NONFREE_REMOTE) $(CAR_ROOT)/nonfree + cd nonfree && git checkout $(CAR_NONFREE_COMMIT) + cd nonfree/intel16 && icdesign intel16 -update all -nogui + +-include nonfree/nonfree.mk + +##################################### +# Islands' variables initialization # +##################################### + +# Cheshire, host domain CHS_ROOT ?= $(shell $(BENDER) path cheshire) # Include cheshire's makefrag only if the dependency was cloned -include $(CHS_ROOT)/cheshire.mk - -# Secure boot -SECURE_BOOT ?= 0 - CHS_BOOTMODE ?= 0 # default passive bootmode CHS_PRELMODE ?= 1 # default serial link preload CHS_BINARY ?= CHS_IMAGE ?= -# Safety Island +# Safety Island, reliabililty and fault-tolerance SAFED_ROOT ?= $(shell $(BENDER) path safety_island) SAFED_SW_DIR := $(SAFED_ROOT)/sw SAFED_BOOTMODE ?= 0 SAFED_BINARY ?= -# Security island +# Security island, security and secure boot SECD_ROOT ?= $(shell $(BENDER) path opentitan) SECD_BINARY ?= SECD_BOOTMODE ?= 0 SECD_IMAGE ?= +# Secure boot +SECURE_BOOT ?= 0 -# PULP cluster +# PULP cluster, reliability and general-purpose accelerator PULPD_ROOT ?= $(shell $(BENDER) path pulp_cluster) PULPD_BINARY ?= PULPD_TEST_NAME ?= PULPD_BOOTMODE ?= -# Spatz cluster +# Spatz cluster, efficient vector co-processor SPATZD_ROOT ?= $(shell $(BENDER) path spatz) SPATZD_MAKEDIR := $(SPATZD_ROOT)/hw/system/spatz_cluster SPATZD_BINARY ?= SPATZD_BOOTMODE ?= 0 # default jtag bootmode -SPATZD_BENDER_DIR ?= $(shell which $(BENDER)) - -# Default variable values for RTL simulation -TBENCH ?= tb_carfield_soc - -# Defines for hyperram model preload at time 0 -HYP_USER_PRELOAD ?= 0 -ifeq ($(HYP_USER_PRELOAD), 1) - HYP0_PRELOAD_MEM_FILE ?= "$(CAR_ROOT)/sw/tests/bare-metal/pulpd/$(PULPD_TEST_NAME).hyperram0.slm" - HYP1_PRELOAD_MEM_FILE ?= "$(CAR_ROOT)/sw/tests/bare-metal/pulpd/$(PULPD_TEST_NAME).hyperram1.slm" -else - HYP0_PRELOAD_MEM_FILE ?= "" - HYP1_PRELOAD_MEM_FILE ?= "" -endif - -RUNTIME_DEFINES := +define+HYP_USER_PRELOAD="$(HYP_USER_PRELOAD)" -RUNTIME_DEFINES += +define+HYP0_PRELOAD_MEM_FILE=\"$(HYP0_PRELOAD_MEM_FILE)\" -RUNTIME_DEFINES += +define+HYP1_PRELOAD_MEM_FILE=\"$(HYP1_PRELOAD_MEM_FILE)\" - -# Include bender targets and defines for common usage and synth verification -# (the following includes are mandatory) -include $(CAR_ROOT)/bender-common.mk -include $(CAR_ROOT)/bender-sim.mk -include $(CAR_ROOT)/bender-synth.mk -include $(CAR_ROOT)/bender-xilinx.mk -include $(CAR_ROOT)/bender-safed.mk - -# Setup Virtual Environment for python scripts (reggen) -VENVDIR?=$(WORKDIR)/.venv -REQUIREMENTS_TXT?=$(wildcard requirements.txt) -include $(CAR_ROOT)/utils/venv.mk - -QUESTA_FLAGS := -permissive -suppress 3009 -suppress 8386 -error 7 +UVM_NO_RELNOTES -ifdef DEBUG - VOPT_FLAGS := $(QUESTA_FLAGS) +acc - VSIM_FLAGS := $(QUESTA_FLAGS) - RUN_AND_EXIT := log -r /*; run -all -else - VOPT_FLAGS := $(QUESTA_FLAGS) -O5 +acc=p+tb_carfield_soc. +noacc=p+carfield. - VSIM_FLAGS := $(QUESTA_FLAGS) -c - RUN_AND_EXIT := run -all; exit -endif - -###################### -# Nonfree components # -###################### -CAR_NONFREE_REMOTE ?= git@iis-git.ee.ethz.ch:carfield/carfield-nonfree.git -CAR_NONFREE_COMMIT ?= e446a8e30d3e5556d14ff74953c51f1bbf8c670f +########################### +# System HW configuration # +########################### -## Clone the non-free verification IP for the Carfield TB -car-nonfree-init: - git clone $(CAR_NONFREE_REMOTE) $(CAR_ROOT)/nonfree - cd nonfree && git checkout $(CAR_NONFREE_COMMIT) - cd nonfree/intel16 && icdesign intel16 -update all -nogui - --include nonfree/nonfree.mk - -############ -# Build SW # -############ - -include $(CAR_SW_DIR)/sw.mk - -############## -# Simulation # -############## -.PHONY: $(CAR_ROOT)/hw/regs/carfield_regs.hjson -$(CAR_ROOT)/hw/regs/carfield_regs.hjson: hw/regs/carfield_regs.csv | venv - $(VENV)/python ./scripts/csv_to_json.py --input $< --output $@ - -.PHONY: $(CAR_ROOT)/hw/regs/carfield_reg_pkg.sv hw/regs/carfield_reg_top.sv -$(CAR_ROOT)/hw/regs/carfield_reg_pkg.sv $(CAR_ROOT)/hw/regs/carfield_reg_top.sv: $(CAR_ROOT)/hw/regs/carfield_regs.hjson | venv - $(VENV)/python utils/reggen/regtool.py -r $< --outdir $(dir $@) +# Interrupt configuration in cheshire +# CLINT interruptible harts +CLINTCORES := 4 +# PLIC interruptible harts +PLICCORES := 8 +# PLIC number of input interrupts +PLIC_NUM_INTRS := 89 -.PHONY: $(CAR_SW_DIR)/include/regs/soc_ctrl.h -$(CAR_SW_DIR)/include/regs/soc_ctrl.h: $(CAR_ROOT)/hw/regs/carfield_regs.hjson | venv - $(VENV)/python utils/reggen/regtool.py -D $< > $@ +# Serial Link configuration in cheshire +SERIAL_LINK_NUM_BITS := 16 -## @section Carfield SoC HW Generation -.PHONY: regenerate_soc_regs -## Regenerate the toplevel SoC Control Register file from the CSV description of all registers in -## hw/regs/carfield_regs.csv. You don't have to run this target unless you changed the CSV file. The -## checked-in pregenerated register file RTL should be up-to-date. If you regenerate the regfile, do -## not forget to check in the generated RTL. -regenerate_soc_regs: $(CAR_ROOT)/hw/regs/carfield_reg_pkg.sv $(CAR_ROOT)/hw/regs/carfield_reg_top.sv $(CAR_SW_DIR)/include/regs/soc_ctrl.h +# AXI Real-Time unit configuration in Carfield +AXIRT_NUM_MGRS := 10 +AXIRT_NUM_SUBS := 2 -## @section Carfield CLINT and PLIC interruptible harts configuration +########################################## +# Virtual environment for python scripts # +########################################## -## The default configuration in cheshire allows for one interruptible hart. When the number of -## external interruptible harts is updated in the cheshire cfg (cheshire_pkg.sv), we need to -## regenerate the PLIC and CLINT accordingly. -## CLINT: define CLINTCORES used in cheshire.mk before including the makefrag. -## PLIC: edit the hjson configuration file in cheshire. -.PHONY: update_plic -update_plic: $(CHS_ROOT)/hw/rv_plic.cfg.hjson - sed -i 's/src: .*/src: $(PLIC_NUM_INTRS),/' $< - sed -i 's/target: .*/target: $(PLICCORES),/' $< +VENVDIR?=$(WORKDIR)/.venv +REQUIREMENTS_TXT?=$(wildcard requirements.txt) +include $(CAR_ROOT)/utils/venv.mk -# @section Serial Link configuration -## The default configuration in cheshire allows for 4 data lanes for the serial link. We update the -## configuration to 8 data lanes. -.PHONY: update_serial_link -update_serial_link: $(CHS_ROOT)/hw/serial_link.hjson - sed -i 's/\(default: "\)8/\116/' $< +########################## +# Dependency maintenance # +########################## -$(CAR_ROOT)/tb/hyp_vip: - rm -rf $@ - mkdir $@ - rm -rf model_tmp && mkdir model_tmp - cd model_tmp; wget https://www.infineon.com/dgdl/Infineon-S27KL0641_S27KS0641_VERILOG-SimulationModels-v05_00-EN.zip?fileId=8ac78c8c7d0d8da4017d0f6349a14f68 - cd model_tmp; mv 'Infineon-S27KL0641_S27KS0641_VERILOG-SimulationModels-v05_00-EN.zip?fileId=8ac78c8c7d0d8da4017d0f6349a14f68' model.zip - cd model_tmp; unzip model.zip - cd model_tmp; mv 'S27KL0641 S27KS0641' exe_folder - cd model_tmp/exe_folder; unzip S27ks0641.exe - cp model_tmp/exe_folder/S27ks0641/model/s27ks0641.v model_tmp/exe_folder/S27ks0641/model/s27ks0641_verilog.sdf $@ - rm -rf model_tmp - -.PHONY: scripts/carfield_compile.tcl -scripts/carfield_compile.tcl: - $(BENDER) script vsim $(common_targs) $(sim_targs) $(common_defs) $(safed_defs) --vlog-arg="$(VLOG_ARGS) $(RUNTIME_DEFINES)" --compilation-mode separate > $@ - echo 'vlog "$(CHS_ROOT)/target/sim/src/elfloader.cpp" -ccflags "-std=c++11"' >> $@ - echo 'vopt $(VOPT_FLAGS) $(TBENCH) -o $(TBENCH)_opt' >> $@ - -.PHONY: car-sim-init -car-sim-init: chs-sim-init $(CAR_ROOT)/tb/hyp_vip scripts/carfield_compile.tcl - -## @section Carfield SoC Simulation -## Compile the Carfield RTL using Questasim. -car-hw-build: car-sim-init - $(QUESTA) vsim -c -do "quit -code [source scripts/carfield_compile.tcl]" - -.PHONY: car-hw-sim -## Run simulation of the carfield RTL. -## @param BOOTMODE=0 The bootmode of carfield. -## @param PRELMODE=1 If 1, use the serial link for memory preloading. -## @param TESTNAME=hello_wolrd The name of the test to simulate. This automatically sets the BINARY variable. Defaults to hello_world. -## @param MEMTYPE=spm The kind of memory used for preloading the test. -## @param BINARY=sw/tests/hello_world/hello_world.spm.elf The path to the elf binary to simulate. Defaults to the path of the test chosen with TESTNAME. -## @param TBENCH=tb_carfield_soc_opt The optimised toplevel testbench to use. Defaults to 'tb_carfield_soc_opt'. -## @param VSIM_FLAGS the flags for the vsim invocation -car-hw-sim: - $(QUESTA) vsim $(VSIM_FLAGS) -do \ - "set HYP_USER_PRELOAD $(HYP_USER_PRELOAD); \ - set SECURE_BOOT $(SECURE_BOOT); \ - set CHS_BOOTMODE $(CHS_BOOTMODE); \ - set CHS_PRELMODE $(CHS_PRELMODE); \ - set CHS_BINARY $(CHS_BINARY); \ - set CHS_IMAGE $(CHS_IMAGE); \ - set SECD_BINARY $(SECD_BINARY); \ - set SECD_BOOTMODE $(SECD_BOOTMODE); \ - set SECD_IMAGE $(SECD_IMAGE); \ - set SAFED_BOOTMODE $(SAFED_BOOTMODE); \ - set SAFED_BINARY $(SAFED_BINARY); \ - set PULPD_BOOTMODE $(PULPD_BOOTMODE); \ - set PULPD_BINARY $(PULPD_BINARY); \ - set SPATZD_BINARY $(SPATZD_BINARY); \ - set SPATZD_BOOTMODE $(SPATZD_BOOTMODE);\ - set TESTBENCH $(TBENCH); \ - set VSIM_FLAGS \"$(VSIM_FLAGS)\"; \ - source $(CAR_ROOT)/scripts/start_carfield.tcl ; \ - $(RUN_AND_EXIT)" - -.PHONY: car-hw-clean -## Remove all simulation build artifacts -car-hw-clean: - rm -rf *.ini trace* *.wlf transcript work - -## @section Carfield SoC Dependency Management +## @section Carfield platform dependency management .PHONY: car-update-deps ## Update and re-resove all IP dependencies. Bender will try to resolve dependency conflicts with ## semantic versioning and the Bender.local file that contains overrides. You should run this target @@ -260,49 +148,23 @@ car-checkout-deps: .PHONY: car-checkout car-checkout: car-checkout-deps -## @section Carfield initialization -.PHONY: car-hw-init -## Initialize carfield by generating cheshire and spatz registers and wrapper, respectively -## This step takes care of the generation of the missing hardware, or an update of the configuration -## of some IPs, such as the PLIC or CLINT. -car-hw-init: spatzd-hw-init chs-hw-init - -.PHONY: spatzd-hw-init -spatzd-hw-init: - $(MAKE) -C $(SPATZD_ROOT) hw/ip/snitch/src/riscv_instr.sv - $(MAKE) -C $(SPATZD_MAKEDIR) -B SPATZ_CLUSTER_CFG=$(SPATZD_MAKEDIR)/cfg/carfield.hjson bootrom - cp $(SPATZD_ROOT)/sw/snRuntime/include/spatz_cluster_peripheral.h $(CAR_SW_DIR)/include/regs/ - -.PHONY: chs-hw-init -## This target has a prerequisite, i.e. the PLIC configuration must be chosen before generating the -## hardware. -chs-hw-init: update_plic update_serial_link - # Note: We use `-B` as AXI RT doesn't currently have a `regenerate` PHONY target to always - # trigger register regeneration when the value of the variables passed to its makefrag - # changes. - $(MAKE) -B chs-hw-all - -.PHONY: chs-sim-init -## Downloads verification IPs for SPI and I2C from cheshire and used by Carfield. -chs-sim-init: - $(MAKE) chs-sim-all +############ +# Build SW # +############ +include $(CAR_SW_DIR)/sw.mk +## @section Carfield platform SW build .PHONY: chs-sw-build -## Builds the SW libraries in cheshire and generates an archive (`libcheshire.a`) available for -## carfield as static library at link time. +## Build the host domain (Cheshire) SW libraries and generates an archive (`libcheshire.a`) +## available for Carfield as static library at link time. chs-sw-build: chs-sw-all .PHONY: car-sw-build ## Builds carfield application SW and specific libraries. It links against `libcheshire.a`. car-sw-build: chs-sw-build safed-sw-build pulpd-sw-build car-sw-all -.PHONY: car-init -## Shortcut to initialize carfield with all the targets described above. -car-init: car-checkout car-hw-init car-sim-init safed-sw-init pulpd-sw-init mibench - -# Initialize and build SW for the Islands .PHONY: safed-sw-init pulpd-sw-init -# Safety Island +## Clone safe domain's SW stack in the dedicated repository. safed-sw-init: $(SAFED_ROOT) $(SAFED_SW_DIR)/pulp-runtime $(SAFED_SW_DIR)/pulp-freertos $(SAFED_SW_DIR)/pulp-runtime: $(SAFED_ROOT) @@ -310,7 +172,7 @@ $(SAFED_SW_DIR)/pulp-runtime: $(SAFED_ROOT) $(SAFED_SW_DIR)/pulp-freertos: $(SAFED_ROOT) $(MAKE) -C $(SAFED_ROOT) pulp-freertos BENDER="$(BENDER)" -# PULP Cluster +## Clone integer PMCA domain's SW stack in the dedicated repository. pulpd-sw-init: $(PULPD_ROOT) $(PULPD_ROOT)/pulp-runtime $(PULPD_ROOT)/regression-tests $(PULPD_ROOT)/pulp-runtime: $(PULPD_ROOT) @@ -318,20 +180,147 @@ $(PULPD_ROOT)/pulp-runtime: $(PULPD_ROOT) $(PULPD_ROOT)/regression-tests: $(PULPD_ROOT) $(MAKE) -C $(PULPD_ROOT) regression-tests -# For independent boot of an island, we allow to compile the binary standalone. +## Build safe domain SW .PHONY: safed-sw-build -safed-sw-build: - . $(CAR_ROOT)/scripts/safed-env.sh; \ +safed-sw-build: safed-sw-init + . $(CAR_ROOT)/env/safed-env.sh; \ $(MAKE) safed-sw-all +## Build integer PMCA domain SW .PHONY: pulpd-sw-build -pulpd-sw-build: - . $(CAR_ROOT)/scripts/pulpd-env.sh; \ +pulpd-sw-build: pulpd-sw-init + . $(CAR_ROOT)/env/pulpd-env.sh; \ $(MAKE) pulpd-sw-all -#.PHONY: spatzd-sw-build -#spatzd-sw-build: -# $(MAKE) -C $(SPATZD_MAKEDIR) BENDER=$(SPATZD_BENDER_DIR) LLVM_INSTALL_DIR=$(LLVM_SPATZ_DIR) GCC_INSTALL_DIR=$(GCC_SPATZ_DIR) −B SPATZ_CLUSTER_CFG=$(SPATZD_MAKEDIR)/cfg/carfield.hjson HTIF_SERVER=NO sw.vsim +## Build vectorial PMCA domain SW +# TODO: properly compile spatz tests from carfield. For now, we symlink to existing tests. If you +#are a user external to ETH, the symlink will not work. We will integrate the compilation flow ASAP. + +#.PHONY: spatzd-sw-build spatzd-sw-build: $(MAKE) -C $(SPATZD_MAKEDIR) BENDER=$(BENDER_PATH) +#LLVM_INSTALL_DIR=$(LLVM_SPATZ_DIR) GCC_INSTALL_DIR=$(GCC_SPATZ_DIR) −B +#SPATZ_CLUSTER_CFG=$(SPATZD_MAKEDIR)/cfg/carfield.hjson HTIF_SERVER=NO sw.vsim + +############### +# Generate HW # +############### + +## @section Carfield platform HW generation +.PHONY: car-hw-init +## Initialize Carfield HW. This step takes care of the generation of the missing hardware or the +## update of default HW configurations in some of the domains. See the two prerequisite's comment +## for more information. +car-hw-init: spatzd-hw-init chs-hw-init + +## @section Carfield platform PCRs generation +.PHONY: regenerate_soc_regs +## Regenerate the toplevel PCRs from the CSV description of all registers in +## hw/regs/carfield_regs.csv. You don't have to run this target unless you changed the CSV file. The +## checked-in pregenerated register file RTL should be up-to-date. If you regenerate the regfile, do +## not forget to check in the generated RTL. In addition, dedicated documentation is autogenerated. +regenerate_soc_regs: $(CAR_ROOT)/hw/regs/carfield_reg_pkg.sv $(CAR_ROOT)/hw/regs/carfield_reg_top.sv $(CAR_SW_DIR)/include/regs/soc_ctrl.h $(CAR_HW_DIR)/regs/pcr.md + +.PHONY: $(CAR_ROOT)/hw/regs/carfield_regs.hjson +$(CAR_ROOT)/hw/regs/carfield_regs.hjson: hw/regs/carfield_regs.csv | venv + $(VENV)/python ./scripts/csv_to_json.py --input $< --output $@ + +.PHONY: $(CAR_ROOT)/hw/regs/carfield_reg_pkg.sv hw/regs/carfield_reg_top.sv +$(CAR_ROOT)/hw/regs/carfield_reg_pkg.sv $(CAR_ROOT)/hw/regs/carfield_reg_top.sv: $(CAR_ROOT)/hw/regs/carfield_regs.hjson | venv + $(VENV)/python utils/reggen/regtool.py -r $< --outdir $(dir $@) + +.PHONY: $(CAR_SW_DIR)/include/regs/soc_ctrl.h +$(CAR_SW_DIR)/include/regs/soc_ctrl.h: $(CAR_ROOT)/hw/regs/carfield_regs.hjson | venv + $(VENV)/python utils/reggen/regtool.py -D $< > $@ + +.PHONY: $(CAR_SW_DIR)/hw/regs/pcr.md +$(CAR_HW_DIR)/regs/pcr.md: $(CAR_ROOT)/hw/regs/carfield_regs.hjson | venv + $(VENV)/python utils/reggen/regtool.py -d $< > $@ + +## Update host domain PLIC and CLINT interrupt controllers configuration. The default configuration +## in cheshire allows for one interruptible hart. When the number of external interruptible harts is +## updated in the Cheshire cfg (cheshire_pkg.sv), we need to regenerate the PLIC and CLINT +## accordingly. CLINT: define CLINTCORES used in cheshire.mk before including the makefrag. PLIC: +## edit the hjson configuration file in cheshire. +.PHONY: update_plic +update_plic: $(CHS_ROOT)/hw/rv_plic.cfg.hjson + sed -i 's/src: .*/src: $(PLIC_NUM_INTRS),/' $< + sed -i 's/target: .*/target: $(PLICCORES),/' $< + +## Update host domain Serial Link configuration. The default configuration in cheshire allows for 4 +## data lanes for the serial link. We update the configuration to 8 data lanes. +.PHONY: update_serial_link +update_serial_link: $(CHS_ROOT)/hw/serial_link.hjson + sed -i 's/\(default: "\)8/\116/' $< + +## Generate Spatz HW starting from a configuration file. This includes register file, memory map, +## interconnect parametrization. +.PHONY: spatzd-hw-init +spatzd-hw-init: + $(MAKE) -C $(SPATZD_ROOT) hw/ip/snitch/src/riscv_instr.sv + $(MAKE) -C $(SPATZD_MAKEDIR) -B SPATZ_CLUSTER_CFG=$(SPATZD_MAKEDIR)/cfg/carfield.hjson bootrom + cp $(SPATZD_ROOT)/sw/snRuntime/include/spatz_cluster_peripheral.h $(CAR_SW_DIR)/include/regs/ + +## Generate Cheshire HW. This target has a prerequisite, i.e. the PLIC and serial link +## configurations must be chosen before generating the hardware. +.PHONY: chs-hw-init +chs-hw-init: update_plic update_serial_link + $(MAKE) -B chs-hw-all + +############## +# Simulation # +############## + +## @section Carfield platform simulation +include $(CAR_SIM_DIR)/sim.mk + +################## +# Global targets # +################## + +## @section Carfield global targets + +.PHONY: car-init-all +## Shortcut to initialize carfield with all the targets described above. +car-init-all: car-checkout car-hw-init car-sim-init safed-sw-init pulpd-sw-init mibench + +## Initialize Carfield and build SW +.PHONY: car-all +car-all: car-init-all car-sw-build + +######### +# Utils # +######### +## @section Carfield platform utilities + +# Lint +SPYGLASS_TARGS += $(common_targs) +SPYGLASS_TARGS += $(synth_targs) +SPYGLASS_DEFS += $(common_defs) +SPYGLASS_DEFS += $(synth_defs) + +## Lint the Carfield codebase using Spyglass +.PHONY:lint +lint: + $(MAKE) -C scripts lint bender_defs="$(SPYGLASS_DEFS)" bender_targs="$(SPYGLASS_TARGS)" > make.log + +############# +# Emulation # +############# +## @section Carfield emulation + +# Xilinx +include $(CAR_XIL_DIR)/xilinx.mk + +####################### +# External benchmarks # +####################### + +## @section External SW benchmarks +## Clone Mibench Embedded Suite benchmark +.PHONY: mibench +mibench: $(CAR_SW_DIR)/benchmarks/mibench + +$(CAR_SW_DIR)/benchmarks/mibench: + git clone git@github.com:alex96295/mibench.git -b carfield $@ # Litmus tests LITMUS_WORK_DIR := work-litmus @@ -356,45 +345,16 @@ $(LITMUS_WORK_DIR)/%.litmus.log: $(LITMUS_WORK_DIR)/%.uart.log cat $< >> $@ echo "" >> $@ +## Clone Litmus tests for the RISC-V concurrency architecture and run them car-run-litmus-tests: $(LITMUS_TEST_LIST) $(addprefix $(LITMUS_WORK_DIR)/, $(addsuffix .litmus.log,$(LITMUS_TESTS))) cat $^ > $(LITMUS_WORK_DIR)/litmus.log +## Check Litmus tests results against golden model car-check-litmus-tests: $(LITMUS_WORK_DIR)/litmus.log cd $(LITMUS_DIR) && LITMUS_LOG=$(CURDIR)/$(LITMUS_WORK_DIR)/litmus.log ci/compare_model.sh > $(CURDIR)/$(LITMUS_WORK_DIR)/compare.log grep "Warning positive differences" $(LITMUS_WORK_DIR)/compare.log ! grep "Warning negative differences" $(LITMUS_WORK_DIR)/compare.log -############ -# RTL LINT # -############ -SPYGLASS_TARGS += $(common_targs) -SPYGLASS_TARGS += $(synth_targs) -SPYGLASS_DEFS += $(common_defs) -SPYGLASS_DEFS += $(synth_defs) - -## @section Carfield SoC Utilities - -.PHONY:lint -## Run Spyglass Lint on the entire RTL -lint: - $(MAKE) -C scripts lint bender_defs="$(SPYGLASS_DEFS)" bender_targs="$(SPYGLASS_TARGS)" > make.log - -############# -# Emulation # -############# - -include $(CAR_XIL_DIR)/xilinx.mk - -############## -# Benchmarks # -############## - -.PHONY: mibench -mibench: $(CAR_SW_DIR)/benchmarks/mibench - -$(CAR_SW_DIR)/benchmarks/mibench: - git clone git@github.com:alex96295/mibench.git -b carfield $@ - ######## # Help # ######## diff --git a/scripts/env-iis.sh b/env/env-iis.sh similarity index 100% rename from scripts/env-iis.sh rename to env/env-iis.sh diff --git a/scripts/pulpd-env.sh b/env/pulpd-env.sh similarity index 100% rename from scripts/pulpd-env.sh rename to env/pulpd-env.sh diff --git a/scripts/safed-env.sh b/env/safed-env.sh similarity index 100% rename from scripts/safed-env.sh rename to env/safed-env.sh diff --git a/scripts/spatzd-env.sh b/env/spatzd-env.sh similarity index 100% rename from scripts/spatzd-env.sh rename to env/spatzd-env.sh diff --git a/hw/carfield.sv b/hw/carfield.sv index 52bdf6da..2ebbb111 100644 --- a/hw/carfield.sv +++ b/hw/carfield.sv @@ -602,7 +602,7 @@ logic [NumDomains-1:0] pwr_on_rsts_n; logic [NumDomains-1:0] rsts_n; -// Each of the 5 clock gateable domains (periph, safety island, security island, spatz and pulp +// Each of the 6 clock gateable domains (periph, safety island, security island, l2, spatz and pulp // cluster) have the following clock distribution scheme: // 1. For each domain the user selects one of 3 different clock sources (host clock, alt clock and // per clock). Each of these main clocks are either supplied externally, by a dedicated PLL per diff --git a/scripts/spyglass/src/carfield_wrap.sv b/scripts/spyglass/src/carfield_wrap.sv deleted file mode 100644 index 3752d900..00000000 --- a/scripts/spyglass/src/carfield_wrap.sv +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright 2021 ETH Zurich and University of Bologna. -// Solderpad Hardware License, Version 0.51, see LICENSE for details. -// SPDX-License-Identifier: SHL-0.51 -// -// Author: Matteo Perotti -// Description: Carfield wrap for SpyGlass analysis. - -module carfield_wrap import carfield_pkg::*; import cheshire_pkg::*; #( - parameter cheshire_cfg_t Cfg = carfield_pkg::CarfieldCfgDefault, // from Cheshire package - parameter int unsigned HypNumPhys = 1, - parameter int unsigned HypNumChips = 1 -) ( - input logic clk_i, - input logic rst_ni, - input logic test_mode_i, - // Boot mode selection - input logic [1:0] boot_mode_i, - // CLINT - input logic rtc_i, - // JTAG Interfacex - input logic jtag_tck_i, - input logic jtag_trst_ni, - input logic jtag_tms_i, - input logic jtag_tdi_i, - output logic jtag_tdo_o, - output logic jtag_tdo_oe_o, - // UART Interface - output logic uart_tx_o, - input logic uart_rx_i, - // UART Modem flow control - output logic uart_rts_no, - output logic uart_dtr_no, - input logic uart_cts_ni, - input logic uart_dsr_ni, - input logic uart_dcd_ni, - input logic uart_rin_ni, - // I2C Interface - output logic i2c_sda_o, - input logic i2c_sda_i, - output logic i2c_sda_en_o, - output logic i2c_scl_o, - input logic i2c_scl_i, - output logic i2c_scl_en_o, - // SPI Host Interface - output logic spih_sck_o, - output logic spih_sck_en_o, - output logic [SpihNumCs-1:0] spih_csb_o, - output logic [SpihNumCs-1:0] spih_csb_en_o, - output logic [ 3:0] spih_sd_o, - output logic [ 3:0] spih_sd_en_o, - input logic [ 3:0] spih_sd_i, - // GPIO interface - input logic [31:0] gpio_i, - output logic [31:0] gpio_o, - output logic [31:0] gpio_en_o, - // Serial link interface - input logic [SlinkNumChan-1:0] slink_rcv_clk_i, - output logic [SlinkNumChan-1:0] slink_rcv_clk_o, - input logic [SlinkNumChan-1:0][SlinkNumLanes-1:0] slink_i, - output logic [SlinkNumChan-1:0][SlinkNumLanes-1:0] slink_o, - // HyperBus clocks - input logic hyp_clk_phy_i, - input logic hyp_rst_phy_ni, - // Physical interace: facing HyperBus - inout [HypNumPhys-1:0][HypNumChips-1:0] pad_hyper_csn, - inout [HypNumPhys-1:0] pad_hyper_ck, - inout [HypNumPhys-1:0] pad_hyper_ckn, - inout [HypNumPhys-1:0] pad_hyper_rwds, - inout [HypNumPhys-1:0] pad_hyper_reset, - inout [HypNumPhys-1:0][7:0] pad_hyper_dq -); - - // DefaultCfg from cheshire_pkg - localparam cheshire_cfg_t DutCfg = DefaultCfg; - - /********************/ - /* Hyper RAM Params */ - /********************/ - - localparam int NumPhys = 1; - localparam int NumChips = 2; - - carfield #( - .Cfg ( DefaultCfg ), - .HypNumPhys ( NumPhys ), - .HypNumChips ( NumChips ) - ) i_dut ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - .test_mode_i (test_mode_i ), - .boot_mode_i (boot_mode_i ), - .rtc_i (rtc_i ), - .jtag_tck_i (jtag_tck_i ), - .jtag_trst_ni (jtag_trst_ni ), - .jtag_tms_i (jtag_tms_i ), - .jtag_tdi_i (jtag_tdi_i ), - .jtag_tdo_o (jtag_tdo_o ), - .jtag_tdo_oe_o (jtag_tdo_oe_o ), - .uart_tx_o (uart_tx_o ), - .uart_rx_i (uart_rx_i ), - .uart_rts_no (uart_rts_no ), - .uart_dtr_no (uart_dtr_no ), - .uart_cts_ni (uart_cts_ni ), - .uart_dsr_ni (uart_dsr_ni ), - .uart_dcd_ni (uart_dcd_ni ), - .uart_rin_ni (uart_rin_ni ), - .i2c_sda_o (i2c_sda_o ), - .i2c_sda_i (i2c_sda_i ), - .i2c_sda_en_o (i2c_sda_en_o ), - .i2c_scl_o (i2c_scl_o ), - .i2c_scl_i (i2c_scl_i ), - .i2c_scl_en_o (i2c_scl_en_o ), - .spih_sck_o (spih_sck_o ), - .spih_sck_en_o (spih_sck_en_o ), - .spih_csb_o (spih_csb_o ), - .spih_csb_en_o (spih_csb_en_o ), - .spih_sd_o (spih_sd_o ), - .spih_sd_en_o (spih_sd_en_o ), - .spih_sd_i (spih_sd_i ), - .gpio_i (gpio_i ), - .gpio_o (gpio_o ), - .gpio_en_o (gpio_en_o ), - .slink_rcv_clk_i (slink_rcv_clk_i ), - .slink_rcv_clk_o (slink_rcv_clk_o ), - .slink_i (slink_i ), - .slink_o (slink_o ), - .hyp_clk_phy_i (hyp_clk_phy_i ), - .hyp_rst_phy_ni (hyp_rst_phy_ni ), - .pad_hyper_csn (pad_hyper_csn ), - .pad_hyper_ck (pad_hyper_ck ), - .pad_hyper_ckn (pad_hyper_ckn ), - .pad_hyper_rwds (pad_hyper_rwds ), - .pad_hyper_reset (pad_hyper_reset ), - .pad_hyper_dq (pad_hyper_dq ) - ); - -endmodule diff --git a/stdout/.gitkeep b/stdout/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/sw/sw.mk b/sw/sw.mk index 40a3d9e2..5ac68305 100644 --- a/sw/sw.mk +++ b/sw/sw.mk @@ -59,11 +59,11 @@ $(foreach link,$(patsubst $(CAR_LD_DIR)/%.ld,%,$(wildcard $(CAR_LD_DIR)/*.ld)),$ CAR_ELFLOAD_BLOCKING_SAFED_SRC_C := $(CAR_SW_DIR)/tests/bare-metal/hostd/safed_offloader_blocking.c CAR_ELFLOAD_BLOCKING_SAFED_PATH := $(basename $(CAR_ELFLOAD_BLOCKING_SAFED_SRC_C)) -CAR_ELFLOAD_PULPD_SRC_C := $(CAR_SW_DIR)/tests/bare-metal/hostd/pulp-offload.c -CAR_ELFLOAD_PULPD_PATH := $(basename $(CAR_ELFLOAD_PULPD_SRC_C)) +CAR_ELFLOAD_BLOCKING_PULPD_SRC_C := $(CAR_SW_DIR)/tests/bare-metal/hostd/pulpd_offloader_blocking.c +CAR_ELFLOAD_BLOCKING_PULPD_PATH := $(basename $(CAR_ELFLOAD_BLOCKING_PULPD_SRC_C)) CAR_SW_TEST_SRCS_S = $(wildcard $(CAR_SW_DIR)/tests/bare-metal/hostd/*.S) -CAR_SW_TEST_SRCS_C = $(filter-out $(CAR_ELFLOAD_BLOCKING_SAFED_SRC_C) $(CAR_ELFLOAD_PULPD_SRC_C), $(wildcard $(CAR_SW_DIR)/tests/bare-metal/hostd/*.c)) +CAR_SW_TEST_SRCS_C = $(filter-out $(CAR_ELFLOAD_BLOCKING_SAFED_SRC_C) $(CAR_ELFLOAD_BLOCKING_PULPD_SRC_C), $(wildcard $(CAR_SW_DIR)/tests/bare-metal/hostd/*.c)) CAR_SW_TEST_DRAM_DUMP = $(CAR_SW_TEST_SRCS_S:.S=.car.dram.dump) $(CAR_SW_TEST_SRCS_C:.c=.car.dram.dump) CAR_SW_TEST_DRAM_SLM = $(CAR_SW_TEST_SRCS_S:.S=.car.dram.slm) $(CAR_SW_TEST_SRCS_C:.c=.car.dram.slm) @@ -103,7 +103,7 @@ car-safed-sw-offload-tests: include $(CAR_SW_DIR)/tests/bare-metal/pulpd/sw.mk car-pulpd-sw-offload-tests: - $(call offload_tests_template,$(PULPD_HEADER_TARGETS),pulpd,$(CAR_ELFLOAD_PULPD_SRC_C),$(CAR_ELFLOAD_PULPD_PATH)) + $(call offload_tests_template,$(PULPD_HEADER_TARGETS),pulpd,$(CAR_ELFLOAD_BLOCKING_PULPD_SRC_C),$(CAR_ELFLOAD_BLOCKING_PULPD_PATH)) # Litmus tests LITMUS_REPO := https://github.com/pulp-platform/CHERI-Litmus.git diff --git a/sw/tests/bare-metal/hostd/pulp-offload.c b/sw/tests/bare-metal/hostd/pulpd_offloader_blocking.c similarity index 100% rename from sw/tests/bare-metal/hostd/pulp-offload.c rename to sw/tests/bare-metal/hostd/pulpd_offloader_blocking.c diff --git a/target/.gitignore b/target/.gitignore new file mode 100644 index 00000000..912e58c9 --- /dev/null +++ b/target/.gitignore @@ -0,0 +1,6 @@ +sim/vsim/modelsim.ini +sim/vsim/carfield_compile.tcl +sim/vsimtranscript +sim/vsim/work/ +sim/vsim/uart/ +sim/src/hyp_vip diff --git a/target/sim/sim.mk b/target/sim/sim.mk new file mode 100644 index 00000000..b25bd2df --- /dev/null +++ b/target/sim/sim.mk @@ -0,0 +1,147 @@ +# Copyright 2024 ETH Zurich and University of Bologna. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Alessandro Ottaviano + +## @section Carfield platform simulation + +QUESTA ?= questa-2023.4 +TBENCH ?= tb_carfield_soc + +## Get HyperRAM verification IP (VIP) for simulation +$(CAR_TGT_DIR)/sim/src/hyp_vip: + rm -rf $@ + mkdir $@ + rm -rf model_tmp && mkdir model_tmp + cd model_tmp; wget https://www.infineon.com/dgdl/Infineon-S27KL0641_S27KS0641_VERILOG-SimulationModels-v05_00-EN.zip?fileId=8ac78c8c7d0d8da4017d0f6349a14f68 + cd model_tmp; mv 'Infineon-S27KL0641_S27KS0641_VERILOG-SimulationModels-v05_00-EN.zip?fileId=8ac78c8c7d0d8da4017d0f6349a14f68' model.zip + cd model_tmp; unzip model.zip + cd model_tmp; mv 'S27KL0641 S27KS0641' exe_folder + cd model_tmp/exe_folder; unzip S27ks0641.exe + cp model_tmp/exe_folder/S27ks0641/model/s27ks0641.v model_tmp/exe_folder/S27ks0641/model/s27ks0641_verilog.sdf $@ + rm -rf model_tmp + +CAR_SIM_ALL += $(CHS_ROOT)/target/sim/models/s25fs512s.v +CAR_SIM_ALL += $(CHS_ROOT)/target/sim/models/24FC1025.v +CAR_SIM_ALL += $(CAR_TGT_DIR)/sim/src/hyp_vip + +# Defines for hyperram model preload at time 0 +HYP_USER_PRELOAD ?= 0 +HYP0_PRELOAD_MEM_FILE ?= "" +HYP1_PRELOAD_MEM_FILE ?= "" + +RUNTIME_DEFINES := +define+HYP_USER_PRELOAD="$(HYP_USER_PRELOAD)" +RUNTIME_DEFINES += +define+HYP0_PRELOAD_MEM_FILE=\"$(HYP0_PRELOAD_MEM_FILE)\" +RUNTIME_DEFINES += +define+HYP1_PRELOAD_MEM_FILE=\"$(HYP1_PRELOAD_MEM_FILE)\" + +############# +# Questasim # +############# + +## @section Questasim simulator target + +QUESTA_FLAGS := -permissive -suppress 3009 -suppress 8386 -error 7 +UVM_NO_RELNOTES +ifdef DEBUG + VOPT_FLAGS := $(QUESTA_FLAGS) +acc + VSIM_FLAGS := $(QUESTA_FLAGS) + RUN_AND_EXIT := log -r /*; run -all +else + VOPT_FLAGS := $(QUESTA_FLAGS) -O5 +acc=p+$(TBENCH). +noacc=p+carfield. + VSIM_FLAGS := $(QUESTA_FLAGS) -c + RUN_AND_EXIT := run -all; exit +endif + +.PHONY: $(CAR_VSIM_DIR)/compile.carfield_soc.tcl +$(CAR_VSIM_DIR)/compile.carfield_soc.tcl: + $(BENDER) script vsim $(common_targs) $(sim_targs) $(common_defs) $(safed_defs) --vlog-arg="$(RUNTIME_DEFINES)" --compilation-mode separate > $@ + echo 'vlog "$(CHS_ROOT)/target/sim/src/elfloader.cpp" -ccflags "-std=c++11"' >> $@ + echo 'vopt $(VOPT_FLAGS) $(TBENCH) -o $(TBENCH)_opt' >> $@ + +CAR_VSIM_ALL += $(CAR_SIM_ALL) +CAR_VSIM_ALL += $(CAR_VSIM_DIR)/compile.carfield_soc.tcl + +## Generate all required VIPs (SPI flash, I2c EEPROm, HyperRAM, etc) and compilation scripts for Questasim +.PHONY: car-vsim-sim-init +car-vsim-sim-init: $(CAR_VSIM_ALL) + +## Compile Carfield HW using Questasim. Run `make car-sim-init` from the root directory to prepare +## the simulation environment before running this command. +.PHONY: car-vsim-sim-build +car-vsim-sim-build: $(CAR_VSIM_DIR)/compile.carfield_soc.tcl + cd $(CAR_VSIM_DIR); $(QUESTA) vsim -c -do "quit -code [source $<]" + +.PHONY: car-vsim-sim-clean +## Remove all Questasim simulation build artifacts +car-vsim-sim-clean: + rm -rf $(CAR_VSIM_DIR)/uart $(CAR_VSIM_DIR)/FETCH* $(CAR_VSIM_DIR)/logs $(CAR_VSIM_DIR)/*.ini $(CAR_VSIM_DIR)/trace* $(CAR_VSIM_DIR)/*.wlf $(CAR_VSIM_DIR)/transcript $(CAR_VSIM_DIR)/work + +.PHONY: car-vsim-sim-run +## Run simulation of the carfield RTL. +## @param HYP_USER_PRELOAD=0 Whether to preload code in the HyperRAM model. +## @param CHS_BOOTMODE=0 The bootmode of host domain <0 JTAG|1 Serial Link> +## @param CHS_PRELMODE=1 If 1, use the serial link for host domain memory preloading, otherwise JTAG. +## @param CHS_BINARY= ELF to be executed on host domain +## @param CHS_IMAGE= Raw image (ROMs) or GPT disk image to be executed on Cheshire (when CHS_BOOTMODE >= 1) +## @param SECD_BINARY= ELF to be executed on the host domain +## @param SECD_IMAGE= Raw image (ROMs) or GPT disk image to be executed on Cheshire (when CHS_BOOTMODE >= 1) +## @param SECD_BOOTMODE=0 The bootmode of secure domain <0 JTAG|1 Serial Link> +## @param SAFED_BINARY= ELF to be executed on safe domain +## @param SAFED_BOOTMODE=0 The bootmode of safe domain <0 JTAG|1 Serial Link> +## @param PULPD_BINARY= ELF to be executed on integer PMCA +## @param PULPD_BOOTMODE=0 The bootmode of safe domain <0 JTAG|1 Serial Link> +## @param SPATZD_BINARY== ELF to be executed on integer PMCA +## @param SPATZD_BOOTMODE=0 The bootmode of safe domain <0 JTAG|1 Serial Link> +## @param TESTBENCH=tb_carfield_soc_opt The optimised toplevel testbench to use. Defaults to 'tb_carfield_soc_opt'. +## @param VSIM_FLAGS The flags for the vsim invocation +car-vsim-sim-run: + $(eval CHS_BINARY_ABS := $(realpath $(CHS_BINARY))) + $(eval CHS_IMAGE_ABS := $(realpath $(CHS_IMAGE))) + $(eval SECD_BINARY_ABS := $(realpath $(SECD_BINARY))) + $(eval SECD_IMAGE_ABS := $(realpath $(SECD_IMAGE))) + $(eval SAFED_BINARY_ABS := $(realpath $(SAFED_BINARY))) + $(eval PULPD_BINARY_ABS := $(realpath $(PULPD_BINARY))) + $(eval SPATZD_BINARY_ABS := $(realpath $(SPATZD_BINARY))) + cd $(CAR_VSIM_DIR); $(QUESTA) vsim $(VSIM_FLAGS) -do \ + "set HYP_USER_PRELOAD $(HYP_USER_PRELOAD); \ + set SECURE_BOOT $(SECURE_BOOT); \ + set CHS_BOOTMODE $(CHS_BOOTMODE); \ + set CHS_PRELMODE $(CHS_PRELMODE); \ + set CHS_BINARY $(CHS_BINARY_ABS); \ + set CHS_IMAGE $(CHS_IMAGE_ABS); \ + set SECD_BINARY $(SECD_BINARY_ABS); \ + set SECD_BOOTMODE $(SECD_BOOTMODE); \ + set SECD_IMAGE $(SECD_IMAGE_ABS); \ + set SAFED_BINARY $(SAFED_BINARY_ABS); \ + set SAFED_BOOTMODE $(SAFED_BOOTMODE); \ + set PULPD_BINARY $(PULPD_BINARY_ABS); \ + set PULPD_BOOTMODE $(PULPD_BOOTMODE); \ + set SPATZD_BINARY $(SPATZD_BINARY_ABS); \ + set SPATZD_BOOTMODE $(SPATZD_BOOTMODE);\ + set TESTBENCH $(TBENCH); \ + set VSIM_FLAGS \"$(VSIM_FLAGS)\"; \ + source $(CAR_VSIM_DIR)/start.carfield_soc.tcl ; \ + $(RUN_AND_EXIT)" + +####### +# VCS # +####### +## @section VCS simulator target + +CAR_VCS_ALL += $(CAR_SIM_ALL) +# TODO + +########### +# Xcelium # +########### + +## @section Xcelium simulator target + +CAR_XCELIUM_ALL += $(CAR_XCELIUM_ALL) +# TODO + +## @section Global targets +.PHONY: car-sim-init + +## Generate all required VIPs and compilation scripts for all supported simulators +car-sim-init: car-vsim-sim-init diff --git a/tb/carfield_fix.sv b/target/sim/src/carfield_fix.sv similarity index 100% rename from tb/carfield_fix.sv rename to target/sim/src/carfield_fix.sv diff --git a/tb/carfield_tb.sv b/target/sim/src/carfield_tb.sv similarity index 100% rename from tb/carfield_tb.sv rename to target/sim/src/carfield_tb.sv diff --git a/tb/vip_carfield_soc.sv b/target/sim/src/vip_carfield_soc.sv similarity index 99% rename from tb/vip_carfield_soc.sv rename to target/sim/src/vip_carfield_soc.sv index 4d29e4f6..9bbc1344 100644 --- a/tb/vip_carfield_soc.sv +++ b/target/sim/src/vip_carfield_soc.sv @@ -110,7 +110,7 @@ module vip_carfield_soc for (genvar l=0; l +## @section Carfield emulation + # # Makefile variables (user inputs are in capital letters) # +VIVADO ?= vitis-2020.2 vivado + XILINX_PROJECT ?= carfield # XILINX_FLAVOR in {vanilla,bd} see carfield_bd.mk XILINX_FLAVOR ?= bd @@ -68,18 +72,29 @@ $(CAR_XIL_DIR)/out/%.bit: $(xilinx_bit_$(XILINX_FLAVOR)) cp $(patsubst %.bit,%.ltx,$< $@); \ fi -# Build bitstream +## Build bitstream for Carfield +## @param XILINX_PROJECT The name of the Xilinx project +## @param XILINX_FLAVOR= The flavor of the implementation +## @param XILINX_BOARD The target Xilinx board car-xil-all: $(xilinx_bit) -# Program last bitstream +## Program last bitstream for Carfield +## @param VIVADO The Vivado version in use +## @param XILINX_BOARD The target Xilinx board to be programmed +## @param VIVADO_FLAGS Some flags for Vivado, such as batch or gui mode car-xil-program: @echo "Programming board $(XILINX_BOARD) ($(xilinx_part))" $(vivado_env) $(VIVADO) $(VIVADO_FLAGS) -source $(CAR_XIL_DIR)/scripts/program.tcl -# Flash linux image +## Flash Linux image on Cheshire +## @param VIVADO The Vivado version in use +## @param XILINX_BOARD The target Xilinx board to be programmed +## @param XILINX_FLAVOR= The flavor of the implementation. +## @param VIVADO_FLAGS Some flags for Vivado, such as batch or gui mode car-xil-flash: $(CAR_SW_DIR)/boot/linux_carfield_$(XILINX_FLAVOR)_$(XILINX_BOARD).gpt.bin $(vivado_env) FILE=$< OFFSET=0 $(VIVADO) $(VIVADO_FLAGS) -source $(CAR_XIL_DIR)/scripts/flash_spi.tcl +## Clean Xilinx artifacts for all implementations car-xil-clean: car-xil-clean-vanilla car-xil-clean-bd xilinx-ip-clean-all .PHONY: car-xil-program car-xil-flash car-xil-clean car-xil-all diff --git a/scripts/Makefile b/utils/lint/lint.mk similarity index 100% rename from scripts/Makefile rename to utils/lint/lint.mk diff --git a/scripts/spyglass/scripts/run_lint.tcl b/utils/lint/spyglass/scripts/run_lint.tcl similarity index 100% rename from scripts/spyglass/scripts/run_lint.tcl rename to utils/lint/spyglass/scripts/run_lint.tcl diff --git a/scripts/spyglass/sgdc/func.sgdc b/utils/lint/spyglass/sgdc/func.sgdc similarity index 100% rename from scripts/spyglass/sgdc/func.sgdc rename to utils/lint/spyglass/sgdc/func.sgdc From 0edff57a6803f329393d5e337319eb728c6b3602 Mon Sep 17 00:00:00 2001 From: aottaviano Date: Mon, 20 Nov 2023 18:28:25 +0100 Subject: [PATCH 3/5] docs: Add documentation --- .github/workflows/publish-docs.yml | 35 + .gitignore | 3 + README.md | 146 ++-- docs/gs.md | 79 ++ docs/img/arch.svg | 4 + docs/img/clk_rst.svg | 4 + docs/img/isolation.svg | 4 + docs/index.md | 1 + docs/tg/index.md | 23 + docs/tg/integr.md | 73 ++ docs/tg/sim.md | 110 +++ docs/tg/synth.md | 9 + docs/tg/xilinx.md | 321 ++++++++ docs/um/arch.md | 797 ++++++++++++++++++++ docs/um/index.md | 8 + docs/um/sw.md | 224 ++++++ hw/regs/pcr.md | 1126 ++++++++++++++++++++++++++++ mkdocs.yml | 48 ++ requirements.txt | 9 + 19 files changed, 2924 insertions(+), 100 deletions(-) create mode 100644 .github/workflows/publish-docs.yml create mode 100644 docs/gs.md create mode 100644 docs/img/arch.svg create mode 100644 docs/img/clk_rst.svg create mode 100644 docs/img/isolation.svg create mode 120000 docs/index.md create mode 100644 docs/tg/index.md create mode 100644 docs/tg/integr.md create mode 100644 docs/tg/sim.md create mode 100644 docs/tg/synth.md create mode 100644 docs/tg/xilinx.md create mode 100644 docs/um/arch.md create mode 100644 docs/um/index.md create mode 100644 docs/um/sw.md create mode 100644 hw/regs/pcr.md create mode 100644 mkdocs.yml diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml new file mode 100644 index 00000000..7d8f9e11 --- /dev/null +++ b/.github/workflows/publish-docs.yml @@ -0,0 +1,35 @@ +# Copyright 2020 ETH Zurich and University of Bologna. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +# Author: Paul Scheffler + +name: publish-docs + +on: + push: + branches: [ main ] + workflow_dispatch: + +jobs: + + deploy: + runs-on: ubuntu-22.04 + steps: + - + name: Checkout + uses: actions/checkout@v3 + with: + submodules: recursive + - + name: Install Python + uses: actions/setup-python@v2 + with: + python-version: 3.9 + cache: pip + - + name: Install Python requirements + run: pip install -r requirements.txt + - + name: Deploy Documentation + run: mkdocs gh-deploy --force diff --git a/.gitignore b/.gitignore index fa91a155..7433c473 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,9 @@ spatz /working_dir/ /stdout +# Documentation site +site/ + # sw auto-generated sw/tests/bare-metal/safed/*.h sw/tests/bare-metal/pulpd/*.h diff --git a/README.md b/README.md index 2212f3ae..b5235fe8 100644 --- a/README.md +++ b/README.md @@ -1,122 +1,68 @@ # Carfield -This repository hosts the Carfield SoC platform, a mixed-criticality SoC -targeting the automotive domain. It uses -[`Cheshire`](https://github.com/pulp-platform/cheshire) as main host domain. It -is developed as part of the PULP project, a joint effort between ETH Zurich and -the University of Bologna. +Carfield is an open-research heterogeneous platform for safety, resilient and time-predictable systems. Originally conceived as automotive-oriented SoC, the high configurability of the platform makes it tunable to target a broader class of mixed-criticality applications' domains, such as automotive, space or industry. -## Disclaimer +Carfield is developed as part of the PULP project, a joint effort between ETH Zurich and the +University of Bologna. -This project is still considered to be in early development; some parts may not -yet be functional, and existing interfaces and conventions may be broken without -prior notice. We target a formal release in the very near future. +## Motivation -## Dependencies -To handle project dependencies, you can use -[bender](https://github.com/pulp-platform/bender). +The rapid evolution of AI algorithms and the massive amount of sensed data across +application-domains such as Automotive, Space and Cyber-Physical embedded systems (CPSs), call for a +*paradigm shift* in the design of **next generation of mixed-criticality systems (MCSs)**, from +simple micro-controllers towards powerful and heterogeneous edge computers. -## Carfield Initialization -To initialize Carfield, do the following: -* Execute the command: +These must not only deliver outstanding performance and energy efficiency but also ensure steadfast +safety, resilience, and security. - ``` - make car-init - ``` +The Carfield platform aims to tackle these architectural challenges establishing itself as a +pre-competitive heterogeneous platform for MCSs, underpinned by **fully open-source Intellectual +Properties (IPs)**. - It will take care of: +Carfield showcases pioneering hardware solutions, addressing challenges related to time-predictable +on/off-chip communication, robust fault recovery mechanisms, secure boot processes, cryptographic +acceleration services, hardware-assisted virtualization, and accelerated computation for both +floating-point and integer workloads. - 1. Clone all the Carfield dependencies; - 2. Initialize the [Cheshire SoC](https://github.com/pulp-platform/cheshire). This can be - done separately by running `make chs-init` - 3. Downloads the Hyperram models from the iis-gitlab. If you don't have access to it, you - can also download the freely-available Hyperram models from - [here](https://www.cypress.com/documentation/models/verilog/s27kl0641-s27ks0641-verilog) - and unzip them according to the bender. +## Quick Start -* Check that you have a RISCV toolchain for both RV64 and RV32 ISAs. For ETH, type: - ``` - source scripts/env-iis.sh - ``` +* To learn how to build and use Carfield, see [Getting + Started](https://pulp-platform.github.io/carfield/gs/). +* To learn about available simulation, FPGA, and ASIC targets, see + [Targets](https://pulp-platform.github.io/carfield/tg). +* For detailed information on Carfield's inner workings, consult the [User + Manual](https://pulp-platform.github.io/carfield/um/). -## Simulation - -Follow these steps to launch a Carfield simulation: - -### Compile HW and SW - -* Generate the compile scripts for Questasim and compile Carfield. - - ``` - make car-hw-build - ``` - - It is also possible to run `make -B scripts/carfield_compile.tcl` to - re-generate the compile script after hardware modfications. - -* Compile tests for Carfield. Tests resides in `sw/tests`. - - ``` - make car-sw-build - ``` - - The latter commands: - * Compiles safety island and pulp cluster standalone tests - * Compiles CVA6 standalone and offloading tests - -### System bootmodes - -* The current supported bootmodes from Cheshire are: - - | `CHS_BOOTMODE` | `CHS_PRELMODE` | Action | - | --- | --- | --- | - | 0 | 0 | Passive bootmode, JTAG preload | - | 0 | 1 | Passive bootmode, Serial Link preload | - | 0 | 2 | Passive bootmode, UART preload | - | 0 | 3 | Passive bootmode, Secure Boot from SECD | - | 1 | - | Autonomous bootmode, SPI SD card | - | 2 | - | Autonomous bootmode, SPI flash | - | 3 | - | Autonomous bootmode, I2C EEPROM | - - `Bootmode` indicates the available bootmodes in Cheshire, while `Preload mode` indicates the type - of preload, if any is needed. For RTL simulation, bootmodes 0, 2 and 3 are supported. SPI SD card - bootmode is supported on FPGA emulation. - -* The current supported bootmodes for the Safety Island are: - - | `SAFED_BOOTMODE` | Action | - | --- | --- | - | 0 | Passive bootmode, JTAG preload | - | 1 | Passive bootmode, Serial Link preload | - -### Simulation - -To launch an RTL simulation with the selected boot/preload modes for the island of choice, type: - - -* For cheshire in passive bootmode (`CHS_BOOTMODE=0`), set `CHS_BINARY` for Cheshire +If you are impatient and have all needed +[dependencies](https://pulp-platform.github.io/carfield/gs/#dependencies), type: ``` -make car-hw-sim CHS_BOOTMODE= CHS_PRELMODE= CHS_BINARY=.car.elf PULPCL_BINARY= SPATZCL_BINARY= SECD_BINARY= SAFED_BOOTMODE= SAFED_BINARY= +make car-all ``` -* For cheshire in autonomous bootmode (`CHS_BOOTMODE` = {1,2,3}), set `CHS_IMAGE` for Cheshire +and then run a [simulation](https://pulp-platform.github.io/carfield/tg/sim) with Questasim by +typing: +```tcl +make car-vsim-sim-build +make car-vsim-sim-run CHS_BINARY=./sw/tests/bare-metal/hostd/helloworld.car.l2.elf ``` -make car-hw-sim CHS_BOOTMODE= CHS_PRELMODE= CHS_IMAGE=.car.memh PULPCL_BINARY= SPATZCL_BINARY= SECD_BINARY= SAFED_BOOTMODE= SAFED_BINARY= -``` -### Debugging +--- + +To display the main *Make* build targets and their usage, from the root repository type: + +```tcl +make help +``` -Per default, Questasim compilation is performance-optimised and simulation logging is disabled. To enable full visibility, logging, and the Questa GUI, set `DEBUG=1` when executing the steps above. +The Make files are autodocumented. ## License -Unless specified otherwise in the respective file headers, all code checked into -this repository is made available under a permissive license. All hardware -sources and tool scripts are licensed under the Solderpad Hardware License 0.51 -(see `LICENSE`) with the exception of generated register file code (e.g. -`hw/regs/*.sv`), which is generated by a fork of lowRISC's -[`regtool`](https://github.com/lowRISC/opentitan/blob/master/util/regtool.py) -and licensed under Apache 2.0. All software sources are licensed under Apache -2.0. +Unless specified otherwise in the respective file headers, all code checked into this repository is +made available under a permissive license. All hardware sources and tool scripts are licensed under +the Solderpad Hardware License 0.51 (see `LICENSE`) with the exception of generated register file +code (e.g. `hw/regs/*.sv`), which is generated by a fork of lowRISC's +[`regtool`](https://github.com/lowRISC/opentitan/blob/master/util/regtool.py) and licensed under +Apache 2.0. All software sources are licensed under Apache 2.0. diff --git a/docs/gs.md b/docs/gs.md new file mode 100644 index 00000000..d34e93a5 --- /dev/null +++ b/docs/gs.md @@ -0,0 +1,79 @@ +# Getting Started + +We first discuss the Carfield's project structure, its dependencies, and how to build it. + +## Repository structure + +The project is structured as follows: + +| Directory | Description | Documentation | +| --------- | ------------------------------------------ | --------------------- | +| `doc` | Documentation | [Home](index.md) | +| `hw` | Hardware sources as SystemVerilog RTL | [Architecture](um/arch.md) | +| `sw` | Software stack, build setup, and tests | [Software Stack](um/sw.md) | +| `target` | Simulation, FPGA, and ASIC target setups | [Targets](tg/index.md) | +| `utils` | Utility scripts | | +| `scripts` | Some helper scripts for env setup | | + +## Dependencies + +To *build* Carfield, you will need: + +- GNU Make `>= 3.82` +- Python `>= 3.9` +- Bender `>= 0.27.1` +- RISCV GCC `>= 11.2.0` +- Python packages in `requirements.txt` + +We use [Bender](https://github.com/pulp-platform/bender) for hardware IP and dependency management; +for more information on using Bender, please see its documentation. You can install Bender directly +through the Rust package manager Cargo: + +``` +cargo install bender +``` + +Depending on your desired target, additional dependencies may be needed. + +## Building Carfield + +To build different parts of Carfield, the `carfield.mk` run `make` followed by these targets: + +- `car-hw-init`: generated hardware, including IPs and boot ROM +- `car-sim-init`(†): scripts and external models for simulation +- `car-sw-build` (‡): bare-metal software running on the hardware + +† *`car-sim-init` will download externally provided peripheral simulation models, some proprietary +and with non-free license terms, from their publically accessible sources. By running +`car-sim-init`, you accept this.* + +‡ *`car-sw-build` requires RV64 and RV32 toolchains. See the [Software Stack](um/sw.md) for more + details.* + +To run all build targets above (†)(‡): + +``` +make car-init-all +``` + +Running `car-init-all` is *required* at least once to correctly configure IPs we depend on. On +reconfiguring any generated hardware or changing IP versions, `car-init-all` should be rerun. + +The following additional targets are not invoked by the above, but also available: + +- `chs-bootrom-all` - rebuilds Cheshire's boot ROM. This is not done by default as reproducible +builds (as checked by CI) can only be guaranteed for fixed compiler versions. +- `car-nonfree-init` - clones our internal repository with nonfree resources we cannot release, +including our internal CI or technology-specific standard cells, scripts and tools. *This is not +necessary to use Carfield*. + +### Note +Carfield uses [`Cheshire`](https://github.com/pulp-platform/cheshire) as main dependency. Compared +to the other dependencies, Cheshire provides most of the HW/SW infrastructure used by Carfield. All +Cheshire's `make` targets, described in the dedicated documentation, are available in Carfield +through the inclusion of the makefrag `cheshire.mk` in `carfield.mk`. + +## Targets + +A *target* is an end use for Carfield. Each target requires different steps from here; read the page +for your desired target in the following [Targets](tg/index.md) chapter. diff --git a/docs/img/arch.svg b/docs/img/arch.svg new file mode 100644 index 00000000..a1a7ee45 --- /dev/null +++ b/docs/img/arch.svg @@ -0,0 +1,4 @@ + + + +
Partitionable hybrid LLC/SPM
Partitionable...
HyperRAM
controller
HyperRAM...
Host Domain (Cheshire)
Host Domain (Cheshire)
System Bus (64-bit AXI4 matrix)
System Bus (64-bit AXI4 matrix)
DMA
DMA
JTAG Debug
JTAG Debug
System Bus (TLUL)
System Bus (TLUL)
Ibex RV32
Ibex RV...
PLIC
PLIC
Life Cyc.
Life Cyc...
Main SPM
Main SPM
OTP mem.
OTP mem.
Ibex RV32
Ibex RV...
Dual Lockstep
Dual Lockstep
RNG
RNG
AES128
AES128
SHA2
SHA2
OTBN
OTBN
KMAC
KMAC
HMAC
HMAC
Crypto DSAs
Crypto DSAs
CAN x1
CAN x1
ETH x1
ETH x1
Generic
Timers
Generic...
WDT x1
WDT x1
Low-latency TCDM bus
Low-latency TCDM bus
DMA
DMA
SPM interleaved (M banks)
SPM interleaved (M banks)
I$
I$
VRF
VRF
FPU0
FPU0
Integer PMCA
Integer PMCA
PCRs
PCRs
Mailbox
Unit
Mailbox...
PWM
Timers
PWM...
CV32
RT
CV32...
System bus (OBI)
System bus (OBI)
Peripheral bus (Regbus/APB)
Peripheral bus (Regbus/APB)
PCRs
PCRs
Boot
ROM
Boot...
ECC
Mgr
ECC...
Private
DSPM + ECC
Private...
Triple-Core-Lockstep
Triple-Core-Lockstep
CLIC
CLIC
JTAG
Dbg
JTAG...
Dyn. addressing switch
Dyn. addressing switch
Bank group 0
Bank group 0
SPM bank + ECC
SPM bank + ECC
SPM bank + ECC
SPM bank + ECC
Bank group arbiter
Bank group arbiter
Peripheral bus (Regbus/APB)
Peripheral bus (Regbus/APB)
Boot & Host interfaces
Boot & Host interfaces
UART x1
UART x1
QSPIM x1
QSPIM x1
I2CM x1
I2CM x1
USB x1
USB x1
PLIC x1
PLIC x1
CLINT/CLIC (per-core)
CLINT/CLIC (...
Intr. Router
Intr. Router
BootROM
BootROM
Host PCRs
Host PCRs
L1 D$ & I$
L1 D$ & I$
FPU
FPU
MMU
MMU
CVA6RT
RV64GCH
CVA6RT...
Peripheral bus (TLUL)
Peripheral bus (TLUL)
Timers
Timers
OTP ctrl.
OTP ctrl...
UART
UART
Pwr. mgr.
Pwr. mgr.
Clk. mgr.
Clk. mgr.
Rst. mgr.
Rst. mgr.
Key mngr.
Key mng...
DMA
DMA
WDT
WDT
SPIM
SPIM
Alert
Alert
FPU
FPU
MMU
MMU
CVA6RT
RV64GCH
CVA6RT...
Self-inv. cache coher.
Self-inv. cache coh...
Serial Link
Serial Link
Peripheral bus (Regbus/APB)
Peripheral bus (Regbus/APB)
Peripherals
Peripherals
AON
AON
JTAG Dbg
JTAG D...
CV32
RT
CV32...
CV32
RT
CV32...
FPU
FPU
FPU
FPU
FPU
FPU
Gen. Timer
Gen. T...
Private
ISPM + ECC
Private...
BootROM
BootROM
L1 D$ & I$
L1 D$ & I$
Self-inv. cache coher.
Self-inv. cache coh...
Bank group N-1
Bank group N-1
SPM bank + ECC
SPM bank + ECC
SPM bank + ECC
SPM bank + ECC
FPU3
FPU3
IPU
IPU
Snitch
RV32
Snitch...
Spatz RVV coproc.
Spatz RVV...
Snitch
RV32
Snitch...
VRF
VRF
FPU0
FPU0
FPU3
FPU3
IPU
IPU
Snitch
RV32
Snitch...
Spatz RVV coproc.
Spatz RVV...
CV32
#0
CV32...
Tensor
DSA
(RedMulE)
Tensor...
Low-latency TCDM bus
Low-latency TCDM bus
DMA
DMA
SPM interleaved (M banks)
SPM interleaved (M banks)
I$
I$
HMR Mngr.
HMR Mngr.
Peripherals
Peripherals
Vector PMCA
Vector PMCA
Accelerator Domain
Accelerator Domain
Dynamic SPM
Dynamic SPM
Safe domain
Safe domain
Secure domain (OpenTitan)
Secure domain (OpenTitan)
CV32
#1
CV32...
CV32
#11
CV32...
HMR cluster
HMR cluster
Legend
Legend
AXI-REALM Guard & Cfg.
AXI-REALM...
GPIO x32
GPIO x32
AXI-REALM real-time monitoring and regulation unit for managers
AXI-REALM real-time monitoring and regulation unit for managers
Bus protocol adapter
Bus protocol adapter
Text is not SVG - cannot display
\ No newline at end of file diff --git a/docs/img/clk_rst.svg b/docs/img/clk_rst.svg new file mode 100644 index 00000000..4d2f4fbf --- /dev/null +++ b/docs/img/clk_rst.svg @@ -0,0 +1,4 @@ + + + +
WARM RESET (SW-controlled)
WARM RESET (SW-co...
X_ISOLATE
X_ISOLATE
X_DOMAIN_RST
X_DOMAIN_RST
x_rst_n
x_rst_n
RESET
SYNCHRONIZER
DOMAIN X
RESET...
X_ISOLATE_STATUS
X_ISOLATE_STATUS
x_por_rst_n
x_por_rst_n
Domain X
Domain X
RESET
SYNCHRONIZER HOST DOMAIN (CHESHIRE)
RESET...
PCRs
PCRs
host_rst_n
host_rst_n
Clock and reset control (Host)
Clock and reset control (Host)
X_CLK_EN
X_CLK_EN
X_CLK_SEL
X_CLK_SEL
X_CLK_DIV_VALUE
X_CLK_DIV_VALUE
PCRs
PCRs
CLOCK INT. DIV. X
(def. div. 1)
CLOCK INT. DI...
CLK MUX X
CLK MUX X
host_clk_i
host_clk_i
alt_clk_i
alt_clk_i
per_clk_i
per_clk_i
pwr_on_rst_n
pwr_on_rst...
pwr_on_rst_n
pwr_on_rst...
COLD RESET
COLD RESET
Text is not SVG - cannot display
\ No newline at end of file diff --git a/docs/img/isolation.svg b/docs/img/isolation.svg new file mode 100644 index 00000000..50989f6e --- /dev/null +++ b/docs/img/isolation.svg @@ -0,0 +1,4 @@ + + + +
x_rst_n
x_rst_n
x_por_rst_n
x_por_rst_n
Async AXI
Async AXI
Async AXI
Async AXI
CDC
CDC
CDC
CDC
Isolate
Isolate
Isolate
Isolate
AXI
AXI
AXI
AXI
Domain X
Domain X
CDC
CDC
CDC
CDC
AXI
AXI
AXI
AXI
rst
sync
rst...
isolate
isolate
sync
sync
sync
sync
isolated
isolated
&
&
rst
sync
rst...
Host domain
AXI matrix
Host domain...
Domain X
Domain X
Text is not SVG - cannot display
\ No newline at end of file diff --git a/docs/index.md b/docs/index.md new file mode 120000 index 00000000..32d46ee8 --- /dev/null +++ b/docs/index.md @@ -0,0 +1 @@ +../README.md \ No newline at end of file diff --git a/docs/tg/index.md b/docs/tg/index.md new file mode 100644 index 00000000..025d16bd --- /dev/null +++ b/docs/tg/index.md @@ -0,0 +1,23 @@ +# Targets + +A *target* refers to an end use of Carfield. This could be a simulation setup, an FPGA or ASIC +implementation, or the less common integration into other SoCs. + +Target setups can either be *included* in this repository or live in an *external* repository and +use Carfield as a dependency. + +## Included Targets + +Included target setups live in the `target` directory. Each included target has a *documentation +page* in this chapter: + +- [Simulation](sim.md) +- [Synthesis and physical implementation](synth.md) +- [Xilinx FPGAs](xilinx.md) + +## External Targets + +For ASIC implementation target, where an additional wrapper is needed for clock generation blocks, +bidirectional pads or additional circuitry, or the less common integration into larger SoCs, +Carfield may be included either as a Bender dependency or Git submodule. For further information and +best pratices, see [Integration](integr.md). diff --git a/docs/tg/integr.md b/docs/tg/integr.md new file mode 100644 index 00000000..9db36172 --- /dev/null +++ b/docs/tg/integr.md @@ -0,0 +1,73 @@ +# Integration + +Carfield is a complex platform, therefore the case of it being integrated in larger SoCs is rare. A +more common scenario is the use of Carfield in a ASIC wrapper that includes bidirectional pads, +clock generation blocks (PLLs, FLLs...) or other circuitry. + +This page explain how to integrate Carfield to fulfill on of these needs. Since Carfield heavily +relies on Cheshire, for better understanding we suggest to integrate this reading with its +equivalent in the Cheshire's documentation. + +## Using Carfield In Your Project + +As for internal targets, Carfield *must be built* before use in external projects. We aim to +simplify this as much as possible with a portable *make fragment*, `carfield.mk`. + +If you use GNU Make to build your project and Bender to handle dependencies, you can include the +Carfield build system into your own makefile with: + +```make +include $(shell bender path carfield)/carfield.mk +``` + +All of Carfield's build targets are available with the prefix `car-`. + +You can leverage this to ensure your Carfield build is up to date and rebuild hardware and software +whenever necessary. You can change the default value of any build parameter, replace source files to +adapt Carfield, or reuse parts of its build system, such as the software stack or the register and +ROM generators. + +## Instantiating Carfield + +A minimal clean instantiation would look as follows: + +```systemverilog +`include "cheshire/typedef.svh" + +// Define function to derive configuration from defaults. +// This could also (preferrably) be done in a system package. +function automatic cheshire_pkg::cheshire_cfg_t gen_cheshire_cfg(); + cheshire_pkg::cheshire_cfg_t ret = cheshire_pkg::DefaultCfg; + // Make overriding changes. Here, we add two AXI manager ports + ret.AxiExtNumMst = 2; + return ret; +endfunction + +localparam cheshire_cfg_t CheshireCfg = gen_cheshire_cfg(); + +// Generate interface types prefixed by `csh_` from our configuration. +`CHESHIRE_TYPEDEF_ALL(csh_, CheshireCfg) + +// Instantiate Cheshire with our configuration and interface types. + carfield #( + .Cfg ( DutCfg ), + .HypNumPhys ( NumPhys ), + .HypNumChips ( NumChips ), + .reg_req_t ( reg_req_t ), + .reg_rsp_t ( reg_rsp_t ) + ) dut ( + // ... IOs here ... + ); +``` + +## Verifying Carfield In-System + +To simplify the simulation and verification of Carfield in other systems or top-level wrappers +(e.g., ASIC), we provide a monolithic block of verification IPs called `carfield_vip`. This is used +along with the `X_vip` modules provided for other domains. Their description can be found in the +dedicated domain's documentation. In particular, `carfield_vip` currently includes: + +* Preloadable Cypress HyperRAM models (used to simulate boot). + +Additionally, we provide a module `carfield_vip_tristate` which adapts the unidirectional IO of this +module to bidirectional IOs which may be interfaced with pads where necessary. diff --git a/docs/tg/sim.md b/docs/tg/sim.md new file mode 100644 index 00000000..2528fa45 --- /dev/null +++ b/docs/tg/sim.md @@ -0,0 +1,110 @@ +# Simulation + +This page describes how to simulate Carfield to execute baremetal programs. Please first read +[Getting Started](../gs.md) to make sure you have all the dependencies and initialized your +repository. + +We currently provide working setups for: + +- Questa Advanced Simulator (QuestaSim) `>= 2022.3` + +We plan on supporting more simulators in the future. If your situation requires it, simulating +Carfield on other setups should be straightforward. + +## Testbench + +Carfield comprises several bootable domains, that are described in the +[Architecture](../um/arch.md#domains) section. + +Each of these domains can be independently booted by keeping the rest of the SoC asleep through the +domain JTAG, or Cheshire's JTAG and Serial Link, which have access to the whole platform except for +the *secure domain*. + +Alternatively, some domains can offload baremetal programs to other domains at runtime. This is +common pratice when offloading programs to the *accelerator domain* from the *host* or *safe +domains*. + +Note that while runtime offloading can be exploited by RTL simulation with reasonably-sized +programs, we suggest to follow the [FPGA mapping](xilinx.md) steps and use [OpenMP-based +offload](../um/sw.md) with heterogeneous cross-compilation. + +--- + +We provide a single SystemVerilog testbench for `carfield_soc` that handles standalone execution of +baremetal programs for each domain. The code for domain `X` is preloaded through simulated interface +drivers. In addition, some domains can read from external memory models from their boot ROM and then jump to +execution. + +As for Cheshire, Carfield testbench employs physical interfaces (JTAG or Serial Link) for memory +preload by default. This could increase the memory preload time (independently from the target +memory: dynamic SPM, LLC-SPM, or DRAM), significantly based on the ELF size. + +Since by default all domains are clock gated and isolated after POR except for the *host domain* +(Cheshire), as described in [Architecture](../um/arch.md), the testbench handles the wake-up +process. + +To speed up the process, the external DRAM can be initialized in simulation (namely, at time `0ns`) +for domain `X` through the make variable `HYP_USER_PRELOAD`. Carfield [SW Stack](../um/sw.md) +provides automatic generation of the required `*.slm` files, targeting an HyperRAM configured with +two physical chips. Note, this flow is **not** recommended during ASIC development cycle as it may +hide bugs in the physical interfaces. + +### Passive boot + +| `X` | `X_BOOTMODE` | `X_PRELMODE` | Action | +| ----------------------------------------- | ---------- | ---------- | --------------------------- | +| `CHS`, `SAFED`, `SECD`, `PULPD`, `SPATZD` | 0 | 0 | Preload through JTAG | +| `CHS`, `SAFED`, `SECD`, `PULPD`, `SPATZD` | 0 | 1 | Preload through serial link | + +Preloading boot modes expect an ELF executable to be passed through `X_BINARY`. + +### Autonomous boot + +| `X` | `CHS_BOOTMODE` | `CHS_PRELMODE` | Action | +| ------------- | -------------- | -------------- | ----------------------------------------------------- | +| `CHS` | 0 | 2 | Preload through UART | +| `CHS` | 1-3 | - | Autonomous boot, see [Boot ROM](../um/sw.md#boot-rom) | + +Autonomous boot modes expect a disk image (GPT formatted or raw code) to be passed through +`X_IMAGE`. For more information on how to build software for Carfield and the details on the boot +process of each domain, see [Software Stack](../um/sw.md). + +For simulation of Carfield in other designs, or in ASIC wrappers that reside in other repositories, +we provide the module `carfield_vip` encapsulating all verification IPs and their interfaces. + +## QuestaSim + +After building Carfield, the design can be compiled and simulated with QuestaSim. Below, we provide +an example with `Serial Link` passive preload of a baremetal program `helloworld.car.l2.elf` to be +executed on the *host domain* (Cheshire, i.e., `X=CHS`): + +```tcl +# Initialize Carfield +make car-init-all + +# Compile the design +make car-vsim-sim-build + +# Preload `helloworld.car.l2.elf` in passive bootmode through serial link, then start the simulation +make car-vsim-sim-run CHS_BOOTMODE=0 CHS_PRELMODE=1 CHS_BINARY=./sw/tests/bare-metal/hostd/helloworld.car.l2.elf +``` + +The design needs to be recompiled only when hardware is changed. + +To clean simulation builds, from the `vsim` folder run + +```tcl +make car-vsim-sim-clean +``` + +To display general help for each *Make* target, type + +```tcl +make help +``` + +### Debugging + +Per default, Questasim compilation is performance-optimised, and GUI and simulation logging are +disabled. To enable full visibility, logging, and the Questa GUI, set `DEBUG=1` when launching the +simulation. diff --git a/docs/tg/synth.md b/docs/tg/synth.md new file mode 100644 index 00000000..1668dee3 --- /dev/null +++ b/docs/tg/synth.md @@ -0,0 +1,9 @@ +# Logic synthesis and physical implementation + +Currently, synthesis of Carfield is available with closed source tools, and hence its scripts are +added in the `nonfree` repository mentioned in the [Getting Started](../gs.md) section. + +Once open-EDA and open-PDK flow is available, it will be updated in this page. + +For independent synthesis of carfield by external users, we provide a wrapper under +`target/synth/carfield_synth_wrap.sv`. diff --git a/docs/tg/xilinx.md b/docs/tg/xilinx.md new file mode 100644 index 00000000..43ce371b --- /dev/null +++ b/docs/tg/xilinx.md @@ -0,0 +1,321 @@ +# Xilinx FGPAs + +This page describes how to map Carfield on Xilinx FPGAs to *execute baremetal programs* or *boot +CVA6 Linux*. Please first read [Getting Started](../gs.md) to make sure have all dependencies. +Additionally, for on-chip debugging you need: + +- OpenOCD `>= 0.10.0` + +We currently provide working setups for: + +- Xilinx VCU128 with Vivado `>= 2020.2` + +We are working on support for more boards in the future. + +The Carfield bitstreams are divided in two flavors at the moment. The `flavor_vanilla` and the +`flavor_bd`. + +- `flavor_vanilla` - The hardware to be mapped on the FPGA is fully described in System Verilog. +This flow is lightweight, easily reproducible, and self contained. As each IP is integrated by hand +in the RTL, only the Xilinx DDR, Xilinx VIO and Xilinx clock wizard are available (at the moment). + +- `flavor_bd` - In order to allow for more complex top level, this flow relies on the Vivado block +design flow to link Carfield with external IPs. This flow is less human readable but allows +integrating more complex IPs as Xilinx Ethernet. *Note that this may require you to own the +respective licenses.* + +## Building the vanilla bistream + +Due to the structure of the Makefile flow. All the following commands are to be executed at the root +of the Carfield repository. If you want to see the Makefiles that you will be using, you can find +the generic FPGA rules in `target/xilinx/xilinx.mk` and the vanilla specific rules in +`target/xilinx/flavor_vanilla/flavor_vanilla.mk`. + +First, make sure that you have fetch and generated all the RTL: + +```bash +make car-init +``` + +Generate the bitstream in `target/xilinx/out/` by running: + +```bash +make car-xil-all XILINX_FLAVOR=vanilla [VIVADO=version] +[VIVADO_MODE={batch,gui}] [XILINX_BOARD={vcu128}] [NO_HYPERBUS={0,1}] +[GEN_EXT_JTAG={0,1}] [GEN_PULP_CLUSTER={0,1}] [GEN_SAFETY_ISLAND={0,1}] +[GEN_SPATZ_CLUSTER={0,1}] [GEN_OPEN_TITAN={0,1}] +``` + +See the argument list below: + +| Argument | Relevance | Description | +|----------------|-----------|---------------------------------------------------------------------------------------------------------------------------------------| +| VIVADO | all | Vivado command to use | +| XILINX_BOARD | all | `vcu128` | +| NO_HYPERBUS | all | `0` Use the hyperram controller inside `carfield.sv`
`1` Use the Xilinx DDR controller | +| GEN_EXT_JTAG | vcu128 | `0` Connect the JTAG debugger to the board's JTAG (see [vcu128](#xilinx-vcu128))
`1` Connect the JTAG debugger to an external JTAG chain | +| GEN_*[IP]* | all | `0` Replace the IP with an AXI error slave
`1` Instanciate the IP | +| VIVADO_MODE | all | `batch` Compile in Vivado shell
`gui` Compile in Vivado gui | + +See below some typical building time for reference: + +| IPs | Board | Duration | +|-------------------|--------|------------| +| PULP | vcu128 | xxhxxmin | +| SAFETY | vcu128 | xxhxxmin | +| SPATZ | vcu128 | xxhxxmin | +| PULP + SAFETY | vcu128 | xxhxxmin | + +You can find which sources are used by looking at `Bender.yml` (target `all(xilinx, fpga, +xilinx_vanilla)`). This file is used by bender to generate +`target/xilinx/flavor_vanilla/scripts/add_sources.tcl`. You can open this file to see all the file +list of the project. (Note that even if you disable an IP, its files will still needed by Vivado and +added to the `add_sources.tcl`). + +Note that the `make` command above will first compile the Xilinx ips located in +`target/xilinx/xilinx_ips` before compiling the bitstream. + +## Building the bd (block design) bistream + +Please read and try to compile a vanilla bitstream first to identify potential issues. + +You can find the bd specific rules in `target/xilinx/flavor_vanilla/flavor_bd.mk`. + +Again, make sure that you have fetched and generated all the RTL: + +```bash +make car-init +``` + +Generate the bitstream in `target/xilinx/out/` by running: + +```bash +make car-xil-all XILINX_FLAVOR=bd [VIVADO=version] [VIVADO_MODE={batch,gui}] +[XILINX_BOARD={vcu128}] [NO_HYPERBUS={0,1}] [GEN_EXT_JTAG={0,1}] +[GEN_PULP_CLUSTER={0,1}] [GEN_SAFETY_ISLAND={0,1}] [GEN_SPATZ_CLUSTER={0,1}] +[GEN_OPEN_TITAN={0,1}] +``` + +See the argument list below: + +| Argument | Relevance | Description | +|----------------|-----------|---------------------------------------------------------------------------------------------------------------------------------------| +| VIVADO | all | Vivado command to use | +| XILINX_BOARD | all | `vcu128` | +| NO_HYPERBUS | all | `0` Use the hyperram controller inside `carfield.sv`
`1` Use the Xilinx DDR controller | +| GEN_EXT_JTAG | vcu128 | `0` Connect the JTAG debugger to the board's JTAG (see [vcu128](#xilinx-vcu128))
`1` Connect the JTAG debugger to an external JTAG chain | +| GEN_*[IP]* | all | `0` Replace the IP with an AXI error slave
`1` Instanciate the IP | +| VIVADO_MODE | all | `batch` Compile in Vivado shell
`gui` Compile in Vivado gui | + +See below some typical building time for reference: + +| IPs | Board | Duration | +|-------------------|--------|------------| +| PULP | vcu128 | xxhxxmin | +| SAFETY | vcu128 | xxhxxmin | +| SPATZ | vcu128 | xxhxxmin | +| PULP + SAFETY | vcu128 | xxhxxmin | + +You can find which sources are used by looking at `Bender.yml` (target `all(xilinx, fpga, +xilinx_bd)`). This file is used by bender to generate +`target/xilinx/flavor_bd/scripts/add_sources.tcl`. You can open this file to see all the file list +of the project. (Note that even if you disable an IP, its files will still needed by Vivado and +added to the `add_sources.tcl`). + +Note that the `make` command above will first package a Carfield ip before compiling the bitstream. + +## Board specificities + +### Xilinx VCU128 +> #### Bootmodes and VIOs +> +> As there are no switches on this board, the CVA6 bootmode (see [Cheshire +bootrom](https://pulp-platform.github.io/cheshire/um/sw/#boot-rom)) is selected by Xilinx VIOs that +can be set in the Vivado GUI (see [Using Vivado GUI](#bringup_vivado_gui)). +> +> #### External JTAG chain +> +> The VCU128 development board only provides one JTAG chain, used by Vivado to program the +bitstream, and interact with certain Xilinx IPs (ILAs, VIOs, ...). The RV64 requires access to a +JTAG chain to connect GDB to the debug-module in the bitstream. + +> When using `EXT_JTAG=0` it is possible to connect the debug module to the internal FPGA's JTAG by +using the Xilinx BSCANE macro. With this, you will only need the normal Xilinx USB cable to interact +with CVA6. Note that it means that +Vivado and OpenOCD can not use the same cable at the same time. +>**WARNING: this setup (with `EXT_JTAG=0`) will only work for designs containing the host only** as +it is not possible to chain multiple devices on the BSCANE macro. If you need to use `EXT_JTAG=0` +consider modifying the RTL to remove the debug modules of the IPs. + +> When using `EXT_JTAG=1` we add an external JTAG chain for the RV64 host and other island through +the FPGA's GPIOs. Since the VCU128 does not have GPIOs we use we use a Digilent JTAG-HS2 cable +connected to the Xilinx XM105 FMC debug card. See the connections in `vcu128.xdc`. + +## Bare-metal bringup + +### Programming the FPGA + +#### Using Vivado GUI + +If you have closed Vivado, or compiled in batch mode, you can open the Vivado GUI: + +```bash +# Find your project +find . -name "*.xpr" +# Open it in gui +vitis-2020.2 vivado project.xpr +``` + +You can now open the Hardware Manager and program the FPGA. Once done, Vivado will give you access +the to Virtual Inputs Outputs (VIOs). You can now assert the following signals (on Cheshire top +level). + + | VIO | Function | + | ----------------- | ----------------------------------------------------------------| + | vio_reset | Positive edge-sensitive reset for the whole system | + | vio_boot_mode | Override the boot-mode switches described above | + | vio_boot_mode_sel | Select between 0: using boot mode switches 1: use boot mode VIO | + +#### Using command line + +A script `program.tcl` is available to flash the bitstream without opening Vivado GUI. You will need +to give the following variable to access your board (see `target/xilinx/xilinx.mk`). + +- `XILINX_PORT` - Vivado opened port (default **3121**) +- `FPGA_PATH` - Vivado path to your FPGA (default **xilinx_tcf/Xilinx/[serial_id]**) +- `XILINX_HOST` - Path to your Vivado server (default **localhost**) + +Change the values to the appropriate ones (they be found in the Hardware Manager in Vivado GUI) and +program the board: + +```bash +make chs-xil-program VIVADO_MODE=batch XILINX_BOARD=vcu128 XILINX_FLAVOR=flavor +``` + +### Loading binary and debugging with OpenOCD + +Tbd + +## Running Baremetal Code + +Tbd + +### JTAG Preloading + +Tbd + +## Booting Linux + +To boot Linux, we must load the *OpenSBI* firmware, which takes over M mode and launches the U-boot +bootloader. U-boot then loads Linux. For more details, see [Boot Flow](../um/sw.md#boot-flow). + +Clone the `carfield` branch of CVA6 SDK at the root of this repository and build the firmware +(OpenSBI + U-boot) and Linux images (*this will take about 30 minutes*): + +```bash +git clone https://github.com/pulp-platform/cva6-sdk.git --branch carfield +make -C cva6-sdk images +``` + +In principle, we can boot Linux through JTAG by loading all images into memory, launching OpenSBI, +and instructing U-boot to load the kernel directly from memory. Here, we focus on autonomous boot +from SD card or SPI flash. + +In this case, OpenSBI is loaded by a regular baremetal program called the Zero-Stage Loader (ZSL). +The boot ROM loads the ZSL from SD card, which then loads the device tree and firmware from other SD +card partitions into memory and launches OpenSBI. + +To create a full Linux disk image from the ZSL, device tree, firmware, and Linux, run: + +```bash +# Place the cva6-sdk where they are expected: +ln -s cva6-sdk/install64 sw/boot/install64 +# Optional: Pre-uild explicitely the image +make CAR_ROOT=. sw/boot/linux_carfield_bd_vcu128.gpt.bin +``` + +You can now recompile the board, it should start booting automatically! + +### Xilinx VCU128 +> +> This board does not offer a SD card reader. We need to load the image in the +integrated flash: +> +> ``` +> make chs-xil-flash VIVADO_MODE=batch XILINX_BOARD=vcu128 XILINX_FLAVOR=flavor +> ``` +> +> Use the parameters defined in [Using command line](#bringup_vivado_cli) +(defaults are in `target/xilinx/xilinx.mk`) to select your board: +> +> This script will erase your bitstream, once the flash has been written (c.a. +10min) you will need to re-program the bitstream on the board. + +## Add your own board + +If you wish to add a flow for a new FPGA board, please do the following steps: +_Please consider opening a pull request containing the necessary changes to integrate your new board +(:_ + +### Makefile + +Add your board on top of `target/xilinx/xilinx.mk`, in particular `xilinx_part` and +`xilinx_board_long` are identifying the FPGA chip and board (can be found in VIvado GUI). The +parameters identifying your personal device `XILINX_PORT`, `XILINX_FPGA_PATH`, `XILINX_HOST` can be +left empty for now. + +### Vanilla flow +> +> #### Re-arametrize existing IPs +> +> Carfield's emulation requires a few Vivado IPs to work properly. They are +defined and pre-compiled in `target/xilinx/xilinx_ips/*`. +> If you add a new board, you will need to reconfigure your IPs for this board. For instance, to use +the _Vivado MIG DDR4 controller_, modify `target/xilinx/xilinx_ips/xlnx_mig_ddr4/run.tcl`. There, +add the relevant +`$::env(XILINX_BOARD)` entry with your configuration. +> To know which configuration to use your board, you can open a blank project in Vivado GUI, create +a blank block design, and instanciate the MIG DDR4 IP there. The Vivado TCL console should write the +default parameters for your FPGA. You can later re-configure the IP in the block design and Vivado +will print to the tcl console the modified parameters. Then you can copy these tcl lines to the +`run.tcl` file. Make sure that you added your ip to `target/xilinx/flavor_vanilla/flavor_vanilla.mk` +under "xilinx_ips_names_vanilla_**your_board**". +> +> #### Add a new IP +> +> If your board require a new IP that has not been integrated already do the +following : +> +> - Add a new folder `target/xilinx/xilinx_ips/[your_ip]` taking the example of the `xlnx_mig_ddr4`. +> - Modify `target/xilinx/xilinx_ips/[your_ip]/tcl/run.tcl` and +`target/xilinx/xilinx_ips/[your_ip]/Makefile` accordingly. > - Add your IP to +`target/flavor_vanilla/flavor_vanilla.mk` under "xilinx_ips_names_vanilla_**your_board**". +> +> #### Instantiate your IP +> +> Connect it's top module in the top-level: +`target/xilinx/flavor_vanilla/src/cheshire_top_xilinx.sv`. If your IP is a DDR controller, please +add it to `target/xilinx/src/dram_wrapper_xilinx.sv`. Note that this file contains a pipeline to +resize AXI transactions from Cheshire to your controller. +> +> Add the relevant macro parameters to `target/xilinx/flavor_vanilla/src/phy_definitions.sv` in +order to disable your IP for non-relevant boards. +> +> #### Add a new device tree +> +> Each board is defined by a device-tree, when adding a new board, please add a device tree in +`sw/boot` for each supported flavors. +> +> #### Debug +> +> It is possible to use ILA (Integrated Logic Analyzers) in order to debug some signals on the +running FPGA. Add the following before declaring your signals: +> +```verilog +// Indicate that you need to debug a signal +(* dont_touch = "yes" *) (* mark_debug = "true" *) logic signal_d0; +// You can also use the following macro from phy_definitions.svh +`ila(ila_signal_d0, signal_d0) +``` +> +> Then, re-build your bitstream. diff --git a/docs/um/arch.md b/docs/um/arch.md new file mode 100644 index 00000000..4e46ed2c --- /dev/null +++ b/docs/um/arch.md @@ -0,0 +1,797 @@ +# Architecture + +![Carfield Block Diagram](../img/arch.svg) + +Carfield is organized in *domains*. As a mixed-criticality system (MCS), each domain serves +different purposes in terms of functional safety and reliability, security, and computation +capabilities. + +Carfield relies on Cheshire as its host domain, and extends its minimal SoC with additional +interconnect ports and interrupts. + +The above block diagram depicts a fully-featured Carfield SoC, which currently provides: + +- **Domains**: + - *Host domain* (Cheshire), a Linux-capable RV64 system based on dual-core CVA6 processors with + self-invalidation coherency mechanism + - *Safe domain*, a Triple-Core-Lockstep (TCLS) RV32 microcontroller system based on CV32E40P, + with fast interrupt handling through the RISC-V CLIC + - *Secure domain*, a Dual-Core-Lockstep (DCLS) RV32 Hardware Root of Trust (HW RoT) systems that + ensures the secure boot for the whole platform, serves as secure monitor for the entire + system, and provides crypto acceleration services through various crypto-accelerators + - *Accelerator domain*, comprises two programmable multi-core accelerators (PMCAs), an 12-cores + integer cluster with Hybrid Modular Redundancy (HMR) capabilities oriented to compute + intensive integer workloads such as AI, and a vectorial cluster with floating point vector + processing capabilities to accelerate intensive control tasks + +- **On-chip and off-chip memory endpoints**: + - *Dynamic SPM*: dynamically configurable scratchpad memory (SPM) for *interleaved* or + *contiguous* accesses aiming at reducing systematic bus conflicts to improve the + time-predictability of the on-chip communication + - *Partitionable hybrid LLC SPM*: the last-level cache (*host domain*) can be configured as SPM + at runtime, as described in Cheshire's + [Architecture](https://pulp-platform.github.io/cheshire/um/arch/) + - *External DRAM*: off-chip HyperRAM (Infineon) interfaced with in-house, open-source AXI4 + Hyberbus memory controller and digital PHY connected to Cheshire's LLC + +- **Mailbox unit** + - Main communication vehicle among domains, based on an interrupt notification mechanism + +- **Platform control registers (PCRs)** + - Management and control registers for the entire platform, control clock sources assignments, + clock gating, isolation. + +- **Interconnect** (as in Cheshire): + - A last level cache (LLC) configurable as a scratchpad memory (SPM) per-way + - Up to 16 external AXI4 manager ports and 16 AXI and Regbus subordinate ports + - Per-manager AXI4 traffic regulators for real-time applications + - Per-manager AXI4 bus error units (UNBENT) for interconnect error handling + +- **Interrupts** (as in Cheshire): + - Core-local (CLINT *and* CLIC) and platform (PLIC) interrupt controllers + - Dynamic interrupt routing from and to internal and external targets. + +- **Peripherals**: + - Generic timers + - PWM timers + - Watchdog timer + - Ethernet + - CAN + +## Memory Map + +This section shows Carfield's memory map. The group `Internal to Cheshire` in the table below only +recalls the memory map described in the dedicatd [documentation for +Cheshire](https://pulp-platform.github.io/cheshire/um/arch/) and is explicitely shown here for +clarity. + +| **Start Address** | **End Address (excl.)** | **Length** | **Size** | **Permissions** | **Cacheable** | **Atomics** | **Region** | **Device** | +|--------------------------|-------------------------|------------------|----------|-----------------|---------------|-------------|--------------|----------------------------------------------------------------------| +| **Internal to Cheshire** | | | | | | | | | +| `0x0000_0000` | `0x0004_0000` | `0x04_0000` | 256 KiB | (debug) | | | Debug | Debug CVA6 | +| `0x0004_0000` | `0x0100_0000` | | | | | | *Reserved* | | +| `0x0100_0000` | `0x0100_1000` | `0x00_1000` | 4 KiB | rw | | | Config | AXI DMA Config | +| `0x0100_1000` | `0x0200_0000` | | | | | | *Reserved* | | +| `0x0200_0000` | `0x0204_0000` | `0x04_0000` | 256 KiB | rx | | | Memory | Boot ROM | +| `0x0204_0000` | `0x0208_0000` | `0x04_0000` | 256 KiB | rw | | | Irq | CLINT | +| `0x0208_0000` | `0x020c_0000` | `0x04_0000` | 256 KiB | rw | | | Irq | IRQ Routing | +| `0x020c_0000` | `0x0210_0000` | `0x04_0000` | 256 KiB | rw | | | Irq | AXI-REALM unit | +| `0x020c_0000` | `0x0300_0000` | | | | | | *Reserved* | | +| `0x0300_0000` | `0x0300_1000` | `0x00_1000` | 4 KiB | rw | | | Config | Cheshire PCRs | +| `0x0300_1000` | `0x0300_2000` | `0x00_1000` | 4 KiB | rw | | | Config | LLC | +| `0x0300_2000` | `0x0300_3000` | `0x00_1000` | 4 KiB | rw | | | I/O | [UART](https://opentitan.org/book/hw/ip/uart/doc/registers.html) | +| `0x0300_3000` | `0x0300_4000` | `0x00_1000` | 4 KiB | rw | | | I/O | [I2C](https://opentitan.org/book/hw/ip/i2c/doc/registers.html) | +| `0x0300_4000` | `0x0300_5000` | `0x00_1000` | 4 KiB | rw | | | I/O | [SPIM](https://opentitan.org/book/hw/ip/spi_host/doc/registers.html) | +| `0x0300_5000` | `0x0300_6000` | `0x00_1000` | 4 KiB | rw | | | I/O | [GPIO](https://opentitan.org/book/hw/ip/gpio/doc/registers.html) | +| `0x0300_6000` | `0x0300_7000` | `0x00_1000` | 4 KiB | rw | | | Config | Serial Link | +| `0x0300_7000` | `0x0300_8000` | `0x00_1000` | 4 KiB | rw | | | Config | VGA | +| `0x0300_8000` | `0x0300_A000` | `0x00_1000` | 8 KiB | rw | | | Config | UNBENT (bus error unit) | +| `0x0300_A000` | `0x0300_B000` | `0x00_1000` | 4 KiB | rw | | | Config | Tagger (LLC partitioning) | +| `0x0300_8000` | `0x0400_0000` | | | | | | *Reserved* | | +| `0x0400_0000` | `0x1000_0000` | `0x40_0000` | 64 MiB | rw | | | Irq | PLIC | +| `0x0800_0000` | `0x0C00_0000` | `0x40_0000` | 64 MiB | rw | | | Irq | CLICs | +| `0x1000_0000` | `0x1400_0000` | `0x40_0000` | 64 MiB | rwx | yes | yes | Memory | LLC Scratchpad | +| `0x1400_0000` | `0x1800_0000` | `0x40_0000` | 64 MiB | rwx | | yes | Memory | LLC Scratchpad | +| `0x1800_0000` | `0x2000_0000` | | | | | | *Reserved* | | +| **External to Cheshire** | | | | rw | | | | | +| `0x2000_0000` | `0x2000_1000` | `0x00_1000` | 4 KiB | rw | | | I/O | Ethernet | +| `0x2000_1000` | `0x2000_2000` | `0x00_1000` | 4 KiB | rw | | | I/O | CAN BUS | +| `0x2000_2000` | `0x2000_3000` | `0x00_1000` | 4 KiB | rw | | | I/O | (empty) | +| `0x2000_3000` | `0x2000_4000` | `0x00_1000` | 4 KiB | rw | | | I/O | (empty) | +| `0x2000_4000` | `0x2000_5000` | `0x00_1000` | 4 KiB | rw | | | I/O | GP timer 1 (System timer) | +| `0x2000_5000` | `0x2000_6000` | `0x00_1000` | 4 KiB | rw | | | I/O | GP timer 2 (Advanced timer) | +| `0x2000_6000` | `0x2000_7000` | `0x00_1000` | 4 KiB | rw | | | I/O | GP timer 3 | +| `0x2000_7000` | `0x2000_8000` | `0x00_1000` | 4 KiB | rw | | | I/O | Watchdog timer | +| `0x2000_8000` | `0x2000_9000` | `0x00_1000` | 4 KiB | rw | | | I/O | (empty) | +| `0x2000_9000` | `0x2000_a000` | `0x00_1000` | 4 KiB | rw | | | I/O | HyperBUS | +| `0x2000_a000` | `0x2000_b000` | `0x00_1000` | 4 KiB | rw | | | I/O | Pad Config | +| `0x2000_b000` | `0x2000_c000` | `0x00_1000` | 4 KiB | rw | | | I/O | L2 ECC Config | +| `0x2001_0000` | `0x2001_1000` | `0x00_1000` | 4 KiB | rw | | | I/O | Carfield Control and Status | +| `0x2002_0000` | `0x2002_1000` | `0x00_1000` | 4 KiB | rw | | | I/O | (if any) PLL/CLOCK | +| `0x2800_1000` | `0x4000_0000` | | | | | | *Reserved* | | +| `0x4000_0000` | `0x4000_1000` | `0x00_1000` | 4 KiB | rw | | | Irq | Mailboxes | +| `0x4000_1000` | `0x5000_0000` | | | | | | *Reserved* | | +| `0x5000_0000` | `0x5080_0000` | `0x80_0000` | 8 MiB | rw | | | Accelerators | Integer Cluster | +| `0x5080_0000` | `0x5100_0000` | | | | | | *Reserved* | | +| `0x5100_0000` | `0x5180_0000` | `0x80_0000` | 8 MiB | rw | | | Accelerators | FP Cluster | +| `0x5100_0000` | `0x6000_0000` | | | | | | *Reserved* | | +| `0x6000_0000` | `0x6002_0000` | `0x02_0000` | 128 KiB | rw | | yes | Safe domain | Safety Island Memory | +| `0x6002_0000` | `0x6020_0000` | `0x1e_0000` | | rw | | | Safe domain | reserved | +| `0x6020_0000` | `0x6030_0000` | `0x10_0000` | 1 MiB | rw | | yes | Safe domain | Safety Island Peripherals | +| `0x6030_0000` | `0x6080_0000` | `0x50_0000` | | rw | | | Safe domain | reserved | +| `0x6080_0000` | `0x7000_0000` | | | | | | *Reserved* | | +| `0x7000_0000` | `0x7002_0000` | `0x02_0000` | 128 KiB | rwx | yes | yes | Memory | LLC Scratchpad | +| `0x7800_0000` | `0x7810_0000` | `0x10_0000` | 1 MiB | rwx | yes | yes | Memory | L2 Scratchpad (Port 1, interleaved) | +| `0x7810_0000` | `0x7820_0000` | `0x10_0000` | 1 MiB | rwx | yes | yes | Memory | L2 Scratchpad (Port 1, non-interleaved) | +| `0x7820_0000` | `0x7830_0000` | `0x10_0000` | 1 MiB | rwx | yes | yes | Memory | L2 Scratchpad (Port 2, interleaved) | +| `0x7830_0000` | `0x7840_0000` | `0x10_0000` | 1 MiB | rwx | yes | yes | Memory | L2 Scratchpad (Port 2, non-interleaved) | +| `0x8000_0000` | `0x20_8000_0000` | `0x20_0000_0000` | 128 GiB | rwx | yes | yes | Memory | LLC/DRAM | + +## Interrupt map + +Carfield's interrupt components are exhaustivly described in +the dedicated section of the [documentation for +Cheshire](https://pulp-platform.github.io/cheshire/um/arch/). This section describes Carfield's interrupt map. + +| **Interrupt Source** | **Interrupt sink** | **Bitwidth** | **Connection** | **Type** | **Comment** | +|-----------------------------|---------------------|--------------|---------------------------------------------------------------|-----------------|---------------------------| +| **Carfield peripherals** | | | | | | +| `intr_wkup_timer_expired_o` | | 1 | `car_wdt_intrs[0] ` | level-sensitive | | +| `intr_wdog_timer_bark_o ` | | 1 | `car_wdt_intrs[1] ` | level-sensitive | | +| `nmi_wdog_timer_bark_o ` | | 1 | `car_wdt_intrs[2] ` | level-sensitive | | +| `wkup_req_o ` | | 1 | `car_wdt_intrs[3] ` | level-sensitive | | +| `aon_timer_rst_req_o ` | | 1 | `car_wdt_intrs[4] ` | level-sensitive | | +| `irq ` | | 1 | `car_can_intr ` | level-sensitive | | +| `ch_0_o[0] ` | | 1 | `car_adv_timer_ch0 ` | edge-sensitive | | +| `ch_0_o[1] ` | | 1 | `car_adv_timer_ch1 ` | edge-sensitive | | +| `ch_0_o[2] ` | | 1 | `car_adv_timer_ch2 ` | edge-sensitive | | +| `ch_0_o[3] ` | | 1 | `car_adv_timer_ch3 ` | edge-sensitive | | +| `events_o[0] ` | | 1 | `car_adv_timer_events[0]` | edge-sensitive | | +| `events_o[1] ` | | 1 | `car_adv_timer_events[1]` | edge-sensitive | | +| `events_o[2] ` | | 1 | `car_adv_timer_events[2]` | edge-sensitive | | +| `events_o[3] ` | | 1 | `car_adv_timer_events[3]` | edge-sensitive | | +| `irq_lo_o ` | | 1 | `car_sys_timer_lo ` | edge-sensitive | | +| `irq_hi_o ` | | 1 | `car_sys_timer_hi ` | edge-sensitive | | +| **Cheshire peripherals** | | | | | | +| `zero ` | | 1 | `zero ` | level-sensitive | | +| `uart ` | | 1 | `uart ` | level-sensitive | | +| `i2c_fmt_threshold ` | | 1 | `i2c_fmt_threshold ` | level-sensitive | | +| `i2c_rx_threshold ` | | 1 | `i2c_rx_threshold ` | level-sensitive | | +| `i2c_fmt_overflow ` | | 1 | `i2c_fmt_overflow ` | level-sensitive | | +| `i2c_rx_overflow ` | | 1 | `i2c_rx_overflow ` | level-sensitive | | +| `i2c_nak ` | | 1 | `i2c_nak ` | level-sensitive | | +| `i2c_scl_interference` | | 1 | `i2c_scl_interference` | level-sensitive | | +| `i2c_sda_interference` | | 1 | `i2c_sda_interference` | level-sensitive | | +| `i2c_stretch_timeout ` | | 1 | `i2c_stretch_timeout ` | level-sensitive | | +| `i2c_sda_unstable ` | | 1 | `i2c_sda_unstable ` | level-sensitive | | +| `i2c_cmd_complete ` | | 1 | `i2c_cmd_complete ` | level-sensitive | | +| `i2c_tx_stretch ` | | 1 | `i2c_tx_stretch ` | level-sensitive | | +| `i2c_tx_overflow ` | | 1 | `i2c_tx_overflow ` | level-sensitive | | +| `i2c_acq_full ` | | 1 | `i2c_acq_full ` | level-sensitive | | +| `i2c_unexp_stop ` | | 1 | `i2c_unexp_stop ` | level-sensitive | | +| `i2c_host_timeout ` | | 1 | `i2c_host_timeout ` | level-sensitive | | +| `spih_error ` | | 1 | `spih_error ` | level-sensitive | | +| `spih_spi_event ` | | 1 | `spih_spi_event ` | level-sensitive | | +| `gpio ` | | 32 | `gpio ` | level-sensitive | | +| **Spatz cluster** | | | | | | +| | `msip_i[0]` | 1 | `(hostd_spatzcl_mb_intr_ored[0] \| safed_spatzcl_intr_mb[0])` | level-sensitive | Snitch core #0 | +| | `msip_i[1]` | 1 | `(hostd_spatzcl_mb_intr_ored[1] \| safed_spatzcl_intr_mb[1])` | level-sensitive | Snitch core #1 | +| | `mtip_i[0]` | 1 | `chs_mti[0] ` | level-sensitive | Snitch core #0 | +| | `mtip_i[1]` | 1 | `chs_mti[1] ` | level-sensitive | Snitch core #1 | +| | `meip_i ` | 2 | `\- ` | | unconnected | +| | `seip_i ` | 2 | `\- ` | | unconnected | +| **HRM integer cluster** | | | | | | +| `eoc_o` | | 1 | `pulpcl_eoc ` | level-sensitive | | +| | `mbox_irq_i` | 1 | `(hostd_pulpcl_mb_intr_ored \| safed_pulpcl_intr_mb)` | level-sensitive | to offload binaries | +| **Secure domain** | | | | | | +| | `irq_ibex_i` | 1 | `(hostd_secd_mb_intr_ored \| safed_secd_intr_mb)` | level-sensitive | to wake-up Ibex core | +| **Safe domain** | | | | | | +| | `irqs_i[0] ` | 1 | `hostd_safed_mbox_intr[0] ` | level-sensitive | from host domain CVA6#0 | +| | `irqs_i[1] ` | 1 | `hostd_safed_mbox_intr[1] ` | level-sensitive | from host domain CVA6#1 | +| | `irqs_i[2] ` | 1 | `secd_safed_mbox_intr ` | level-sensitive | from secure domain | +| | `irqs_i[3] ` | 1 | `pulpcl_safed_mbox_intr ` | level-sensitive | from HMR custer | +| | `irqs_i[4] ` | 1 | `spatzcl_safed_mbox_intr ` | level-sensitive | from vectorial cluster | +| | `irqs[5] ` | 1 | `irqs_distributed_249 ` | level-sensitive | tied to 0 | +| | `irqs[6] ` | 1 | `irqs_distributed_250 ` | level-sensitive | host domain UART | +| | `irqs[7] ` | 1 | `irqs_distributed_251 ` | level-sensitive | i2c_fmt_threshold | +| | `irqs[8] ` | 1 | `irqs_distributed_252 ` | level-sensitive | i2c_rx_threshold | +| | `irqs[9] ` | 1 | `irqs_distributed_253 ` | level-sensitive | i2c_fmt_overview | +| | `irqs[10] ` | 1 | `irqs_distributed_254 ` | level-sensitive | i2c_rx_overflow | +| | `irqs[11] ` | 1 | `irqs_distributed_255 ` | level-sensitive | i2c_nak | +| | `irqs[12] ` | 1 | `irqs_distributed_256 ` | level-sensitive | i2c_scl_interference | +| | `irqs[13] ` | 1 | `irqs_distributed_257 ` | level-sensitive | i2c_sda_interference | +| | `irqs[14] ` | 1 | `irqs_distributed_258 ` | level-sensitive | i2c_stret h_timeout | +| | `irqs[15] ` | 1 | `irqs_distributed_259 ` | level-sensitive | i2c_sda_unstable | +| | `irqs[16] ` | 1 | `irqs_distributed_260 ` | level-sensitive | i2c_cmd_complete | +| | `irqs[17] ` | 1 | `irqs_distributed_261 ` | level-sensitive | i2c_tx_stretch | +| | `irqs[18] ` | 1 | `irqs_distributed_262 ` | level-sensitive | i2c_tx_overflow | +| | `irqs[19] ` | 1 | `irqs_distributed_263 ` | level-sensitive | i2c_acq_full | +| | `irqs[20] ` | 1 | `irqs_distributed_264 ` | level-sensitive | i2c_unexp_stop | +| | `irqs[21] ` | 1 | `irqs_distributed_265 ` | level-sensitive | i2c_host_timeout | +| | `irqs[22] ` | 1 | `irqs_distributed_266 ` | level-sensitive | spih_error | +| | `irqs[23] ` | 1 | `irqs_distributed_267 ` | level-sensitive | spih_spi_event | +| | `irqs[55:24] ` | 32 | `irqs_distributed_299:268 ` | level-sensitive | gpio | +| | `irqs_i[56] ` | 1 | `irqs_distributed_300 ` | level-sensitive | pulpcl_eoc | +| | `irqs_i[57] ` | 1 | `irqs_distributed_309 ` | level-sensitive | car_wdt_intrs[0] | +| | `irqs_i[58] ` | 1 | `irqs_distributed_310 ` | level-sensitive | car_wdt_intrs[1] | +| | `irqs_i[59] ` | 1 | `irqs_distributed_311 ` | level-sensitive | car_wdt_intrs[2] | +| | `irqs_i[60] ` | 1 | `irqs_distributed_312 ` | level-sensitive | car_wdt_intrs[3] | +| | `irqs_i[61] ` | 1 | `irqs_distributed_313 ` | level-sensitive | car_wdt_intrs[4] | +| | `irqs_i[62] ` | 1 | `irqs_distributed_314 ` | level-sensitive | car_can_intr | +| | `irqs_i[63] ` | 1 | `irqs_distributed_315 ` | edge-sensitive | car_adv_timer_ch0 | +| | `irqs_i[64] ` | 1 | `irqs_distributed_316 ` | edge-sensitive | car_adv_timer_ch1 | +| | `irqs_i[65] ` | 1 | `irqs_distributed_317 ` | edge-sensitive | car_adv_timer_ch2 | +| | `irqs_i[66] ` | 1 | `irqs_distributed_318 ` | edge-sensitive | car_adv_timer_ch3 | +| | `irqs_i[67] ` | 1 | `irqs_distributed_319 ` | edge-sensitive | car_adv_timer_events[0] | +| | `irqs_i[68] ` | 1 | `irqs_distributed_320 ` | edge-sensitive | car_adv_timer_events[1] | +| | `irqs_i[69] ` | 1 | `irqs_distributed_321 ` | edge-sensitive | car_adv_timer_events[2] | +| | `irqs_i[70] ` | 1 | `irqs_distributed_322 ` | edge-sensitive | car_adv_timer_events[0] | +| | `irqs_i[71] ` | 1 | `irqs_distributed_323 ` | edge-sensitive | car_sys_timer_lo | +| | `irqs_i[72] ` | 1 | `irqs_distributed_324 ` | edge-sensitive | car_sys_timer_hi | +| | `irqs_i[127:73]` | 54 | `irqs_distributed_331:325 ` | - | tied to 0 | +| **Cheshire** | | | | | | +| | `intr_ext_i[0] ` | 1 | `pulpcl_eoc ` | level-sensitive | from HMR cluster | +| | `intr_ext_i[2:1] ` | 2 | `pulpcl_hostd_mbox_intr ` | level-sensitive | from HMR cluster | +| | `intr_ext_i[4:3] ` | 2 | `spatzcl_hostd_mbox_intr` | level-sensitive | from vectorial cluster | +| | `intr_ext_i[6:5] ` | 2 | `safed_hostd_mbox_intr ` | level-sensitive | from safe domain | +| | `intr_ext_i[8:7] ` | 2 | `secd_hostd_mbox_intr ` | level-sensitive | from secure domain | +| | `intr_ext_i[9] ` | 1 | `car_wdt_intrs[0] ` | level-sensitive | from carfield peripherals | +| | `intr_ext_i[10] ` | 1 | `car_wdt_intrs[1] ` | level-sensitive | from carfield peripherals | +| | `intr_ext_i[11] ` | 1 | `car_wdt_intrs[2] ` | level-sensitive | from carfield peripherals | +| | `intr_ext_i[12] ` | 1 | `car_wdt_intrs[3] ` | level-sensitive | from carfield peripherals | +| | `intr_ext_i[13] ` | 1 | `car_wdt_intrs[4] ` | level-sensitive | from carfield peripherals | +| | `intr_ext_i[14] ` | 1 | `car_can_intr ` | level-sensitive | from carfield peripherals | +| | `intr_ext_i[15] ` | 1 | `car_adv_timer_ch0 ` | edge-sensitive | from carfield peripherals | +| | `intr_ext_i[16] ` | 1 | `car_adv_timer_ch1 ` | edge-sensitive | from carfield peripherals | +| | `intr_ext_i[17] ` | 1 | `car_adv_timer_ch2 ` | edge-sensitive | from carfield peripherals | +| | `intr_ext_i[18] ` | 1 | `car_adv_timer_ch3 ` | edge-sensitive | from carfield peripherals | +| | `intr_ext_i[19] ` | 1 | `car_adv_timer_events[0]` | edge-sensitive | from carfield peripherals | +| | `intr_ext_i[20] ` | 1 | `car_adv_timer_events[1]` | edge-sensitive | from carfield peripherals | +| | `intr_ext_i[21] ` | 1 | `car_adv_timer_events[2]` | edge-sensitive | from carfield peripherals | +| | `intr_ext_i[22] ` | 1 | `car_adv_timer_events[3]` | edge-sensitive | from carfield peripherals | +| | `intr_ext_i[23] ` | 1 | `car_sys_timer_lo ` | edge-sensitive | from carfield peripherals | +| | `intr_ext_i[24] ` | 1 | `car_sys_timer_hi ` | edge-sensitive | from carfield peripherals | +| | `intr_ext_i[31:25]` | 7 | `0 ` | | tied to 0 | +| `meip_ext_o[0]` | | \- | | level-sensitive | unconnected | +| `meip_ext_o[1]` | | \- | | level-sensitive | unconnected | +| `meip_ext_o[2]` | | \- | | level-sensitive | unconnected | +| `seip_ext_o[0]` | | \- | | level-sensitive | unconnected | +| `seip_ext_o[1]` | | \- | | level-sensitive | unconnected | +| `seip_ext_o[2]` | | \- | | level-sensitive | unconnected | +| `msip_ext_o[0]` | | \- | | level-sensitive | unconnected | +| `msip_ext_o[1]` | | \- | | level-sensitive | unconnected | +| `msip_ext_o[2]` | | \- | | level-sensitive | unconnected | +| `mtip_ext_o[0]` | | \- | | level-sensitive | Snitch core #0 | +| `mtip_ext_o[1]` | | \- | | level-sensitive | Snitch core #1 | +| `mtip_ext_o[2]` | | \- | | level-sensitive | unconnected | + +## Domains + +The total number of domains is 7: *host domain*, *safe domain*, *secure domain*, *integer PMCA +domain*, *vectorial PMCA domain*, *peripheral domain*, *dynamic SPM*. + +Carfield's domains live in dedicated repositories. We therefore invite the reader to consult the +documentation of each domain. + +For more information about domains' memory requirements, visit [Synthesis and physical +implementation](../tg/synth.md). + +Below, we focus on domains' parameterization within Carfield. + +### [Host domain (Cheshire)](https://github.com/pulp-platform/cheshire) + +The *host domain* (Cheshire) embeds all the necessary components required to run OSs such as +embedded Linux. It has two orthogonal *operation modes*. + +1. *Untrusted mode*: in this operation mode, the host domain is tasked to run untrusted services, +i.e. non time- and non safety-critical applications. For example, this could be the case of infotainment +on a modern car. In this mode, as in traditional automotive platforms, safety and resiliency +features are deferred to a dedicated 32-bit microcontroller-like system, called `safe domain` in +Carfield. + +2. *Hybrid trusted/untrusted mode*: in this operation mode, the host domain is in charge of both +critical and non-critical applications. Key features supported to achieve this are: + * A virtualization layer, which allows the system to accommodate the execution of multiple OSs, +including rich, Unix-like OSs and Real-Time OSs (RTOS), coexisting on the same HW. + * Spatial and temporal partitioning of resources: AXI matrix crossbar + ([AXI-REALM](https://arxiv.org/abs/2311.09662)), LLC, TLB, and a `physical tagger` in front of + the cores to mark partitions by acting directly on the physical address space + * Runtime configurable data/instruction cache and SPM + * Fast interrupt handling, with optional interrupt routing through the RISC-V fast interrupt +controller CLIC, + * Configurable dual core setup between *lockstep* or *SMP* mode. + + Hybrid operation mode is currently experimental, and mostly for research purposes. We advise of + relying on a combination of host ad safe domain for a more traditional approach. + +Cheshire is configured as follows: + +* Two 64-bit, RISC-V CVA6 cores, with lightweight self-invalidation cache coherency, fast interrupt +and virtualization support. +* 8 external AXI manager ports (`AxiNumExtSlv`) added to the matrix crossbar: + - Dynamic SPM port 0 + - Dynamic SPM port 1 + - Safe domain + - HMR cluster + - Vectorial cluster + - Mailbox unit + - Ethernet + - Peripherals +* 4 external AXI subordinate ports (`AxiNumExtMst`) added to the matrix crossbar: + - Safe domain + - Secure domain + - HMR cluster + - Vectorial cluster +* 4 external regbus subordinate ports (`NumTotalRegSlv`): + - PCRs: control domains enable, clock gate, isolation + - PLL control registers: for ASIC top-levels, leave unconnected otherwise + - Padmux control registers: for ASIC top-levels, leave unconnected otherwise + - Dynamic SPM ECC control registers +* [AXI-REALM](https://arxiv.org/abs/2311.09662) unit for bandwidth regulation and monitoring + integrated in front of each AXI matrix crossbar manager +* Last-level cache (LLC) with HW spatial partitioning +* 32 *external* input interrupts (`CarfieldNumExtIntrs`), see [Interrupt map](#interrupt-map) in + addition to Cheshire's own internal interrupts. Unused are tied to 0 (currently 9/32) +* 2 external interruptible harts (`CarfieldNumInterruptibleHarts`). The interruptible harts are + Snitch core \#0 and \#1 in the vectorial cluster. +* An interrupt router with 1 external target (`CarfieldNUmRouterTargets`), tasked to distribute N + input interrupts to M targets. In Carfield, the external target is the `safe domain`. +* All Cheshire peripherals, except for VGA + +By default, Cheshire hosts 128KiB of hybrid LLC/SPM, user-configurable. + +### [Safe domain](https://github.com/pulp-platform/safety_island) + +The *safe domain* is a simple MCU-like domain that comprises three 32-bit real-time CV32E40P +(CV32RT) RISC-V cores operating in triple-core-lockstep mode (TCLS). + +These cores, enhanced with the RISC-V CLIC controller and optimized for fast interrupt handling and +context switch, run RTOSs and safety-critical applications, embodying a core tenet of the platform +reliability. + +The *safe domain* is essential when the *host domain* is operated in *untrusted* mode. + +The *safe domain* is configured as follows: + +* 1 RISC-V debug module prividing indipendent JTAG interface off-Carfield +* 1 AXI manager and 1 AXI subordinate ports, 32-bit data and 32-bit address wide, to and from the + *host domain*, respectively. AXI datawidth conversion with the host domain is handled internally + to the safe domain. +* 1 generic timer, essential for periodic ticks common in RTOSs. The generic timer in the *safe + domain* is the same integrated in [Carfield's *peripheral domain*](#peripheral-domain). +* CLIC RISC-V interrupt controller; as opposed to Cheshire, currently the CLIC is configured to run + run in M-mode. +* 128 *external* input interrupts. Unused are tied to 0. +* Fast interrupt extension that extends CV32 with additional logic to accelerate context switching. + From here, the name [CV32RT](https://arxiv.org/abs/2311.08320) +* 1 32-bit per-core FPU with down to float-16 precision, totaling 3 FPUs + +By default, the processing elements share access to 128KiB of SPM for instructions and data, +user-configurable. + +### [Secure domain](https://github.com/pulp-platform/opentitan/tree/carfield-soc) + +The secure domain, based on the [OpenTitan +project](https://opentitan.org/book/doc/introduction.html), serves as the Hardware Root-of-Trust +(HWRoT) of the platform. It handles *secure boot* and system integrity monitoring fully in HW +through cryptographic acceleration services. + +Compared to vanilla OpenTitan, the secure domain integrated in Carfield is modified/configured as follows: + +* 1 AXI4 manager interface to Carfield, with a bridge between AXI4 and TileLink Uncached Lightweight + (TL-UL) internally used by OpenTitan. By only exposing a manager port, unwanted access to the + secure domain is prevented. + +* Embedded flash memory replaced with an SRAM preloaded before secure boot procedure from an + external SPI flash through OpenTitan private SPI peripheral. Once preload is over, the OpenTitan + secure boot framework is unchanged compared to the vanilla version. + +* Finally, a *boot manager* module has been designed and integrated to manage the [two available + bootmodes](./sw.md). In **Secure** mode, the systems executes the secure boot framework as soon as + the reset is asserted, loading code from the external SPI and performing the signature check on + its content. Otherwise, in **Non-secure** mode, the *secure domain* is clock gated and must be + clocked and woken-up by an external entity (e.g., *host domain*) + +By default, the secure domain hosts 512KiB of main SPM, and 16KiB of OTP memory, user-configurable. + +### Accelerator domain + +To augment computational capabilities, Carfield incorporates two PMCAs, described below. Both PMCAs +integrate DMA engines to independently fetch data from the on-chip SPM or external DRAM. + +#### [HMR integer PMCA](https://github.com/pulp-platform/pulp_cluster/tree/yt/rapidrecovery) + +The [hybrid modular redundancy (HMR) *integer PMCA*](https://arxiv.org/abs/2303.08706) is +specialized in accelerating the inference of Deep Learning and Machine Learning models. The +multicore accelerator is built around 12 32-bit RISC-V cores empowered with ISA extensions, enabling +integer arithmetic from 32-bit down to 2-bit precision. + +The integer PMCA does not integrate a fully-fledged FPU co-processor. Nevertheless, it features a +highly specialized domain specific accelerator (DSA), +[RedMulE](https://www.sciencedirect.com/science/article/pii/S0167739X23002546), which enables fast +and energy-efficient floating-point GEMM on 16-bit and 8-bit data formats. This makes the PMCA +capable of on-chip training of generalized Deep Learning models. + +As part of a MCS, the integer PMCA's general-purpose cores can be reconfigured for *redundant +execution*. A [Hybrid Modular Redundancy (HMR)](https://doi.org/10.1145/3635161) unit allows the +split/lock of the available cores in different redundant configurations during runtime, trading off +the computing performance and the fault resilience capability according to the criticality of the +application. + +The PMCA can be configured in multiple redundant modes: +* **Independent:** All cores act independently with no redundancy mechanism. This configuration allows + higher performance but has no reliability. +* **Dual Modular Redundancy (DMR)**: The cores are grouped in lock-stepped pairs and rely on a + specialized hardware extension for fast fault recovery in less than 30 clock cycles in case of + fault detection. The PMCA provides the best trade-off between performance and fault recovery in + this configuration. +* **Triple Modular Redundancy (TMR)**: The cores are grouped in lock-stepped triplets and rely on + either hardware extension or software mechanisms to recover from incurring faults. The PMCA + provides the highest fault resilience in this configuration, at the cost of reduced performance. + +By default, the integer PMCA's processing elements and tensor accelerator share access to 256KiB of +L1 SPM, user-configurable. + +#### [Vectorial PMCA](https://github.com/pulp-platform/spatz) + +The [*vectorial PMCA*, or Spatz PMCA](https://dl.acm.org/doi/abs/10.1145/3508352.3549367) handles +vectorizable multi-format floating-point workloads. + +A Spatz vector unit acts as a coprocessor of the [Snitch +core](https://github.com/pulp-platform/snitch_cluster), a tiny RV32IMA core which decodes and +forwards vector instructions to the vector unit. + +A Snitch core and a Spatz vector unit are together referred to as *Core Complex (CC)*. The vectorial +PMCA is composed by two CCs, each with the following configuration: + +* 2 KiB of latch-based VRF +* 4 transprecision FPUs +* 1 integer processing unit (IPU) + +Each FPU supports *FP8*, *FP16*, *FP32*, and *FP64* computation, while the IPU supports 8, 16, 32, +and 64-bit integer computation. + +By default, the CCs share access to 128KiB of L1 SPM, user-configurable. + +## On-chip and off-chip memory endpoints + +### [Dynamic scratchpad memory (SPM)](https://github.com/pulp-platform/dyn_spm) + +The dynamic SPM features dynamically switching address mapping policy. It manages the following +features: + +* Two AXI subordinate ports +* Two address mapping modes: *interleaved* and *contiguous* +* 4 address spaces, 2 for each port. The address space is used to select the AXI port to use, and + the mapping mode +* Every address space points to the same physical SRAM through a low-latency matrix crossbar +* ECC-equipped memory banks + +By default, Carfield hosts 1MiB of dynamic SPM, user-configurable. + +### [Partitionable hybrid LLC/SPM](https://github.com/pulp-platform/axi_llc) + +Carfield hosts a LLC optionaly reconfigurable as SPM during runtime. In addition, the LLC supports +HW-based partitioning to exploit intra-process or inter-processes isolation, improving the system's +predictability. The LLC is described in detail in Cheshire's +[Architecture](https://pulp-platform.github.io/cheshire/um/arch). + +### [HyperBus off-chip link](https://github.com/pulp-platform/hyperbus) + +Carfield integrates a in-house, open-source implementation of Infineon' HyperBus off-chip controller +to connect to external HyperRAM modules. + +It manages the following features: + +* An AXI interface that attaches to Cheshire's [partitionable hybrid + LLC/SPM](#partitionable-hybrid-llc-spm) +* A configurable number of physical HyperRAM chips it can be attached to; by default, support for 2 + physical chips is provided +* Support for HyperRAM chips with different densities (from 8MiB to 64MiB per chip aligned with + specs). + +## System bus interconnect + +The interconnect is composed of a main [AXI4](https://github.com/pulp-platform/axi) matrix (or +crossbar) with AXI5 atomic operations (ATOPs) support. The crossbar extends Cheshire's with +additional external AXI manager and subordinate ports. + +Cheshire's auxiliary [Regbus](https://github.com/pulp-platform/register_interface) demultiplexer is +extended with additional peripheral configuration ports for external PLL/FLL and padmux +configuration, which are specific of ASIC wrappers. + +An additional peripheral subsystem based on APB hosts Carfield-specific peripherals. + +## [Mailbox unit](https://github.com/pulp-platform/mailbox_unit) + +The mailbox unit consists in a number of configurable mailboxes. Each mailbox is the preferred +communication vehicle between *domains*. It can be used to wake-up certain domains, notify an +*offloader* (e.g., Cheshire) that a *target device* (e.g., the integer PMCA) has reached execution +completion, dispatch *entry points* to a *target device* to jump-start its execution, and many +others. + +It manages the following features: + +* Interrupt based signaling receiver and sender +* A shared memory space common to all the mailboxes, implemented as a single register file. + Currently, Carfield implements 25 mailboxes. +* Support for 32-bit word aligned read/write access. +* A convenience AXI-Lite wrapper for the configuration port. + +--- + +Assuming each mailbox is identified with id `i`, the register file map reads: + +| **Offset** | **Register** | **Width (bit)** | **Note** | +|--------------------|------------------|-----------------|--------------------| +| `0x00 + i * 0x100` | `INT_SND_STAT` | `1` | current irq status | +| `0x04 + i * 0x100` | `INT_SND_SET ` | `1` | set irq | +| `0x08 + i * 0x100` | `INT_SND_CLR ` | `1` | clear irq | +| `0x0C + i * 0x100` | `INT_SND_EN ` | `1` | enable irq | +| `0x40 + i * 0x100` | `INT_RCV_STAT` | `1` | current irq status | +| `0x44 + i * 0x100` | `INT_RCV_SET ` | `1` | set irq | +| `0x48 + i * 0x100` | `INT_RCV_CLR ` | `1` | clear irq | +| `0x4C + i * 0x100` | `INT_RCV_EN ` | `1` | enable irq | +| `0x80 + i * 0x100` | `LETTER0 ` | `32` | message | +| `0x8C + i * 0x100` | `LETTER1 ` | `32` | message | + +The above register map can be found in the dedicated +[repository](https://github.com/pulp-platform/mailbox_uni) and is reported here for convenience. + +## Platform control registers + +PCRs provide basic system information, and control clock, reset and other functionalities of +Carfield's *domains*. + +A more detailed overview of each PCR (register subfields and description) can be found +[here](../../hw/regs/pcr.md). PCR base address is listed in the [Memory Map](#memory-map) as for the +other devices. + +| **Name** | **Offset** | **Length** | **Description** | +|:---------------------------------|:-----------|-----------:|:-----------------------------------------------------------------------| +| `VERSION0` | `0x0` | `4` | Cheshire sha256 commit | +| `VERSION1` | `0x4` | `4` | Safety Island sha256 commit | +| `VERSION2` | `0x8` | `4` | Security Island sha256 commit | +| `VERSION3` | `0xc` | `4` | PULP Cluster sha256 commit | +| `VERSION4` | `0x10` | `4` | Spatz CLuster sha256 commit | +| `JEDEC_IDCODE` | `0x14` | `4` | JEDEC ID CODE | +| `GENERIC_SCRATCH0` | `0x18` | `4` | Scratch | +| `GENERIC_SCRATCH1` | `0x1c` | `4` | Scratch | +| `HOST_RST` | `0x20` | `4` | Host Domain reset -active high, inverted in HW- | +| `PERIPH_RST` | `0x24` | `4` | Periph Domain reset -active high, inverted in HW- | +| `SAFETY_ISLAND_RST` | `0x28` | `4` | Safety Island reset -active high, inverted in HW- | +| `SECURITY_ISLAND_RST` | `0x2c` | `4` | Security Island reset -active high, inverted in HW- | +| `PULP_CLUSTER_RST` | `0x30` | `4` | PULP Cluster reset -active high, inverted in HW- | +| `SPATZ_CLUSTER_RST` | `0x34` | `4` | Spatz Cluster reset -active high, inverted in HW- | +| `L2_RST` | `0x38` | `4` | L2 reset -active high, inverted in HW- | +| `PERIPH_ISOLATE` | `0x3c` | `4` | Periph Domain AXI isolate | +| `SAFETY_ISLAND_ISOLATE` | `0x40` | `4` | Safety Island AXI isolate | +| `SECURITY_ISLAND_ISOLATE` | `0x44` | `4` | Security Island AXI isolate | +| `PULP_CLUSTER_ISOLATE` | `0x48` | `4` | PULP Cluster AXI isolate | +| `SPATZ_CLUSTER_ISOLATE` | `0x4c` | `4` | Spatz Cluster AXI isolate | +| `L2_ISOLATE` | `0x50` | `4` | L2 AXI isolate | +| `PERIPH_ISOLATE_STATUS` | `0x54` | `4` | Periph Domain AXI isolate status | +| `SAFETY_ISLAND_ISOLATE_STATUS` | `0x58` | `4` | Safety Island AXI isolate status | +| `SECURITY_ISLAND_ISOLATE_STATUS` | `0x5c` | `4` | Security Island AXI isolate status | +| `PULP_CLUSTER_ISOLATE_STATUS` | `0x60` | `4` | PULP Cluster AXI isolate status | +| `SPATZ_CLUSTER_ISOLATE_STATUS` | `0x64` | `4` | Spatz Cluster AXI isolate status | +| `L2_ISOLATE_STATUS` | `0x68` | `4` | L2 AXI isolate status | +| `PERIPH_CLK_EN` | `0x6c` | `4` | Periph Domain clk gate enable | +| `SAFETY_ISLAND_CLK_EN` | `0x70` | `4` | Safety Island clk gate enable | +| `SECURITY_ISLAND_CLK_EN` | `0x74` | `4` | Security Island clk gate enable | +| `PULP_CLUSTER_CLK_EN` | `0x78` | `4` | PULP Cluster clk gate enable | +| `SPATZ_CLUSTER_CLK_EN` | `0x7c` | `4` | Spatz Cluster clk gate enable | +| `L2_CLK_EN` | `0x80` | `4` | Shared L2 memory clk gate enable | +| `PERIPH_CLK_SEL` | `0x84` | `4` | Periph Domain pll select (0 -> host pll, 1 -> alt PLL, 2 -> per pll) | +| `SAFETY_ISLAND_CLK_SEL` | `0x88` | `4` | Safety Island pll select (0 -> host pll, 1 -> alt PLL, 2 -> per pll) | +| `SECURITY_ISLAND_CLK_SEL` | `0x8c` | `4` | Security Island pll select (0 -> host pll, 1 -> alt PLL, 2 -> per pll) | +| `PULP_CLUSTER_CLK_SEL` | `0x90` | `4` | PULP Cluster pll select (0 -> host pll, 1 -> alt PLL, 2 -> per pll) | +| `SPATZ_CLUSTER_CLK_SEL` | `0x94` | `4` | Spatz Cluster pll select (0 -> host pll, 1 -> alt PLL, 2 -> per pll) | +| `L2_CLK_SEL` | `0x98` | `4` | L2 Memory pll select (0 -> host pll, 1 -> alt PLL, 2 -> per pll) | +| `PERIPH_CLK_DIV_VALUE` | `0x9c` | `4` | Periph Domain clk divider value | +| `SAFETY_ISLAND_CLK_DIV_VALUE` | `0xa0` | `4` | Safety Island clk divider value | +| `SECURITY_ISLAND_CLK_DIV_VALUE` | `0xa4` | `4` | Security Island clk divider value | +| `PULP_CLUSTER_CLK_DIV_VALUE` | `0xa8` | `4` | PULP Cluster clk divider value | +| `SPATZ_CLUSTER_CLK_DIV_VALUE` | `0xac` | `4` | Spatz Cluster clk divider value | +| `L2_CLK_DIV_VALUE` | `0xb0` | `4` | L2 Memory clk divider value | +| `HOST_FETCH_ENABLE` | `0xb4` | `4` | Host Domain fetch enable | +| `SAFETY_ISLAND_FETCH_ENABLE` | `0xb8` | `4` | Safety Island fetch enable | +| `SECURITY_ISLAND_FETCH_ENABLE` | `0xbc` | `4` | Security Island fetch enable | +| `PULP_CLUSTER_FETCH_ENABLE` | `0xc0` | `4` | PULP Cluster fetch enable | +| `SPATZ_CLUSTER_DEBUG_REQ` | `0xc4` | `4` | Spatz Cluster debug req | +| `HOST_BOOT_ADDR` | `0xc8` | `4` | Host boot address | +| `SAFETY_ISLAND_BOOT_ADDR` | `0xcc` | `4` | Safety Island boot address | +| `SECURITY_ISLAND_BOOT_ADDR` | `0xd0` | `4` | Security Island boot address | +| `PULP_CLUSTER_BOOT_ADDR` | `0xd4` | `4` | PULP Cluster boot address | +| `SPATZ_CLUSTER_BOOT_ADDR` | `0xd8` | `4` | Spatz Cluster boot address | +| `PULP_CLUSTER_BOOT_ENABLE` | `0xdc` | `4` | PULP Cluster boot enable | +| `SPATZ_CLUSTER_BUSY` | `0xe0` | `4` | Spatz Cluster busy | +| `PULP_CLUSTER_BUSY` | `0xe4` | `4` | PULP Cluster busy | +| `PULP_CLUSTER_EOC` | `0xe8` | `4` | PULP Cluster end of computation | +| `ETH_RGMII_PHY_CLK_DIV_EN` | `0xec` | `4` | Ethernet RGMII PHY clock divider enable bit | +| `ETH_RGMII_PHY_CLK_DIV_VALUE` | `0xf0` | `4` | Ethernet RGMII PHY clock divider value | +| `ETH_MDIO_CLK_DIV_EN` | `0xf4` | `4` | Ethernet MDIO clock divider enable bit | +| `ETH_MDIO_CLK_DIV_VALUE` | `0xf8` | `4` | Ethernet MDIO clock divider value | + +## Peripherals + +Carfield enhances Cheshire's peripheral subsystem with additional capabilities. + +An external AXI manager port is attached to the matrix crossbar. The 64-bit data, 48-bit address AXI +protocol is converted to the slower, 32-bit data and address APB protocol. An APB demultiplexer +allows attaching several peripherals, described below. + +### Generic and advanced timer + +Carfield integrates a generic timer and an advanced timer. + +The [*generic timer*](https://github.com/pulp-platform/timer_unit) manages the following features: + +- 2 general purpose 32-bit up counter timers +- Input trigger sources: + - FLL/PLL clock + - FLL/PLL clock + Prescaler + - Real-time clock (RTC) at crystal frequency (32kHz) or higher + - External event +- 8-bit programmable prescaler to FLL/PLL clock +- Counting modes: + - One shot mode: timer is stopped after first comparison match + - Continuous mode: timer continues counting after comparison match + - Cycle mode: timer resets to 0 after comparison match and continues counting + - 64 bit cascaded mode +- Interrupt request generation on comparison match + +For more information, read the dedicated +[documentation](https://github.com/pulp-platform/timer_unit/blob/master/doc/TIMER_UNIT_reference.xlsx). + +The [*advanced timer*](https://github.com/pulp-platform/apb_adv_timer) manages the following +features: + +* 4 timers with 4 output signal channels each +* PWM generation functionality +* Multiple trigger input sources: + - output signal channels of all timers + - 32 GPIOs + - Real-time clock (RTC) at crystal frequency (32kHz) or higher + - FLL/PLL clock + In Carfield, we rely on a RTC. +* Configurable input trigger modes +* Configurable prescaler for each timer +* Configurable counting mode for each timer +* Configurable channel threshold action for each timer +* 4 configurable output events +* Configurable clock gating of each timer + +For more information, read the dedicated +[documentation](https://github.com/pulp-platform/apb_adv_timer/blob/master/doc/APB_ADV_TIMER_reference.xlsx). + +### Watchdog timer + +We employ the watchdog timer developed by the [OpenTitan +project](https://opentitan.org/book/doc/introduction.html) project. It manages the following +features: + +* Two 32-bit upcounting timers: one timer functions as a wakeup timer, one as a watchdog timer +* 2 thresholds: *bark* (generates an interrupt) and *bite* (resets core) +* A 12 bit pre-scaler for the wakeup timer to enable very long timeouts + +For more information, read the dedicated +[documentation](https://opentitan.org/book/hw/ip/aon_timer/). + +### CAN + +We employ a CAN device developed by the [Czech Technical +University](https://github.com/AlSaqr-platform/can_bus/tree/pulp) in Prague. It manages the +following features: + +* CAN 2.0, CAN FD 1.0 and ISO CAN FD +* Avalon memory bus +* Timestamping and transmission at given time +* Optional event and error logging +* Fault confinement state manipulation +* Transceiver delay measurement +* Variety of interrupt sources +* Filtering of received frame +* Listen-only mode, Self-test mode, Acknowledge forbidden mode +* Up to 14 Mbit in “Data” bit-rate (with 100 Mhz Core clock) + +For more information, read the dedicated +[documentation](https://github.com/AlSaqr-platform/can_bus/tree/pulp/doc) + +### Ethernet + +We employ Ethernet IPs developed by [Alex +Forencich](https://github.com/alexforencich/verilog-ethernet) and assemble them with a +high-performant DMA, the same used in Cheshire. + +We use Reduced gigabit media-independent interface (RGMII) that supports speed up to 1000Mbit/s +(1GHz). + +For more information, read the dedicated +[documentation](http://alexforencich.com/wiki/en/verilog/ethernet/start) of Ethernet components from +its original repository. + +## Clock and reset + +![Reset and Clock Distribution for a domain *X*](../img/clk_rst.svg) + +![Isolation for a domain *X*](../img/isolation.svg) + +The two figures above show the clock, reset and isolation distribution for a *domain* `X` in +Carfield, and their relationship. A more detailed description is provided below. + +### Clock distribution scheme, clock gating and isolation + +Carfield is provided with 3 clocks sources. They can be fully asynchronous and not bound to any +phase relationship, since dual-clock FIFOs are placed between domains to allow clock domain crossing +(CDC): + +* `host_clk_i`: preferably, clock of the *host domain* +* `alt_clk_i`: preferably, clock of *alternate* domains, namely *safe domain*, *secure domain*, + *accelerator domain* +* `per_clk_i`: preferably, clock of *peripheral domain* + +In addition, a real-time clock (RTC, `rt_clk_i`) is provided externally, at crystal frequency +(32kHz) or higher. + +These clocks are supplied externally, by a dedicated PLL per clock source or by a single PLL that +supplies all three clock sources. The configuration of the clock source can be handled by the +external PLL wrapper configuration registers, e.g. in a ASIC top level + +Regardless of the specific name used for the clock signals in HW, Carfield has a flexible clock +distribution that allows each of the 3 clock sources to be assigned to a *domain*, as explained +below. + +--- + +As the top figure shows, out of the 7 *domains* described in [Domains](#domains), 6 can be clock +gated and *isolated*: *safe domain*, *secure domain*, *accelerator domain*, *peripheral domain*, +*dynamic SPM*. + +When *isolation* for a domain `X` is enabled, data transfers towards a domain are terminated and +never reach it. To achieve this, an AXI4 compliant *isolation* module is placed in front of each +domain. The bottom figure shows in detail the architecture of the isolation scheme between the *host +domain* and a generic `X` domain, highlighting its relationship with the domain's reset and cloc +signals. + +For each of the 6 clock gateable domains, the following clock distribution scheme applies: + +1. The user selects one of the 3 different clock sources +2. The selected clock source for the domain is fed into a default-bypassed arbitrary integer clock + divider with 50% duty cycle. This allows to use different integer clock divisions for every + target domain to use different clock frequencies +3. The internal clock gate of the clock divider is used to provide clock gating for the domain. + +HW resources for the clock distribution (steps 1., 2., and 3.) and isolation of a domain `X`, are +SW-controlled via dedicated PCRs. Refer to [Platform Control Registers](#platform-control-registers) +in this page for more information. + +The only domain that is always-on and de-isolated is the *host domain* (Cheshire). If required, +clock gating and/or isolation of it can be handled at higher levels of hierarchy, e.g. in a +dedicated ASIC wrapper. + +### Startup behavior after Power-on reset (POR) + +The user can decide whether *secure boot* must be performed on the executing code before runtime. If +so, the *secure domain* must be active after POR, i.e., clocked and de-isolated. This behavior is +regulated by the input pin `secure_boot_i` according to the following table: + +| `secure_boot_i` | **Secure Boot** | **System status after POR** | +|:----------------|----------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------| +| `0` | `OFF` | *secure domain* gated and isolated as the other 5 domains, *host domain* always-on and idle | +| `1` | `ON` | *host domain* always-on and idle, *secure domain* active, takes over *secure boot* and can't be warm reset-ed; other 5 domains gated and isolated | + +Regardless of the value of `secure_boot_i`, since by default some domains are clock gated and +isolated after POR, SW or external physical interfaces (JTAG/Serial Link) must handle their wake-up +process. Routines are provided in the [Software Stack](../../sw/include/car_util.h). + +### Reset distribution scheme + +Carfield is provided with one POR (active-low), `pwr_on_rst_ni`, responsible for the platform's +*cold reset*. + +The POR is synchronized with the clock of each domain, user-selected as explained above, and +propagated to the domain. + +In addition, a *warm reset* can be initiated from SW through the PCRs for each domain. Exceptions to +this are the *host domain* (always-on), and the *secure domain* when `secure_boot_i` is asserted. diff --git a/docs/um/index.md b/docs/um/index.md new file mode 100644 index 00000000..990cfeaf --- /dev/null +++ b/docs/um/index.md @@ -0,0 +1,8 @@ +# User Manual + +The *user manual* provides detailed reference information on Carfield: + +- [Architecture](arch.md): Describes the hardware design, features, configuration and memory + map of Carfield. +- [Software Stack](sw.md): Describes how to run code on Carfield and its heterogeneous software + stack. diff --git a/docs/um/sw.md b/docs/um/sw.md new file mode 100644 index 00000000..7d5472c6 --- /dev/null +++ b/docs/um/sw.md @@ -0,0 +1,224 @@ +# Software Stack + +Carfield's Software Stack is provided in the `sw/` folder, organized as follows: + +``` +sw +├── boot +├── include +├── lib +├── link +├── sw.mk +├── tests +    ├── bare-metal +    │   ├── hostd +    │   ├── pulpd +    │   ├── safed +    │   ├── secd +    │   └── spatzd +    └── linux +``` + +Employing Cheshire as *host domain*, Carfield's software stack is largely based on, and built on top +of, [Cheshire's](https://pulp-platform.github.io/cheshire/um/sw/). + +This means that it shares the same: + +* Baremetal programs (BMPs) build flow and structure +* Boot ROM +* Zero-Stage Loader +* OpenSBI Firmware +* Linux + +Therefore, we defer the reader to Cheshire's Software Stack description for more information. + +Programs compiled for Carfield are linked against Cheshire's static library (`libcheshire.a`). This +operation is transparent to the programmer, that can take advantage of Cheshire's device drivers and +SW routines within Carfield seamlessly. + +Provided the equivalence and reuse between Carfield and Cheshire, in this page we focus on +Carfield-specific SW components and build flow, with an emphasis on domains different than Cheshire. + +## Compiler requirements + +General-purpose processing elements (PEs) integrated in Carfield implement the RISC-V ISA, targeting +either RV64 (*host domain*) or RV32 (all the others: *safe domain*, *secure domain*, *integer PMCA*, +and *vectorial PMCA*). + +To build programs for a Carfield domain with the base ISA and its regular extensions (namely, +`RV64G` and `RV32IMACF`) *without* using *custom* extensions that each domain provide, you simply +need vanilla RV64 and RV32 compilers. + +Otherwise, to use *custom* instruction supported in HW for a domain, specific compiler support is +required. We are working to improve compiler support by providing pointers to pre-built releases or +a container-based build flow. + +## Boot Flow and Secure Boot + +Carfield supports two *operative boot flows*: + +* **Non-secure**: being an always-on domain, in this *operative boot flow* Cheshire takes over + Carfield's boot flow. This means that *passive* and *autonomous* boot are equivalent to those + described in Cheshire's [Software Stack](https://pulp-platform.github.io/cheshire/um/sw/). Since + the other domains are clock gated, SW to be executed on them requires Cheshire to handle their + wake-up sequence. + +* **Secure**: The *secure domain* performs the secure boot process on the code that will be executed + on the Carfield system, independently of the domain. For more information, read the dedicated + [secure boot documentation](https://opentitan.org/book/doc/security/specs/secure_boot) of the + OpenTitan project. + +## Single domain programs build flow + +### Baremetal programs (BMPs) + +BMPs for all domains can be built from the root of Carfield through a portable *make fragment* +`sw.mk` located in the `sw/` folder. + +To simplify each domain SW build as much as possible, we provide a make fragment located at +`sw/tests/bare-metal//sw.mk`, included in the main `sw.mk`. + +BMPs for each domain are compiled *in situ* in the domain repository, since each IP was design for, +or supports also, standalone execution and has its own build flow. + +The global command + +``` +make car-sw-build +``` + +builds program binaries in ELF format for each domain, which can be used with the simulation methods +supported by the platform, as described in [Simulation](../tg/sim.md) or on FPGA as described in +[Xilinx FPGAs](../tg/xilinx.md). + +--- + +As in Cheshire, Carfield programs can be created to be executed from several memory locations: + +* Dynamic SPM (`*.l2.elf`): the linkerscript is provided in Carfield's `sw/link/` folder, since + Dynamic SPM is not integrated in the minimal Cheshire +* LLC SPM (`*.spm.elf`): valid when the LLC is configured as such. In Carfield, half of the LLC is + configured as SPM from the boot ROM during system bringup, as this is the default behavior in + Cheshire. +* DRAM (`*.dram.elf`): the off-chip DRAM, e.g., the HyperRAM + +For example, to build a specific BMP (here `sw/tests/bare-metal/hostd/helloworld.c` to be run on +Cheshire) executing from the Dynamic SPM, run: + +``` +make sw/tests/bare-metal/hostd/helloworld.car.l2.elf +``` + +To create the same program executing from DRAM, `sw/tests/bare-metal/hostd/helloworld.car.dram.elf` +can instead be built from the same source. Depending on their assumptions and behavior, not all +programs may be built to execute from all locations. + +### GPOS (e.g., Linux) programs + +When executing *host domain* programs on a GPOS such as Linux (on FPGA/ASIC targets) requiring +access to memory mapped components of other domains, SW intervention is needed to map virtual to +physical addresses, since domains different than the host *currently* lack support for HW-based +virtual memory translation. + +In the current SW stack, this mapping is already provided and hence transparent to the user. For +example, test programs targeting Linux that require it are located in different folder, +`sw/tests/linux/`. + +## Inter-domain offload + +Offload of programs to Carfield domains involves: + +* An *offloader*, typically one of the two controllers, i.e., the *host* or *safe* domains +* A *target device*, typically the *accelerator domain*. The *safe domain* can also play the role of + target device when offloaded RTOS payloads from the *host domain*. + +Programs can be offloaded with: + +* **Simple baremetal offload (BMO)**, useful for regression tests that are simple enough to be + executed with cycle-accurate RTL simulations. For instance, this can be the case of dynamic timing + analysis (DTA) carried out during an ASIC development cycle. + +* **The [OpenMP](https://www.openmp.org/) API**, recommended when developing SW for Carfield on a + FPGA or, eventually, ASIC implementing Carfield, because of the ready-to-use OS support + (currently, Linux). Note that usage of the OpenMP API with non OS-directed (baremetal) SW can be + supported, and would eventually replace the BMO described above. + +In the following, we briefly describe both. + +--- + +**Note for the reader** + +Since by default all domains are clock gated and isolated after POR except for the *host domain* +(Cheshire), as described in [Architecture](../um/arch.md), the wake-up process must be handled from +the application source code. + +### Baremetal offload (non OpenMP based) + +For BMO, the offloader takes care of bootstrapping the target device ELF in the correct memory +location, initializing the target and launching its execution through a simple ELF Loader. The ELF +Loader source code is located in the offloader's SW directory, and follows a naming convention: + +``` +_offloader_.c +``` + +The target device's ELF is included into the offloader's ELF Loader as a *header file*. The target +device's ELF sections are first pre-processed offline to extract instruction addresses.The resulting +header file provides the ELF loading process at the selected memory location. The loading process +can be carried out by the offloader as R/W sequences, or deferred to a DMA-driven memcopy. In +addition, the offloader takes care of bootstrapping the target device, i.e. initializing it and +launching its execution. + +Upon target device completion, the offloader: + +* Is asynchronously notified of the event via a mailboxe interrupt; BMOs of this kind are called + *non-blocking* +* Sychronously polls a specific register to catch the completion; BMOs of this kind are called + *blocking* + +Currently, *blocking BMO* is implemented. + +--- + +As an example, assume the *host domain* as offloader and the *integer PMCA* as target device. + +1. The host domain ELF Loader is included in `sw/tests/bare-metal/hostd` +1. A header file is generated out of each regression test available in the integer PMCA repository. + For this example, the resulting header files are included in `sw/tests/bare-metal/pulpd` +2. The final ELF executed by the offloader is created by subsequently including each header file + from each integer PMCA regression test + +The resulting offloader ELF's name reads: + +``` +_offloader_..car..elf +``` + +According to the memory location where the BMP will be executed. + +The final offloader ELF can be preloaded with simulation methods described in the +[Simulation](../tg/sim.md) section, and can be built again as explained above. + +--- + +**Note for the reader** + +BMO is in general not recommended for developing SW for Carfield, as it was introduced during ASIC +development cycle and can be an effective litmus test to find and fix HW bugs, or during DTA. + +For SW development on Carfield and in particular domain-driven offload, it is recommended to use +OpenMP offload on FPGA/ASIC, described below. The latter will eventually replace the simple BMO also +for baremetal regression checks in future releases of the project. + +### OpenMP offload (recommended: use on FPGA/ASIC) + +TODO Cyril + +## External benchmarks + +We support several external benchmarks, whose build flow has been slightly adapted to align with +Carfield's. Currently, they are: + +* [Mibench, a free, commercially representative embedded benchmark + suite](https://ieeexplore.ieee.org/document/990739) diff --git a/hw/regs/pcr.md b/hw/regs/pcr.md new file mode 100644 index 00000000..d4e1fa9e --- /dev/null +++ b/hw/regs/pcr.md @@ -0,0 +1,1126 @@ +## Summary + +| Name | Offset | Length | Description | +|:-----------------------------------------------------------------------------|:---------|---------:|:-----------------------------------------------------------------------| +| carfield.[`VERSION0`](#version0) | 0x0 | 4 | Cheshire sha256 commit | +| carfield.[`VERSION1`](#version1) | 0x4 | 4 | Safety Island sha256 commit | +| carfield.[`VERSION2`](#version2) | 0x8 | 4 | Security Island sha256 commit | +| carfield.[`VERSION3`](#version3) | 0xc | 4 | PULP Cluster sha256 commit | +| carfield.[`VERSION4`](#version4) | 0x10 | 4 | Spatz CLuster sha256 commit | +| carfield.[`JEDEC_IDCODE`](#jedec_idcode) | 0x14 | 4 | JEDEC ID CODE -TODO assign- | +| carfield.[`GENERIC_SCRATCH0`](#generic_scratch0) | 0x18 | 4 | Scratch | +| carfield.[`GENERIC_SCRATCH1`](#generic_scratch1) | 0x1c | 4 | Scratch | +| carfield.[`HOST_RST`](#host_rst) | 0x20 | 4 | Host Domain reset -active high, inverted in HW- | +| carfield.[`PERIPH_RST`](#periph_rst) | 0x24 | 4 | Periph Domain reset -active high, inverted in HW- | +| carfield.[`SAFETY_ISLAND_RST`](#safety_island_rst) | 0x28 | 4 | Safety Island reset -active high, inverted in HW- | +| carfield.[`SECURITY_ISLAND_RST`](#security_island_rst) | 0x2c | 4 | Security Island reset -active high, inverted in HW- | +| carfield.[`PULP_CLUSTER_RST`](#pulp_cluster_rst) | 0x30 | 4 | PULP Cluster reset -active high, inverted in HW- | +| carfield.[`SPATZ_CLUSTER_RST`](#spatz_cluster_rst) | 0x34 | 4 | Spatz Cluster reset -active high, inverted in HW- | +| carfield.[`L2_RST`](#l2_rst) | 0x38 | 4 | L2 reset -active high, inverted in HW- | +| carfield.[`PERIPH_ISOLATE`](#periph_isolate) | 0x3c | 4 | Periph Domain AXI isolate | +| carfield.[`SAFETY_ISLAND_ISOLATE`](#safety_island_isolate) | 0x40 | 4 | Safety Island AXI isolate | +| carfield.[`SECURITY_ISLAND_ISOLATE`](#security_island_isolate) | 0x44 | 4 | Security Island AXI isolate | +| carfield.[`PULP_CLUSTER_ISOLATE`](#pulp_cluster_isolate) | 0x48 | 4 | PULP Cluster AXI isolate | +| carfield.[`SPATZ_CLUSTER_ISOLATE`](#spatz_cluster_isolate) | 0x4c | 4 | Spatz Cluster AXI isolate | +| carfield.[`L2_ISOLATE`](#l2_isolate) | 0x50 | 4 | L2 AXI isolate | +| carfield.[`PERIPH_ISOLATE_STATUS`](#periph_isolate_status) | 0x54 | 4 | Periph Domain AXI isolate status | +| carfield.[`SAFETY_ISLAND_ISOLATE_STATUS`](#safety_island_isolate_status) | 0x58 | 4 | Safety Island AXI isolate status | +| carfield.[`SECURITY_ISLAND_ISOLATE_STATUS`](#security_island_isolate_status) | 0x5c | 4 | Security Island AXI isolate status | +| carfield.[`PULP_CLUSTER_ISOLATE_STATUS`](#pulp_cluster_isolate_status) | 0x60 | 4 | PULP Cluster AXI isolate status | +| carfield.[`SPATZ_CLUSTER_ISOLATE_STATUS`](#spatz_cluster_isolate_status) | 0x64 | 4 | Spatz Cluster AXI isolate status | +| carfield.[`L2_ISOLATE_STATUS`](#l2_isolate_status) | 0x68 | 4 | L2 AXI isolate status | +| carfield.[`PERIPH_CLK_EN`](#periph_clk_en) | 0x6c | 4 | Periph Domain clk gate enable | +| carfield.[`SAFETY_ISLAND_CLK_EN`](#safety_island_clk_en) | 0x70 | 4 | Safety Island clk gate enable | +| carfield.[`SECURITY_ISLAND_CLK_EN`](#security_island_clk_en) | 0x74 | 4 | Security Island clk gate enable | +| carfield.[`PULP_CLUSTER_CLK_EN`](#pulp_cluster_clk_en) | 0x78 | 4 | PULP Cluster clk gate enable | +| carfield.[`SPATZ_CLUSTER_CLK_EN`](#spatz_cluster_clk_en) | 0x7c | 4 | Spatz Cluster clk gate enable | +| carfield.[`L2_CLK_EN`](#l2_clk_en) | 0x80 | 4 | Shared L2 memory clk gate enable | +| carfield.[`PERIPH_CLK_SEL`](#periph_clk_sel) | 0x84 | 4 | Periph Domain pll select (0 -> host pll, 1 -> alt PLL, 2 -> per pll) | +| carfield.[`SAFETY_ISLAND_CLK_SEL`](#safety_island_clk_sel) | 0x88 | 4 | Safety Island pll select (0 -> host pll, 1 -> alt PLL, 2 -> per pll) | +| carfield.[`SECURITY_ISLAND_CLK_SEL`](#security_island_clk_sel) | 0x8c | 4 | Security Island pll select (0 -> host pll, 1 -> alt PLL, 2 -> per pll) | +| carfield.[`PULP_CLUSTER_CLK_SEL`](#pulp_cluster_clk_sel) | 0x90 | 4 | PULP Cluster pll select (0 -> host pll, 1 -> alt PLL, 2 -> per pll) | +| carfield.[`SPATZ_CLUSTER_CLK_SEL`](#spatz_cluster_clk_sel) | 0x94 | 4 | Spatz Cluster pll select (0 -> host pll, 1 -> alt PLL, 2 -> per pll) | +| carfield.[`L2_CLK_SEL`](#l2_clk_sel) | 0x98 | 4 | L2 Memory pll select (0 -> host pll, 1 -> alt PLL, 2 -> per pll) | +| carfield.[`PERIPH_CLK_DIV_VALUE`](#periph_clk_div_value) | 0x9c | 4 | Periph Domain clk divider value | +| carfield.[`SAFETY_ISLAND_CLK_DIV_VALUE`](#safety_island_clk_div_value) | 0xa0 | 4 | Safety Island clk divider value | +| carfield.[`SECURITY_ISLAND_CLK_DIV_VALUE`](#security_island_clk_div_value) | 0xa4 | 4 | Security Island clk divider value | +| carfield.[`PULP_CLUSTER_CLK_DIV_VALUE`](#pulp_cluster_clk_div_value) | 0xa8 | 4 | PULP Cluster clk divider value | +| carfield.[`SPATZ_CLUSTER_CLK_DIV_VALUE`](#spatz_cluster_clk_div_value) | 0xac | 4 | Spatz Cluster clk divider value | +| carfield.[`L2_CLK_DIV_VALUE`](#l2_clk_div_value) | 0xb0 | 4 | L2 Memory clk divider value | +| carfield.[`HOST_FETCH_ENABLE`](#host_fetch_enable) | 0xb4 | 4 | Host Domain fetch enable | +| carfield.[`SAFETY_ISLAND_FETCH_ENABLE`](#safety_island_fetch_enable) | 0xb8 | 4 | Safety Island fetch enable | +| carfield.[`SECURITY_ISLAND_FETCH_ENABLE`](#security_island_fetch_enable) | 0xbc | 4 | Security Island fetch enable | +| carfield.[`PULP_CLUSTER_FETCH_ENABLE`](#pulp_cluster_fetch_enable) | 0xc0 | 4 | PULP Cluster fetch enable | +| carfield.[`SPATZ_CLUSTER_DEBUG_REQ`](#spatz_cluster_debug_req) | 0xc4 | 4 | Spatz Cluster debug req | +| carfield.[`HOST_BOOT_ADDR`](#host_boot_addr) | 0xc8 | 4 | Host boot address | +| carfield.[`SAFETY_ISLAND_BOOT_ADDR`](#safety_island_boot_addr) | 0xcc | 4 | Safety Island boot address | +| carfield.[`SECURITY_ISLAND_BOOT_ADDR`](#security_island_boot_addr) | 0xd0 | 4 | Security Island boot address | +| carfield.[`PULP_CLUSTER_BOOT_ADDR`](#pulp_cluster_boot_addr) | 0xd4 | 4 | PULP Cluster boot address | +| carfield.[`SPATZ_CLUSTER_BOOT_ADDR`](#spatz_cluster_boot_addr) | 0xd8 | 4 | Spatz Cluster boot address | +| carfield.[`PULP_CLUSTER_BOOT_ENABLE`](#pulp_cluster_boot_enable) | 0xdc | 4 | PULP Cluster boot enable | +| carfield.[`SPATZ_CLUSTER_BUSY`](#spatz_cluster_busy) | 0xe0 | 4 | Spatz Cluster busy | +| carfield.[`PULP_CLUSTER_BUSY`](#pulp_cluster_busy) | 0xe4 | 4 | PULP Cluster busy | +| carfield.[`PULP_CLUSTER_EOC`](#pulp_cluster_eoc) | 0xe8 | 4 | PULP Cluster end of computation | +| carfield.[`ETH_RGMII_PHY_CLK_DIV_EN`](#eth_rgmii_phy_clk_div_en) | 0xec | 4 | Ethernet RGMII PHY clock divider enable bit | +| carfield.[`ETH_RGMII_PHY_CLK_DIV_VALUE`](#eth_rgmii_phy_clk_div_value) | 0xf0 | 4 | Ethernet RGMII PHY clock divider value | +| carfield.[`ETH_MDIO_CLK_DIV_EN`](#eth_mdio_clk_div_en) | 0xf4 | 4 | Ethernet MDIO clock divider enable bit | +| carfield.[`ETH_MDIO_CLK_DIV_VALUE`](#eth_mdio_clk_div_value) | 0xf8 | 4 | Ethernet MDIO clock divider value | + +## VERSION0 +Cheshire sha256 commit +- Offset: `0x0` +- Reset default: `0x0` +- Reset mask: `0xffffffff` + +### Fields + +```wavejson +{"reg": [{"name": "VERSION0", "bits": 32, "attr": ["ro"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:---------|:--------------| +| 31:0 | ro | 0x0 | VERSION0 | | + +## VERSION1 +Safety Island sha256 commit +- Offset: `0x4` +- Reset default: `0x0` +- Reset mask: `0xffffffff` + +### Fields + +```wavejson +{"reg": [{"name": "VERSION1", "bits": 32, "attr": ["ro"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:---------|:--------------| +| 31:0 | ro | 0x0 | VERSION1 | | + +## VERSION2 +Security Island sha256 commit +- Offset: `0x8` +- Reset default: `0x0` +- Reset mask: `0xffffffff` + +### Fields + +```wavejson +{"reg": [{"name": "VERSION2", "bits": 32, "attr": ["ro"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:---------|:--------------| +| 31:0 | ro | 0x0 | VERSION2 | | + +## VERSION3 +PULP Cluster sha256 commit +- Offset: `0xc` +- Reset default: `0x0` +- Reset mask: `0xffffffff` + +### Fields + +```wavejson +{"reg": [{"name": "VERSION3", "bits": 32, "attr": ["ro"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:---------|:--------------| +| 31:0 | ro | 0x0 | VERSION3 | | + +## VERSION4 +Spatz CLuster sha256 commit +- Offset: `0x10` +- Reset default: `0x0` +- Reset mask: `0xffffffff` + +### Fields + +```wavejson +{"reg": [{"name": "VERSION4", "bits": 32, "attr": ["ro"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:---------|:--------------| +| 31:0 | ro | 0x0 | VERSION4 | | + +## JEDEC_IDCODE +JEDEC ID CODE -TODO assign- +- Offset: `0x14` +- Reset default: `0x0` +- Reset mask: `0xffffffff` + +### Fields + +```wavejson +{"reg": [{"name": "JEDEC_IDCODE", "bits": 32, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-------------|:--------------| +| 31:0 | rw | 0x0 | JEDEC_IDCODE | | + +## GENERIC_SCRATCH0 +Scratch +- Offset: `0x18` +- Reset default: `0x0` +- Reset mask: `0xffffffff` + +### Fields + +```wavejson +{"reg": [{"name": "GENERIC_SCRATCH0", "bits": 32, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-----------------|:--------------| +| 31:0 | rw | 0x0 | GENERIC_SCRATCH0 | | + +## GENERIC_SCRATCH1 +Scratch +- Offset: `0x1c` +- Reset default: `0x0` +- Reset mask: `0xffffffff` + +### Fields + +```wavejson +{"reg": [{"name": "GENERIC_SCRATCH1", "bits": 32, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-----------------|:--------------| +| 31:0 | rw | 0x0 | GENERIC_SCRATCH1 | | + +## HOST_RST +Host Domain reset -active high, inverted in HW- +- Offset: `0x20` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "HOST_RST", "bits": 1, "attr": ["ro"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 100}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:---------|:--------------| +| 31:1 | | | | Reserved | +| 0 | ro | 0x0 | HOST_RST | | + +## PERIPH_RST +Periph Domain reset -active high, inverted in HW- +- Offset: `0x24` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "PERIPH_RST", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 120}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-----------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x0 | PERIPH_RST | | + +## SAFETY_ISLAND_RST +Safety Island reset -active high, inverted in HW- +- Offset: `0x28` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "SAFETY_ISLAND_RST", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 190}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:------------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x0 | SAFETY_ISLAND_RST | | + +## SECURITY_ISLAND_RST +Security Island reset -active high, inverted in HW- +- Offset: `0x2c` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "SECURITY_ISLAND_RST", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 210}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:--------------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x0 | SECURITY_ISLAND_RST | | + +## PULP_CLUSTER_RST +PULP Cluster reset -active high, inverted in HW- +- Offset: `0x30` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "PULP_CLUSTER_RST", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 180}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-----------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x0 | PULP_CLUSTER_RST | | + +## SPATZ_CLUSTER_RST +Spatz Cluster reset -active high, inverted in HW- +- Offset: `0x34` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "SPATZ_CLUSTER_RST", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 190}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:------------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x0 | SPATZ_CLUSTER_RST | | + +## L2_RST +L2 reset -active high, inverted in HW- +- Offset: `0x38` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "L2_RST", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x0 | L2_RST | | + +## PERIPH_ISOLATE +Periph Domain AXI isolate +- Offset: `0x3c` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "PERIPH_ISOLATE", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 160}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:---------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x0 | PERIPH_ISOLATE | | + +## SAFETY_ISLAND_ISOLATE +Safety Island AXI isolate +- Offset: `0x40` +- Reset default: `0x1` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "SAFETY_ISLAND_ISOLATE", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 230}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:----------------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x1 | SAFETY_ISLAND_ISOLATE | | + +## SECURITY_ISLAND_ISOLATE +Security Island AXI isolate +- Offset: `0x44` +- Reset default: `0x1` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "SECURITY_ISLAND_ISOLATE", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 250}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:------------------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x1 | SECURITY_ISLAND_ISOLATE | | + +## PULP_CLUSTER_ISOLATE +PULP Cluster AXI isolate +- Offset: `0x48` +- Reset default: `0x1` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "PULP_CLUSTER_ISOLATE", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 220}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:---------------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x1 | PULP_CLUSTER_ISOLATE | | + +## SPATZ_CLUSTER_ISOLATE +Spatz Cluster AXI isolate +- Offset: `0x4c` +- Reset default: `0x1` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "SPATZ_CLUSTER_ISOLATE", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 230}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:----------------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x1 | SPATZ_CLUSTER_ISOLATE | | + +## L2_ISOLATE +L2 AXI isolate +- Offset: `0x50` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "L2_ISOLATE", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 120}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-----------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x0 | L2_ISOLATE | | + +## PERIPH_ISOLATE_STATUS +Periph Domain AXI isolate status +- Offset: `0x54` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "PERIPH_ISOLATE_STATUS", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 230}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:----------------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x0 | PERIPH_ISOLATE_STATUS | | + +## SAFETY_ISLAND_ISOLATE_STATUS +Safety Island AXI isolate status +- Offset: `0x58` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "SAFETY_ISLAND_ISOLATE_STATUS", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 300}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-----------------------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x0 | SAFETY_ISLAND_ISOLATE_STATUS | | + +## SECURITY_ISLAND_ISOLATE_STATUS +Security Island AXI isolate status +- Offset: `0x5c` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "SECURITY_ISLAND_ISOLATE_STATUS", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 320}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-------------------------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x0 | SECURITY_ISLAND_ISOLATE_STATUS | | + +## PULP_CLUSTER_ISOLATE_STATUS +PULP Cluster AXI isolate status +- Offset: `0x60` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "PULP_CLUSTER_ISOLATE_STATUS", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 290}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:----------------------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x0 | PULP_CLUSTER_ISOLATE_STATUS | | + +## SPATZ_CLUSTER_ISOLATE_STATUS +Spatz Cluster AXI isolate status +- Offset: `0x64` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "SPATZ_CLUSTER_ISOLATE_STATUS", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 300}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-----------------------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x0 | SPATZ_CLUSTER_ISOLATE_STATUS | | + +## L2_ISOLATE_STATUS +L2 AXI isolate status +- Offset: `0x68` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "L2_ISOLATE_STATUS", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 190}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:------------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x0 | L2_ISOLATE_STATUS | | + +## PERIPH_CLK_EN +Periph Domain clk gate enable +- Offset: `0x6c` +- Reset default: `0x1` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "PERIPH_CLK_EN", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 150}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:--------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x1 | PERIPH_CLK_EN | | + +## SAFETY_ISLAND_CLK_EN +Safety Island clk gate enable +- Offset: `0x70` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "SAFETY_ISLAND_CLK_EN", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 220}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:---------------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x0 | SAFETY_ISLAND_CLK_EN | | + +## SECURITY_ISLAND_CLK_EN +Security Island clk gate enable +- Offset: `0x74` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "SECURITY_ISLAND_CLK_EN", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 240}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-----------------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x0 | SECURITY_ISLAND_CLK_EN | | + +## PULP_CLUSTER_CLK_EN +PULP Cluster clk gate enable +- Offset: `0x78` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "PULP_CLUSTER_CLK_EN", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 210}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:--------------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x0 | PULP_CLUSTER_CLK_EN | | + +## SPATZ_CLUSTER_CLK_EN +Spatz Cluster clk gate enable +- Offset: `0x7c` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "SPATZ_CLUSTER_CLK_EN", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 220}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:---------------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x0 | SPATZ_CLUSTER_CLK_EN | | + +## L2_CLK_EN +Shared L2 memory clk gate enable +- Offset: `0x80` +- Reset default: `0x1` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "L2_CLK_EN", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 110}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:----------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x1 | L2_CLK_EN | | + +## PERIPH_CLK_SEL +Periph Domain pll select (0 -> host pll, 1 -> alt PLL, 2 -> per pll) +- Offset: `0x84` +- Reset default: `0x2` +- Reset mask: `0x3` + +### Fields + +```wavejson +{"reg": [{"name": "PERIPH_CLK_SEL", "bits": 2, "attr": ["rw"], "rotate": -90}, {"bits": 30}], "config": {"lanes": 1, "fontsize": 10, "vspace": 160}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:---------------|:--------------| +| 31:2 | | | | Reserved | +| 1:0 | rw | 0x2 | PERIPH_CLK_SEL | | + +## SAFETY_ISLAND_CLK_SEL +Safety Island pll select (0 -> host pll, 1 -> alt PLL, 2 -> per pll) +- Offset: `0x88` +- Reset default: `0x1` +- Reset mask: `0x3` + +### Fields + +```wavejson +{"reg": [{"name": "SAFETY_ISLAND_CLK_SEL", "bits": 2, "attr": ["rw"], "rotate": -90}, {"bits": 30}], "config": {"lanes": 1, "fontsize": 10, "vspace": 230}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:----------------------|:--------------| +| 31:2 | | | | Reserved | +| 1:0 | rw | 0x1 | SAFETY_ISLAND_CLK_SEL | | + +## SECURITY_ISLAND_CLK_SEL +Security Island pll select (0 -> host pll, 1 -> alt PLL, 2 -> per pll) +- Offset: `0x8c` +- Reset default: `0x1` +- Reset mask: `0x3` + +### Fields + +```wavejson +{"reg": [{"name": "SECURITY_ISLAND_CLK_SEL", "bits": 2, "attr": ["rw"], "rotate": -90}, {"bits": 30}], "config": {"lanes": 1, "fontsize": 10, "vspace": 250}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:------------------------|:--------------| +| 31:2 | | | | Reserved | +| 1:0 | rw | 0x1 | SECURITY_ISLAND_CLK_SEL | | + +## PULP_CLUSTER_CLK_SEL +PULP Cluster pll select (0 -> host pll, 1 -> alt PLL, 2 -> per pll) +- Offset: `0x90` +- Reset default: `0x1` +- Reset mask: `0x3` + +### Fields + +```wavejson +{"reg": [{"name": "PULP_CLUSTER_CLK_SEL", "bits": 2, "attr": ["rw"], "rotate": -90}, {"bits": 30}], "config": {"lanes": 1, "fontsize": 10, "vspace": 220}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:---------------------|:--------------| +| 31:2 | | | | Reserved | +| 1:0 | rw | 0x1 | PULP_CLUSTER_CLK_SEL | | + +## SPATZ_CLUSTER_CLK_SEL +Spatz Cluster pll select (0 -> host pll, 1 -> alt PLL, 2 -> per pll) +- Offset: `0x94` +- Reset default: `0x1` +- Reset mask: `0x3` + +### Fields + +```wavejson +{"reg": [{"name": "SPATZ_CLUSTER_CLK_SEL", "bits": 2, "attr": ["rw"], "rotate": -90}, {"bits": 30}], "config": {"lanes": 1, "fontsize": 10, "vspace": 230}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:----------------------|:--------------| +| 31:2 | | | | Reserved | +| 1:0 | rw | 0x1 | SPATZ_CLUSTER_CLK_SEL | | + +## L2_CLK_SEL +L2 Memory pll select (0 -> host pll, 1 -> alt PLL, 2 -> per pll) +- Offset: `0x98` +- Reset default: `0x1` +- Reset mask: `0x3` + +### Fields + +```wavejson +{"reg": [{"name": "L2_CLK_SEL", "bits": 2, "attr": ["rw"], "rotate": -90}, {"bits": 30}], "config": {"lanes": 1, "fontsize": 10, "vspace": 120}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-----------|:--------------| +| 31:2 | | | | Reserved | +| 1:0 | rw | 0x1 | L2_CLK_SEL | | + +## PERIPH_CLK_DIV_VALUE +Periph Domain clk divider value +- Offset: `0x9c` +- Reset default: `0x1` +- Reset mask: `0xffffff` + +### Fields + +```wavejson +{"reg": [{"name": "PERIPH_CLK_DIV_VALUE", "bits": 24, "attr": ["rw"], "rotate": 0}, {"bits": 8}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:---------------------|:--------------| +| 31:24 | | | | Reserved | +| 23:0 | rw | 0x1 | PERIPH_CLK_DIV_VALUE | | + +## SAFETY_ISLAND_CLK_DIV_VALUE +Safety Island clk divider value +- Offset: `0xa0` +- Reset default: `0x1` +- Reset mask: `0xffffff` + +### Fields + +```wavejson +{"reg": [{"name": "SAFETY_ISLAND_CLK_DIV_VALUE", "bits": 24, "attr": ["rw"], "rotate": 0}, {"bits": 8}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:----------------------------|:--------------| +| 31:24 | | | | Reserved | +| 23:0 | rw | 0x1 | SAFETY_ISLAND_CLK_DIV_VALUE | | + +## SECURITY_ISLAND_CLK_DIV_VALUE +Security Island clk divider value +- Offset: `0xa4` +- Reset default: `0x1` +- Reset mask: `0xffffff` + +### Fields + +```wavejson +{"reg": [{"name": "SECURITY_ISLAND_CLK_DIV_VALUE", "bits": 24, "attr": ["rw"], "rotate": 0}, {"bits": 8}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:------------------------------|:--------------| +| 31:24 | | | | Reserved | +| 23:0 | rw | 0x1 | SECURITY_ISLAND_CLK_DIV_VALUE | | + +## PULP_CLUSTER_CLK_DIV_VALUE +PULP Cluster clk divider value +- Offset: `0xa8` +- Reset default: `0x1` +- Reset mask: `0xffffff` + +### Fields + +```wavejson +{"reg": [{"name": "PULP_CLUSTER_CLK_DIV_VALUE", "bits": 24, "attr": ["rw"], "rotate": 0}, {"bits": 8}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:---------------------------|:--------------| +| 31:24 | | | | Reserved | +| 23:0 | rw | 0x1 | PULP_CLUSTER_CLK_DIV_VALUE | | + +## SPATZ_CLUSTER_CLK_DIV_VALUE +Spatz Cluster clk divider value +- Offset: `0xac` +- Reset default: `0x1` +- Reset mask: `0xffffff` + +### Fields + +```wavejson +{"reg": [{"name": "SPATZ_CLUSTER_CLK_DIV_VALUE", "bits": 24, "attr": ["rw"], "rotate": 0}, {"bits": 8}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:----------------------------|:--------------| +| 31:24 | | | | Reserved | +| 23:0 | rw | 0x1 | SPATZ_CLUSTER_CLK_DIV_VALUE | | + +## L2_CLK_DIV_VALUE +L2 Memory clk divider value +- Offset: `0xb0` +- Reset default: `0x1` +- Reset mask: `0xffffff` + +### Fields + +```wavejson +{"reg": [{"name": "L2_CLK_DIV_VALUE", "bits": 24, "attr": ["rw"], "rotate": 0}, {"bits": 8}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-----------------|:--------------| +| 31:24 | | | | Reserved | +| 23:0 | rw | 0x1 | L2_CLK_DIV_VALUE | | + +## HOST_FETCH_ENABLE +Host Domain fetch enable +- Offset: `0xb4` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "HOST_FETCH_ENABLE", "bits": 1, "attr": ["ro"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 190}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:------------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | ro | 0x0 | HOST_FETCH_ENABLE | | + +## SAFETY_ISLAND_FETCH_ENABLE +Safety Island fetch enable +- Offset: `0xb8` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "SAFETY_ISLAND_FETCH_ENABLE", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 280}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:---------------------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x0 | SAFETY_ISLAND_FETCH_ENABLE | | + +## SECURITY_ISLAND_FETCH_ENABLE +Security Island fetch enable +- Offset: `0xbc` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "SECURITY_ISLAND_FETCH_ENABLE", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 300}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-----------------------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x0 | SECURITY_ISLAND_FETCH_ENABLE | | + +## PULP_CLUSTER_FETCH_ENABLE +PULP Cluster fetch enable +- Offset: `0xc0` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "PULP_CLUSTER_FETCH_ENABLE", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 270}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:--------------------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x0 | PULP_CLUSTER_FETCH_ENABLE | | + +## SPATZ_CLUSTER_DEBUG_REQ +Spatz Cluster debug req +- Offset: `0xc4` +- Reset default: `0x0` +- Reset mask: `0x3` + +### Fields + +```wavejson +{"reg": [{"name": "SPATZ_CLUSTER_DEBUG_REQ", "bits": 2, "attr": ["rw"], "rotate": -90}, {"bits": 30}], "config": {"lanes": 1, "fontsize": 10, "vspace": 250}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:------------------------|:--------------| +| 31:2 | | | | Reserved | +| 1:0 | rw | 0x0 | SPATZ_CLUSTER_DEBUG_REQ | | + +## HOST_BOOT_ADDR +Host boot address +- Offset: `0xc8` +- Reset default: `0x1000` +- Reset mask: `0xffffffff` + +### Fields + +```wavejson +{"reg": [{"name": "HOST_BOOT_ADDR", "bits": 32, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:---------------|:--------------| +| 31:0 | rw | 0x1000 | HOST_BOOT_ADDR | | + +## SAFETY_ISLAND_BOOT_ADDR +Safety Island boot address +- Offset: `0xcc` +- Reset default: `0x70000000` +- Reset mask: `0xffffffff` + +### Fields + +```wavejson +{"reg": [{"name": "SAFETY_ISLAND_BOOT_ADDR", "bits": 32, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:----------:|:------------------------|:--------------| +| 31:0 | rw | 0x70000000 | SAFETY_ISLAND_BOOT_ADDR | | + +## SECURITY_ISLAND_BOOT_ADDR +Security Island boot address +- Offset: `0xd0` +- Reset default: `0x70000000` +- Reset mask: `0xffffffff` + +### Fields + +```wavejson +{"reg": [{"name": "SECURITY_ISLAND_BOOT_ADDR", "bits": 32, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:----------:|:--------------------------|:--------------| +| 31:0 | rw | 0x70000000 | SECURITY_ISLAND_BOOT_ADDR | | + +## PULP_CLUSTER_BOOT_ADDR +PULP Cluster boot address +- Offset: `0xd4` +- Reset default: `0x70000000` +- Reset mask: `0xffffffff` + +### Fields + +```wavejson +{"reg": [{"name": "PULP_CLUSTER_BOOT_ADDR", "bits": 32, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:----------:|:-----------------------|:--------------| +| 31:0 | rw | 0x70000000 | PULP_CLUSTER_BOOT_ADDR | | + +## SPATZ_CLUSTER_BOOT_ADDR +Spatz Cluster boot address +- Offset: `0xd8` +- Reset default: `0x70000000` +- Reset mask: `0xffffffff` + +### Fields + +```wavejson +{"reg": [{"name": "SPATZ_CLUSTER_BOOT_ADDR", "bits": 32, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:----------:|:------------------------|:--------------| +| 31:0 | rw | 0x70000000 | SPATZ_CLUSTER_BOOT_ADDR | | + +## PULP_CLUSTER_BOOT_ENABLE +PULP Cluster boot enable +- Offset: `0xdc` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "PULP_CLUSTER_BOOT_ENABLE", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 260}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-------------------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x0 | PULP_CLUSTER_BOOT_ENABLE | | + +## SPATZ_CLUSTER_BUSY +Spatz Cluster busy +- Offset: `0xe0` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "SPATZ_CLUSTER_BUSY", "bits": 1, "attr": ["ro"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 200}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-------------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | ro | 0x0 | SPATZ_CLUSTER_BUSY | | + +## PULP_CLUSTER_BUSY +PULP Cluster busy +- Offset: `0xe4` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "PULP_CLUSTER_BUSY", "bits": 1, "attr": ["ro"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 190}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:------------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | ro | 0x0 | PULP_CLUSTER_BUSY | | + +## PULP_CLUSTER_EOC +PULP Cluster end of computation +- Offset: `0xe8` +- Reset default: `0x0` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "PULP_CLUSTER_EOC", "bits": 1, "attr": ["ro"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 180}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-----------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | ro | 0x0 | PULP_CLUSTER_EOC | | + +## ETH_RGMII_PHY_CLK_DIV_EN +Ethernet RGMII PHY clock divider enable bit +- Offset: `0xec` +- Reset default: `0x1` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "ETH_RGMII_PHY_CLK_DIV_EN", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 260}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-------------------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x1 | ETH_RGMII_PHY_CLK_DIV_EN | | + +## ETH_RGMII_PHY_CLK_DIV_VALUE +Ethernet RGMII PHY clock divider value +- Offset: `0xf0` +- Reset default: `0x64` +- Reset mask: `0xfffff` + +### Fields + +```wavejson +{"reg": [{"name": "ETH_RGMII_PHY_CLK_DIV_VALUE", "bits": 20, "attr": ["rw"], "rotate": 0}, {"bits": 12}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:----------------------------|:--------------| +| 31:20 | | | | Reserved | +| 19:0 | rw | 0x64 | ETH_RGMII_PHY_CLK_DIV_VALUE | | + +## ETH_MDIO_CLK_DIV_EN +Ethernet MDIO clock divider enable bit +- Offset: `0xf4` +- Reset default: `0x1` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "ETH_MDIO_CLK_DIV_EN", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 210}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:--------------------|:--------------| +| 31:1 | | | | Reserved | +| 0 | rw | 0x1 | ETH_MDIO_CLK_DIV_EN | | + +## ETH_MDIO_CLK_DIV_VALUE +Ethernet MDIO clock divider value +- Offset: `0xf8` +- Reset default: `0x64` +- Reset mask: `0xfffff` + +### Fields + +```wavejson +{"reg": [{"name": "ETH_MDIO_CLK_DIV_VALUE", "bits": 20, "attr": ["rw"], "rotate": 0}, {"bits": 12}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:-----------------------|:--------------| +| 31:20 | | | | Reserved | +| 19:0 | rw | 0x64 | ETH_MDIO_CLK_DIV_VALUE | | + diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 00000000..30a63cd0 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,48 @@ +# Copyright 2020 ETH Zurich and University of Bologna. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +site_name: Carfield +theme: + name: material + icon: + repo: fontawesome/brands/github + features: + - navigation.expand + - navigation.tracking + - navigation.sections + - navigation.indexes + - navigation.footer + +plugins: + - glightbox: + touchNavigation: true + loop: false + effect: zoom + slide_effect: slide + width: 100% + height: auto + zoomable: true + draggable: true + skip_classes: + - custom-skip-class-name + auto_caption: false + caption_position: bottom + +repo_url: https://github.com/pulp-platform/carfield +repo_name: pulp-platform/carfield + +nav: +- Home: + - index.md + - Getting Started: gs.md +- Targets: + - tg/index.md + - Simulation: tg/sim.md + - Synthesis and physical implementation: tg/synth.md + - Xilinx FPGAs: tg/xilinx.md + - Integration: tg/integr.md +- User Manual: + - um/index.md + - Architecture: um/arch.md + - Software Stack: um/sw.md diff --git a/requirements.txt b/requirements.txt index d722a3d7..0deb3737 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,12 @@ Mako==1.1.6 PyYAML==6.0 pandas==1.0.1 pyelftools==0.29 +requests +hjson +mako +pyyaml +tabulate +yapf +mkdocs +mkdocs-material +mkdocs-glightbox From 200bb301d265fb9809b13ab551b74da2300d7120 Mon Sep 17 00:00:00 2001 From: aottaviano Date: Wed, 10 Jan 2024 16:39:05 +0100 Subject: [PATCH 4/5] env: Point to newest questa for internal usage (ETH/UNIBO) --- env/env-iis.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/env/env-iis.sh b/env/env-iis.sh index a4ffb219..1d29154c 100644 --- a/env/env-iis.sh +++ b/env/env-iis.sh @@ -8,4 +8,4 @@ ROOTD=$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")/.." && pwd) export PATH=/usr/pack/riscv-1.0-kgf/riscv64-gcc-11.2.0/bin:$PATH # RV64 GCC toolchain export SAFED_RISCV=/usr/pack/riscv-1.0-kgf/pulp-gcc-2.6.0/bin/riscv32-unknown-elf export PULPD_RISCV=/usr/pack/pulpsdk-1.0-kgf/artifactory/pulp-sdk-release/pkg/pulp_riscv_gcc/1.0.16/bin/riscv32-unknown-elf -export QUESTA=questa-2022.3 +export QUESTA=questa-2023.4 From 24187a078be700b9373be020f3d04e65fadab16c Mon Sep 17 00:00:00 2001 From: aottaviano Date: Wed, 10 Jan 2024 17:50:16 +0100 Subject: [PATCH 5/5] utils: Bump regtool --- utils/reggen/reggen/gen_cfg_md.py | 143 +++++++++++ utils/reggen/reggen/gen_md.py | 336 ++++++++++++++++++++++++++ utils/reggen/reggen/md_helpers.py | 122 ++++++++++ utils/reggen/reggen/multi_register.py | 1 + utils/reggen/regtool.py | 22 +- 5 files changed, 617 insertions(+), 7 deletions(-) create mode 100644 utils/reggen/reggen/gen_cfg_md.py create mode 100644 utils/reggen/reggen/gen_md.py create mode 100644 utils/reggen/reggen/md_helpers.py diff --git a/utils/reggen/reggen/gen_cfg_md.py b/utils/reggen/reggen/gen_cfg_md.py new file mode 100644 index 00000000..f74d02e0 --- /dev/null +++ b/utils/reggen/reggen/gen_cfg_md.py @@ -0,0 +1,143 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +"""Generate markdown documentation for the interfaces of an IpBlock.""" + +from typing import TextIO, List, Tuple, Optional + +from reggen.ip_block import IpBlock +from reggen.md_helpers import ( + title, url, italic, coderef, regref_to_link, name_width, table, list_item, +) + + +def gen_cfg_md(cfgs: IpBlock, output: TextIO, register_file: Optional[str] = None) -> None: + comport_url = url( + "Comportable guideline for peripheral device functionality", + "https://opentitan.org/book/doc/contributing/hw/comportability", + ) + output.write( + f'Referring to the {comport_url}, the module ' + f'{coderef(cfgs.name)} has the following hardware interfaces defined\n', + ) + + list_items: List[str] = [] + tables: List[Tuple[ + str, + List[str], + List[List[str]], + ]] = [] + + # Clocks + primary_clock = cfgs.clocking.primary.clock + assert primary_clock + list_items.append('Primary Clock: ' + coderef(primary_clock)) + + other_clocks = cfgs.clocking.other_clocks() + list_items.append( + "Other Clocks: " + + (", ".join(coderef(clk) for clk in other_clocks) if other_clocks else italic("none")) + ) + + # Bus Interfaces + dev_ports = [coderef(port) for port in cfgs.bus_interfaces.get_port_names(False, True)] + assert dev_ports + list_items.append("Bus Device Interfaces (TL-UL): " + ", ".join(dev_ports)) + + host_ports = [coderef(port) for port in cfgs.bus_interfaces.get_port_names(True, False)] + list_items.append( + "Bus Host Interfaces (TL-UL): " + + (", ".join(host_ports) if host_ports else italic("none")) + ) + + # IO + ios = ([('input', x) for x in cfgs.xputs[1]] + + [('output', x) for x in cfgs.xputs[2]] + + [('inout', x) for x in cfgs.xputs[0]]) + + if not ios: + list_items.append("Peripheral Pins for Chip IO: " + italic("none")) + else: + rows = [ + [name_width(x), direction, regref_to_link(x.desc, register_file)] + for direction, x in ios + ] + tables.append(( + "Peripheral Pins for Chip IO", + ["Pin name", "Direction", "Description"], + rows, + )) + + # Inter-Module Signals + if not cfgs.inter_signals: + list_items.append("Inter-Module Signals: " + italic("none")) + else: + rows = [] + for ims in cfgs.inter_signals: + name = ims.name + pkg_struct = ims.package + "::" + ims.struct if ims.package is not None else ims.struct + sig_type = ims.signal_type + act = ims.act + width = str(ims.width) if ims.width is not None else "1" + desc = ims.desc if ims.desc is not None else "" + rows.append([name, pkg_struct, sig_type, act, width, desc]) + + comportibility_url = ( + "https://opentitan.org/book/doc/contributing/hw/comportability/index.html" + "#inter-signal-handling" + ) + tables.append(( + url("Inter-Module Signals", comportibility_url), + ["Port Name", "Package::Struct", "Type", "Act", "Width", "Description"], + rows, + )) + + # Interrupts + if not cfgs.interrupts: + list_items.append("Interrupts: " + italic("none")) + else: + rows = [ + [name_width(x), x.intr_type.name, regref_to_link(x.desc, register_file)] + for x in cfgs.interrupts + ] + tables.append(( + "Interrupts", + ["Interrupt Name", "Type", "Description"], + rows, + )) + + # Alerts + if not cfgs.alerts: + list_items.append("Security Alerts: " + italic("none")) + else: + rows = [ + [x.name, regref_to_link(x.desc, register_file)] + for x in cfgs.alerts + ] + tables.append(( + "Security Alerts", + ["Alert Name", "Description"], + rows, + )) + + # Countermeasures + if not cfgs.countermeasures: + list_items.append("Security Countermeasures: " + italic("none")) + else: + rows = [ + [cfgs.name.upper() + '.' + str(cm), regref_to_link(cm.desc, register_file)] + for cm in cfgs.countermeasures + ] + tables.append(( + "Security Countermeasures", + ["Countermeasure ID", "Description"], + rows, + )) + + for item in list_items: + output.write(list_item(item)) + + output.write("\n") + + for (table_title, header, rows) in tables: + output.write(title(table_title, 2) + table(header, rows)) \ No newline at end of file diff --git a/utils/reggen/reggen/gen_md.py b/utils/reggen/reggen/gen_md.py new file mode 100644 index 00000000..53724863 --- /dev/null +++ b/utils/reggen/reggen/gen_md.py @@ -0,0 +1,336 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +"""Generate markdown documentation for the registers of an IpBlock.""" + +import json +from typing import List, TextIO, Dict, Any, Optional + +from reggen.ip_block import IpBlock +from reggen.md_helpers import ( + coderef, mono, italic, list_item, table, + regref_to_link, first_line, title, url, wavejson, +) +from reggen.multi_register import MultiRegister +from reggen.reg_block import RegBlock +from reggen.register import Register +from reggen.window import Window + + +def gen_md(block: IpBlock, output: TextIO) -> int: + assert block.reg_blocks + # Handle the case where there's just one interface. + if len(block.reg_blocks) == 1: + rb = next(iter(block.reg_blocks.values())) + gen_md_reg_block(output, rb, block.name, block.regwidth) + return 0 + + # Handle the case where there is more than one device interface and, + # correspondingly, more than one reg block. + for iface_name, rb in block.reg_blocks.items(): + assert iface_name + gen_md_reg_block(output, rb, block.name, block.regwidth, iface_name) + + return 0 + + +def gen_md_reg_block( + output: TextIO, rb: RegBlock, comp: str, width: int, iface_name: Optional[str] = None +) -> None: + if len(rb.entries) == 0: + output.write('This interface does not expose any registers.') + return + + # Generate overview table. + gen_md_register_summary(output, rb.entries, comp, width, iface_name) + + # Generate detailed entries. + for x in rb.entries: + if isinstance(x, Register): + gen_md_register(output, x, comp, width) + elif isinstance(x, MultiRegister): + gen_md_multiregister(output, x, comp, width) + else: + assert isinstance(x, Window) + gen_md_window(output, x, comp, width) + + +def gen_md_register_summary(output: TextIO, entries: List[object], + comp: str, width: int, iface_name: Optional[str] = None) -> None: + + heading = "Summary" if iface_name is None \ + else "Summary of the " + coderef(iface_name) + " interface's registers" + output.write(title(heading, 2)) + + bytew = width // 8 + + header = ["Name", "Offset", "Length", "Description"] + rows: List[List[str]] = [] + + def add_row(name: str, anchor: str, offset: int, length: int, description: str) -> None: + rows.append([ + comp + "." + url(mono(name), "#" + anchor), + hex(offset), + str(length), + first_line(description), + ]) + for entry in entries: + if isinstance(entry, MultiRegister): + is_compact = multireg_is_compact(entry, width) + for reg in entry.regs: + # If multiregisters are compact, each register has it's own section, + # so the anchor should link to a section with the individual register name(s). + # Otherwise, there is one section for the whole multiregister, + # so the anchor should link to a section with the multiregister name. + anchor = reg.name if is_compact else entry.name.lower() + add_row(reg.name, anchor, reg.offset, bytew, reg.desc) + elif isinstance(entry, Window): + length = bytew * entry.items + add_row(entry.name, entry.name.lower(), entry.offset, length, entry.desc) + else: + assert isinstance(entry, Register) + add_row(entry.name, entry.name.lower(), entry.offset, bytew, entry.desc) + + output.write(table(header, rows)) + + +def gen_md_window(output: TextIO, win: Window, comp: str, regwidth: int) -> None: + assert win.name + wname = win.name + + # Word aligned start and end addresses. + start_addr = win.offset + end_addr = start_addr + 4 * win.items - 4 + + output.write( + title(wname, 2) + + win.desc + + "\n\n" + + list_item( + "Word Aligned Offset Range: " + + mono(f"{start_addr:#x}") + + "to" + + mono(f"{end_addr:#x}") + ) + + list_item("Size (words): " + mono(f"{win.items}") + "") + + list_item("Access: " + mono(f"{win.swaccess.key}")) + + list_item( + "Byte writes are " + + (italic("not") if not win.byte_write else "") + + " supported." + ) + + "\n" + ) + + +def multireg_is_compact(mreg: MultiRegister, width: int) -> bool: + # Note that validation guarantees that compacted multiregs only ever have one field. + return mreg.compact and (mreg.reg.fields[0].bits.msb + 1) <= width // 2 + + +def gen_md_multiregister(output: TextIO, mreg: MultiRegister, comp: str, width: int) -> None: + # Check whether this is a compacted multireg, in which case we cannot use + # the general definition of the first register as an example for all other instances. + if multireg_is_compact(mreg, width): + for reg in mreg.regs: + gen_md_register(output, reg, comp, width) + return + + # The general definition of the registers making up this multiregister block. + reg_def = mreg.reg + + # Information + output.write( + title(reg_def.name, 2) + + regref_to_link(reg_def.desc) + + "\n" + + list_item("Reset default: " + mono(f"{reg_def.resval:#x}")) + + list_item("Reset mask: " + mono(f"{reg_def.resmask:#x}")) + ) + + # Instances + output.write("\n" + title("Instances", 3)) + output.write(table( + ["Name", "Offset"], + [[reg.name, hex(reg.offset)] for reg in mreg.regs], + )) + + # Fields + output.write("\n" + title("Fields", 3)) + + # Generate bit-field wavejson. + gen_md_reg_picture(output, reg_def, width) + + # Generate fields + gen_md_reg_fields(output, reg_def, width) + + +def gen_md_register(output: TextIO, reg: Register, comp: str, width: int) -> None: + output.write( + title(reg.name, 2) + + regref_to_link(reg.desc) + + "\n" + + list_item("Offset: " + mono(f"{reg.offset:#x}")) + + list_item("Reset default: " + mono(f"{reg.resval:#x}")) + + list_item("Reset mask: " + mono(f"{reg.resmask:#x}")) + ) + if reg.regwen is not None: + output.write( + list_item("Register enable: " + url(mono(reg.regwen), "#" + reg.regwen.lower())) + ) + + # Fields + output.write("\n" + title("Fields", 3)) + + # Generate bit-field wavejson. + gen_md_reg_picture(output, reg, width) + + # Generate fields + gen_md_reg_fields(output, reg, width) + + +def gen_md_reg_picture(output: TextIO, reg: Register, width: int) -> None: + """Outputs a wavejson description of the register in a markdown code block. + + We use WaveDrom to illustrate the register since we already have a wavejson preprocessor. + The wavejson bit-field is great but has some limitations that make it hard to draw nice picture. + Notably, it does not automatically rotate fields that don't fit + or increase the vertical space if necessary. + As the result, the following code makes some assumptions to decide when to rotate + and to compute the vertical space. + Furthermore, we do not know the horizontal size so we have to fix it, + which mean that the final result might be rescaled on the page. + """ + hspace = 640 + vspace = 80 + fontsize = 10 + lanes = 1 + margin = 10 # margin around text + # estimated size that a character takes + font_adv = 10 + # size of each bit in the picture + bit_width = hspace * lanes / width + + fields: List[Dict[str, Any]] = [] + next_bit = 0 + for field in reg.fields: + fieldlsb = field.bits.lsb + # add an empty field if necessary + if fieldlsb > next_bit: + fields.append({"bits": fieldlsb - next_bit}) + # we need to decide whether to rotate or not + # compute the size needed to draw + need_space = font_adv * len(field.name) + 2 * margin + # if this too large horizontally, rotate + # FIXME this does not account for splitting accross lanes + rotate = 0 + if need_space > bit_width * field.bits.width(): + rotate = -90 + # increase vertical space if needed + vspace = max(vspace, need_space) + + fields.append({ + "name": field.name, + "bits": field.bits.width(), + "attr": [field.swaccess.key], + "rotate": rotate + }) + next_bit = field.bits.msb + 1 + + # add an empty field if necessary + if width > next_bit: + fields.append({"bits": width - next_bit}) + # wavedrom configuration, see https://github.com/wavedrom/bitfield + config = {"lanes": lanes, "fontsize": fontsize, "vspace": vspace} + + json_str = json.dumps({"reg": fields, "config": config}) + output.write(wavejson(json_str)) + + +def gen_md_reg_fields(output: TextIO, reg: Register, width: int) -> None: + # The maximum field description length allowed in a register's field table + MAX_DESCRIPTION_LEN = 250 + + # If any field is an enum or has a long description, + # put fields in their own sections. + field_sections = any( + field.enum is not None or + (field.desc is not None and len(field.desc) > MAX_DESCRIPTION_LEN) + for field in reg.fields + ) + + header = ["Bits", "Type", "Reset", "Name"] + colalign = ["center", "center", "center", "left"] + # If generating field sections, the description of fields will not be put in the table. + if not field_sections: + header.append("Description") + colalign.append("left") + + def reserved_row(msb: int, lsb: int) -> List[str]: + return ( + ([f"{msb}:{lsb}"] if msb != lsb else [str(msb)]) + + (["", "", ""] if not field_sections else ["", ""]) + + ["Reserved"] + ) + + rows = [] + nextbit = width - 1 + for field in reversed(reg.fields): + fname = field.name + msb = field.bits.msb + + # Insert a row for any reserved bits before this field + if nextbit > msb: + rows.append(reserved_row(nextbit, msb + 1)) + + row = [ + field.bits.as_str(), + field.swaccess.key, + 'x' if field.resval is None else hex(field.resval), + ] + # If generating field sections, just add the name with a link to it's section. + if field_sections: + row.append(url(fname, f"#{reg.name.lower()}--{fname.lower()}")) + # Otherwise, add the name and description to the table. + else: + row.extend([fname, "" if field.desc is None else regref_to_link(field.desc)]) + + rows.append(row) + + nextbit = field.bits.lsb - 1 + + # Insert a row for any remaining reserved bits + if nextbit > 0: + rows.append(reserved_row(nextbit, 0)) + + output.write(table(header, rows, colalign)) + + # Return before generating field sections, if they are not wanted. + if not field_sections: + return + + # Generate field sections. + for field in reversed(reg.fields): + fname = field.name + + output.write(title(f"{reg.name} . {fname}", 3)) + + if field.desc is not None: + output.write(regref_to_link(field.desc) + "\n") + + if field.enum is not None: + if len(field.enum) == 0: + output.write("All values are reserved.\n") + else: + header = ["Value", "Name", "Description"] + hex_width = 2 + ((field.bits.width() + 3) // 4) + rows = [ + [f"{enum.value:#0{hex_width}x}", enum.name, enum.desc] + for enum in field.enum + ] + output.write(table(header, rows)) + + if field.has_incomplete_enum(): + output.write("Other values are reserved.\n") + + output.write("\n") \ No newline at end of file diff --git a/utils/reggen/reggen/md_helpers.py b/utils/reggen/reggen/md_helpers.py new file mode 100644 index 00000000..98a829f9 --- /dev/null +++ b/utils/reggen/reggen/md_helpers.py @@ -0,0 +1,122 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +"""A collection of functions that aid in generating markdown.""" + +import re +from typing import List, Match, Union, Optional + +import tabulate +from reggen.signal import Signal + + +def name_width(x: Signal) -> str: + '''Returns the name of the given signal followed by it's width.''' + return ( + '{}[{}:0]'.format(x.name, x.bits.msb) + if x.bits.width() != 1 else x.name + ) + + +def coderef(s: str) -> str: + '''Return markdown code to refer to some element in the code''' + return f"**`{s}`**" + + +def mono(s: str) -> str: + '''Return markdown code to put a string in monospace''' + return f"`{s}`" + + +def list_item(s: str) -> str: + '''Return markdown code to put a string as a list item. + + Make sure to use succeeding a new line. + ''' + return f"- {s}\n" + + +def italic(s: str) -> str: + '''Return markdown code to put a string in italic''' + return f"*{s}*" + + +def bold(s: str) -> str: + '''Return markdown code to put a string in bold''' + return f"**{s}**" + + +def url(text: str, url: str) -> str: + '''Return a markdown link to a URL''' + return f"[{text}]({url})" + + +def title(title: str, level: int) -> str: + '''Return the markdown string that corresponds to a title of a certain level''' + assert level <= 6, "commonmark does not handle more than 6 levels of title" + return ('#' * level) + " " + title + '\n' + + +def wavejson(json: str) -> str: + '''Return the markdown code to embed a wavedrom bit-field register picture''' + return f"\n```wavejson\n{json}\n```\n" + + +def first_line(s: str) -> str: + """Returns the first line of a string.""" + try: + return s.split("\n")[0] + except IndexError: + # only one line so return the string. + return s + + +def regref_to_link(s: str, file: Optional[str] = None) -> str: + '''Replaces the register reference markup in the data files with markdown links. + + The markup used in data files is '!!REG_NAME.field' + which is translated to '[`REG_NAME.field`](file#reg_name)'. + + Args: + s (str): The content in which to substitute register links. + file (str | None): An optional link to the file holding registers. + + Returns: + str: The content after the substitutions have been performed. + ''' + def linkify(match: Match[str]) -> str: + name = match.group(1) + register = match.group(1).partition('.')[0].lower() # remove field + return f"[`{name}`]({file if file else ''}#{register})" + + return re.sub(r"!!([A-Za-z0-9_.]+)", linkify, s) + + +def sanitise_for_md_table(s: str) -> str: + '''Transform (a subset of) markdown into something that can be put + in a markdown table cell. + + Specifically, this function handle two corner cases: + - new lines, which are converted to spaces. + - vertical bars, which are escaped. + ''' + s = re.sub(r"\n", " ", s) + s = re.sub(r"\|", r"\\\|", s) + return s + + +def table(header: List[str], + rows: List[List[str]], + colalign: Union[None, List[str]] = None) -> str: + '''Return the markdown code for a table given a header and the rows. + + The content is sanitised for use in a markdown table using `sanitise_for_md_table`. + If `colalign` is not None, each entry is the list specifies the alignment of a + column and can be either 'left', 'right' or 'center'. + ''' + header = [sanitise_for_md_table(x) for x in header] + rows = [[sanitise_for_md_table(x) for x in row] for row in rows] + # For some unknown reason, + # the "github" format of tabulate is "pipe" without the align specifiers, + # despite alignment being part of the GitHub Markdown format. + return "\n" + tabulate.tabulate(rows, header, "pipe", colalign=colalign) + "\n\n" \ No newline at end of file diff --git a/utils/reggen/reggen/multi_register.py b/utils/reggen/reggen/multi_register.py index 82c86677..0266376e 100644 --- a/utils/reggen/reggen/multi_register.py +++ b/utils/reggen/reggen/multi_register.py @@ -69,6 +69,7 @@ def __init__(self, self.cname = check_name(rd['cname'], 'cname field of multireg {}' .format(self.reg.name)) + self.name = self.reg.name self.regwen_multi = check_bool(rd.get('regwen_multi', False), 'regwen_multi field of multireg {}' diff --git a/utils/reggen/regtool.py b/utils/reggen/regtool.py index 76268c9c..f7e117a3 100755 --- a/utils/reggen/regtool.py +++ b/utils/reggen/regtool.py @@ -11,8 +11,10 @@ import sys from pathlib import PurePath -from reggen import (gen_cheader, gen_dv, gen_fpv, gen_html, - gen_json, gen_rtl, gen_selfdoc, version) +from reggen import ( + gen_cfg_md, gen_cheader, gen_dv, gen_fpv, gen_md, gen_html, + gen_json, gen_rtl, gen_selfdoc, version +) from reggen.ip_block import IpBlock DESC = """regtool, generate register info from Hjson source""" @@ -41,14 +43,17 @@ def main(): help='input file in Hjson type') parser.add_argument('-d', action='store_true', - help='Output register documentation (html)') + help='Output register documentation (markdown)') parser.add_argument('--cdefines', '-D', action='store_true', help='Output C defines header') + parser.add_argument('--doc-html-old', + action='store_true', + help='Output html documentation (deprecated)') parser.add_argument('--doc', action='store_true', - help='Output source file documentation (gfm)') + help='Output source file documentation (markdown)') parser.add_argument('-j', action='store_true', help='Output as formatted JSON') @@ -115,9 +120,10 @@ def main(): # the output needs a directory, it is a default path relative to the source # file (used when --outdir is not given). arg_to_format = [('j', ('json', None)), ('c', ('compact', None)), - ('d', ('html', None)), ('doc', ('doc', None)), + ('d', ('registers', None)), ('doc', ('doc', None)), ('r', ('rtl', 'rtl')), ('s', ('dv', 'dv')), - ('f', ('fpv', 'fpv/vip')), ('cdefines', ('cdh', None))] + ('f', ('fpv', 'fpv/vip')), ('cdefines', ('cdh', None)), + ('doc_html_old', ('doc_html_old', None))] format = None dirspec = None for arg_name, spec in arg_to_format: @@ -224,7 +230,9 @@ def main(): src_lic += '\n' + found_spdx with outfile: - if format == 'html': + if format == 'registers': + return gen_md.gen_md(obj, outfile) + elif format == 'doc_html_old': return gen_html.gen_html(obj, outfile) elif format == 'cdh': return gen_cheader.gen_cdefines(obj, outfile, src_lic, src_copy)