diff --git a/.github/workflows/build-apps-job/setup.sh b/.github/workflows/build-apps-job/setup.sh index dd29e72b7..fb1e94a31 100755 --- a/.github/workflows/build-apps-job/setup.sh +++ b/.github/workflows/build-apps-job/setup.sh @@ -21,7 +21,6 @@ echo ======================================== export RISCV='/tools/riscv' &&\ # All peripherals are included to make sure all apps can be built. -sed 's/is_included: "no",/is_included: "yes",/' -i mcu_cfg.hjson # The MCU is generated with various memory banks to avoid example code not fitting. make mcu-gen X_HEEP_CFG=configs/ci.hjson diff --git a/.github/workflows/simulate.yml b/.github/workflows/simulate.yml index ffb167220..5b7a2dd79 100644 --- a/.github/workflows/simulate.yml +++ b/.github/workflows/simulate.yml @@ -16,6 +16,5 @@ jobs: source /root/.bashrc conda activate core-v-mini-mcu make clean-all - sed 's/is_included: "no",/is_included: "yes",/' -i mcu_cfg.hjson make mcu-gen MEMORY_BANKS=6 python3 .github/workflows/sim-apps-job/test_apps.py \ No newline at end of file diff --git a/.gitignore b/.gitignore index 710c28c7f..8e8d9065b 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ build/ *.do *.jou *.str +*.pickle .venv/ __pycache__/ @@ -23,6 +24,10 @@ hw/core-v-mini-mcu/include/core_v_mini_mcu_pkg.sv hw/core-v-mini-mcu/system_bus.sv hw/core-v-mini-mcu/system_xbar.sv hw/core-v-mini-mcu/memory_subsystem.sv +hw/core-v-mini-mcu/ao_peripheral_subsystem.sv +hw/core-v-mini-mcu/core_v_mini_mcu.sv +hw/core-v-mini-mcu/peripheral_subsystem.sv +hw/core-v-mini-mcu/generated_if.sv hw/system/x_heep_system.sv hw/system/pad_ring.sv tb/tb_util.svh @@ -47,6 +52,11 @@ sw/device/lib/drivers/power_manager/power_manager_regs.h sw/device/lib/drivers/power_manager/power_manager.h sw/device/lib/drivers/pad_control/pad_control_regs.h sw/device/lib/drivers/**/*_structs.h +sw/device/lib/drivers/rv_plic/rv_plic_gen.c +sw/device/lib/drivers/rv_plic/rv_plic_gen.h +sw/device/lib/drivers/fast_intr_ctrl/fast_intr_ctrl.c +sw/device/lib/drivers/fast_intr_ctrl/fast_intr_ctrl.h +sw/device/lib/drivers/dma/dma.h # openroad flow/OpenROAD-flow-scripts diff --git a/Makefile b/Makefile index 9df94f6bd..1c631b26a 100644 --- a/Makefile +++ b/Makefile @@ -43,6 +43,8 @@ X_HEEP_CFG ?= configs/general.hjson PAD_CFG ?= pad_cfg.hjson EXT_PAD_CFG ?= +DATA_OBJ_FILE=data_cfg.pickle + # Compiler options are 'gcc' (default) and 'clang' COMPILER ?= gcc @@ -89,10 +91,13 @@ export ## @section Conda conda: environment.yml conda env create -f environment.yml + sed 's,ROOT_PATH,$(shell pwd),g' x_heep_pythonpath.pth > `conda run -n core-v-mini-mcu python -c 'import sysconfig; print(sysconfig.get_paths()["purelib"])'`/x_heep_pythonpath.pth environment.yml: python-requirements.txt util/python-requirements2conda.sh + + ## @section Installation ## Generates mcu files core-v-mini-mcu files and build the design with fusesoc @@ -101,31 +106,39 @@ environment.yml: python-requirements.txt ## @param MEMORY_BANKS=[2(default) to (16 - MEMORY_BANKS_IL)] ## @param MEMORY_BANKS_IL=[0(default),2,4,8] mcu-gen: - $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/core-v-mini-mcu/include --cpu $(CPU) --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_domains $(EXTERNAL_DOMAINS) --external_pads $(EXT_PAD_CFG) --pkg-sv hw/core-v-mini-mcu/include/core_v_mini_mcu_pkg.sv.tpl - $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/core-v-mini-mcu/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv hw/core-v-mini-mcu/system_bus.sv.tpl - $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/core-v-mini-mcu/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv hw/core-v-mini-mcu/system_xbar.sv.tpl - $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/core-v-mini-mcu/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv hw/core-v-mini-mcu/memory_subsystem.sv.tpl - $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/core-v-mini-mcu/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv hw/core-v-mini-mcu/peripheral_subsystem.sv.tpl - $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir tb/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv tb/tb_util.svh.tpl - $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/system/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv hw/system/pad_ring.sv.tpl - $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/core-v-mini-mcu/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv hw/core-v-mini-mcu/core_v_mini_mcu.sv.tpl - $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/system/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv hw/system/x_heep_system.sv.tpl - $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir sw/device/lib/runtime --cpu $(CPU) --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_domains $(EXTERNAL_DOMAINS) --header-c sw/device/lib/runtime/core_v_mini_mcu.h.tpl - $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir sw/linker --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --linker_script sw/linker/link.ld.tpl - $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir . --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --pkg-sv ./core-v-mini-mcu.upf.tpl - $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/ip/power_manager/rtl --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_domains $(EXTERNAL_DOMAINS) --pkg-sv hw/ip/power_manager/data/power_manager.sv.tpl - $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/ip/power_manager/data --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_domains $(EXTERNAL_DOMAINS) --pkg-sv hw/ip/power_manager/data/power_manager.hjson.tpl + $(PYTHON) util/mk_cfg.py -o $(DATA_OBJ_FILE) --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --cpu $(CPU) --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_domains $(EXTERNAL_DOMAINS) --external_pads $(EXT_PAD_CFG) + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir hw/core-v-mini-mcu/include --pkg-sv hw/core-v-mini-mcu/include/core_v_mini_mcu_pkg.sv.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir hw/core-v-mini-mcu/ --tpl-sv hw/core-v-mini-mcu/system_bus.sv.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir hw/core-v-mini-mcu/ --tpl-sv hw/core-v-mini-mcu/system_xbar.sv.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir hw/core-v-mini-mcu/ --tpl-sv hw/core-v-mini-mcu/memory_subsystem.sv.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir hw/core-v-mini-mcu/ --tpl-sv hw/core-v-mini-mcu/peripheral_subsystem.sv.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir hw/core-v-mini-mcu/ --tpl-sv hw/core-v-mini-mcu/ao_peripheral_subsystem.sv.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir tb/ --tpl-sv tb/tb_util.svh.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir hw/system/ --tpl-sv hw/system/pad_ring.sv.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir hw/core-v-mini-mcu/ --tpl-sv hw/core-v-mini-mcu/core_v_mini_mcu.sv.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir hw/system/ --tpl-sv hw/system/x_heep_system.sv.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir sw/device/lib/runtime --header-c sw/device/lib/runtime/core_v_mini_mcu.h.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir sw/device/lib/drivers/rv_plic/ --header-c sw/device/lib/drivers/rv_plic/rv_plic_gen.h.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir sw/device/lib/drivers/rv_plic/ --header-c sw/device/lib/drivers/rv_plic/rv_plic_gen.c.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir sw/device/lib/drivers/fast_intr_ctrl/ --header-c sw/device/lib/drivers/fast_intr_ctrl/fast_intr_ctrl.c.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir sw/device/lib/drivers/fast_intr_ctrl/ --header-c sw/device/lib/drivers/fast_intr_ctrl/fast_intr_ctrl.h.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir sw/device/lib/drivers/dma/ --header-c sw/device/lib/drivers/dma/dma.h.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir sw/linker --linker_script sw/linker/link.ld.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir . --pkg-sv ./core-v-mini-mcu.upf.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir hw/ip/power_manager/rtl --pkg-sv hw/ip/power_manager/data/power_manager.sv.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir hw/ip/power_manager/data --pkg-sv hw/ip/power_manager/data/power_manager.hjson.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir hw/core-v-mini-mcu --pkg-sv hw/core-v-mini-mcu/generated_if.sv.tpl bash -c "cd hw/ip/power_manager; source power_manager_gen.sh; cd ../../../" - $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir sw/device/lib/drivers/power_manager --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_domains $(EXTERNAL_DOMAINS) --pkg-sv sw/device/lib/drivers/power_manager/data/power_manager.h.tpl - $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/system/pad_control/data --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_pads $(EXT_PAD_CFG) --pkg-sv hw/system/pad_control/data/pad_control.hjson.tpl - $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/system/pad_control/rtl --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_pads $(EXT_PAD_CFG) --pkg-sv hw/system/pad_control/rtl/pad_control.sv.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir sw/device/lib/drivers/power_manager --pkg-sv sw/device/lib/drivers/power_manager/data/power_manager.h.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir hw/system/pad_control/data --pkg-sv hw/system/pad_control/data/pad_control.hjson.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir hw/system/pad_control/rtl --pkg-sv hw/system/pad_control/rtl/pad_control.sv.tpl bash -c "cd hw/system/pad_control; source pad_control_gen.sh; cd ../../../" - $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir sw/linker --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --linker_script sw/linker/link_flash_exec.ld.tpl - $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir sw/linker --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --linker_script sw/linker/link_flash_load.ld.tpl - $(PYTHON) ./util/structs_periph_gen.py - $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/fpga/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv hw/fpga/sram_wrapper.sv.tpl - $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/fpga/scripts/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv hw/fpga/scripts/generate_sram.tcl.tpl - $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir sw/device/lib/crt/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv sw/device/lib/crt/crt0.S.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir sw/linker --linker_script sw/linker/link_flash_exec.ld.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir sw/linker --linker_script sw/linker/link_flash_load.ld.tpl + $(PYTHON) ./util/structs_periph_gen.py -i ${DATA_OBJ_FILE} + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir hw/fpga/ --tpl-sv hw/fpga/sram_wrapper.sv.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir hw/fpga/scripts/ --tpl-sv hw/fpga/scripts/generate_sram.tcl.tpl + $(PYTHON) util/mcu_gen.py -i ${DATA_OBJ_FILE} --outdir sw/device/lib/crt/ --tpl-sv sw/device/lib/crt/crt0.S.tpl $(MAKE) verible ## Display mcu_gen.py help @@ -295,6 +308,9 @@ app-clean: app-restore: rm -rf sw/build +clean-cfg: + @rm -f ${DATA_OBJ_FILE} + ## Removes the HW build folder clean-sim: @rm -rf build @@ -303,4 +319,4 @@ clean-sim: clean-app: app-restore ## Removes the CMake build folder and the HW build folder -clean-all: app-restore clean-sim +clean-all: app-restore clean-sim clean-cfg diff --git a/Makefile.venv b/Makefile.venv index c79b9bbcd..12ca92cfc 100644 --- a/Makefile.venv +++ b/Makefile.venv @@ -227,6 +227,7 @@ endif $(VENV): $(PY) -m venv $(VENVDIR) $(VENV)/python -m pip install --upgrade pip setuptools wheel + sed 's,ROOT_PATH,$(shell pwd),g' x_heep_pythonpath.pth > `$(VENV)/python -c 'import sysconfig; print(sysconfig.get_paths()["purelib"])'`/x_heep_pythonpath.pth $(VENV)/$(MARKER): $(VENVDEPENDS) | $(VENV) ifneq ($(strip $(REQUIREMENTS_TXT)),) diff --git a/configs/ci.hjson b/configs/ci.hjson index 02ea10d82..31cd1397e 100644 --- a/configs/ci.hjson +++ b/configs/ci.hjson @@ -20,4 +20,128 @@ start: 0x00000C800 } ] + peripheral_domains: { + ao_peripheral: { + type: "fixed" + address: 0x20000000 + length: 0x00100000 + peripherals: { + f0: { + type: fixed + name: "soc_ctrl" + offset: 0x00000000 + length: 0x00010000 + } + f1: { + type: fixed + name: "bootrom" + offset: 0x00010000 + length: 0x00010000 + } + f2: { + type: fixed + name: "spi_flash" + offset: 0x00020000 + length: 0x00008000 + } + f3: { + type: fixed + name: "spi_memio" + offset: 0x00028000 + length: 0x00008000 + } + f4: { + type: fixed + name: "dma" + offset: 0x00030000 + length: 0x00010000 + } + f5: { + type: fixed + name: "power_manager" + offset: 0x00040000 + length: 0x00010000 + } + f6: { + type: fixed + name: "rv_timer" + suffix: "ao" + offset: 0x00050000 + length: 0x00010000 + } + f7: { + type: fixed + name: "fast_intr_ctrl" + offset: 0x00060000 + length: 0x00010000 + } + f8: { + type: fixed + name: "ext_peripheral" + offset: 0x00070000 + length: 0x00010000 + } + f9: { + type: fixed + name: "pad_control" + offset: 0x00080000 + length: 0x00010000 + } + } + } + peripheral: { + clock_domain: false # not used yet + address: 0x30000000 + length: 0x00100000 + peripherals: { + timer: { + type: rv_timer + } + spi0: { + type: spi_host + event_is_fast_intr: true + dma: true + } + spi1: { + type: spi_host + dma: false + } + i2c: { + type: i2c + } + i2s: { + type: i2s + dma: true + } + rv_plic: { + type: rv_plic + } + gpio0: { + type: gpio + gpios_used: range + start: 0 + end: 7 + intr: fast + } + gpio1: { + type: gpio + gpios_used: range + start: 8 + end: 31 + intr: plic + } + uart: { + type: uart + } + pdm2pcm: { + type: pdm2pcm + } + + } + } + } + + external_interrupts: 2 + + pad_file: "pad_cfg.hjson" # relative to project root } \ No newline at end of file diff --git a/configs/example.py b/configs/example.py index b9e3faf2b..c3a39fab1 100644 --- a/configs/example.py +++ b/configs/example.py @@ -1,6 +1,11 @@ from x_heep_gen.linker_section import LinkerSection +from x_heep_gen.pads import PadManager from x_heep_gen.system import XHeep, BusType +from x_heep_gen.peripherals.peripheral_domain import FixedDomain, PeripheralDomain +from x_heep_gen.peripherals.peripherals import * + + def config(): system = XHeep(BusType.NtoM) system.add_ram_banks([32] * 2) @@ -9,10 +14,41 @@ def config(): system.add_linker_section(LinkerSection.by_size("code", 0, 0x00000C800)) system.add_linker_section(LinkerSection("data", 0x00000C800, None)) + ao_domain = FixedDomain("ao_peripheral", address=0x20000000, addr_size=0x00100000) + ao_domain.add_peripheral(FixedPeripheral("soc_ctrl", offset=0x00000000, addr_size=0x00010000)) + ao_domain.add_peripheral(FixedPeripheral("bootrom", offset=0x00010000, addr_size=0x00010000)) + ao_domain.add_peripheral(FixedPeripheral("spi_flash", offset=0x00020000, addr_size=0x00008000)) + ao_domain.add_peripheral(FixedPeripheral("spi_memio", offset=0x00028000, addr_size=0x00008000)) + ao_domain.add_peripheral(FixedPeripheral("dma", offset=0x00030000, addr_size=0x00010000)) + ao_domain.add_peripheral(FixedPeripheral("power_manager", offset=0x00040000, addr_size=0x00010000)) + ao_domain.add_peripheral(FixedPeripheral("rv_timer", suffix="ao", offset=0x00050000, addr_size=0x00010000)) + ao_domain.add_peripheral(FixedPeripheral("fast_intr_ctrl", offset=0x00060000, addr_size=0x00010000)) + ao_domain.add_peripheral(FixedPeripheral("ext_peripheral", offset=0x00070000, addr_size=0x00010000)) + ao_domain.add_peripheral(FixedPeripheral("pad_control", offset=0x00080000, addr_size=0x00010000)) + system.add_domain(ao_domain) + + on_off_domain = PeripheralDomain("peripheral", address=0x30000000, addr_size=0x00100000) + on_off_domain.add_peripheral(RvTimerPeripheral()) + on_off_domain.add_peripheral(SpiHostPeripheral(dma=True, event_is_fast_intr=True)) + on_off_domain.add_peripheral(SpiHostPeripheral(dma=False)) + on_off_domain.add_peripheral(I2CPeripheral()) + on_off_domain.add_peripheral(I2SPeripheral(dma=True)) + on_off_domain.add_peripheral(RvPlicPeripheral()) + on_off_domain.add_peripheral(Pdm2PcmPeripheral()) + on_off_domain.add_peripheral(GpioPeripheral(gpios_used={i:i for i in range(0, 8)}, intr_map={i:"fast" for i in range(0, 8)})) + on_off_domain.add_peripheral(GpioPeripheral(gpios_used={i:i for i in range(8, 32)}, intr_map={i:"plic" for i in range(8, 32)})) + on_off_domain.add_peripheral(UartPeripheral()) + system.add_domain(on_off_domain) + + with open("pad_cfg.hjson") as f: + system.add_pad_manager(PadManager.load(f.read())) + + system.set_ext_intr(2) + # Here the system is build, # The missing gaps are filled, like the missing end address of the data section. system.build() if not system.validate(): raise RuntimeError("there are errors") - + return system diff --git a/configs/example_interleaved.hjson b/configs/example_interleaved.hjson index e831d7978..768e86289 100644 --- a/configs/example_interleaved.hjson +++ b/configs/example_interleaved.hjson @@ -37,4 +37,126 @@ start: 0x00000C800 } ] + + peripheral_domains: { + ao_peripheral: { + type: "fixed" + address: 0x20000000 + length: 0x00100000 + peripherals: { + f0: { + type: fixed + name: "soc_ctrl" + offset: 0x00000000 + length: 0x00010000 + } + f1: { + type: fixed + name: "bootrom" + offset: 0x00010000 + length: 0x00010000 + } + f2: { + type: fixed + name: "spi_flash" + offset: 0x00020000 + length: 0x00008000 + } + f3: { + type: fixed + name: "spi_memio" + offset: 0x00028000 + length: 0x00008000 + } + f4: { + type: fixed + name: "dma" + offset: 0x00030000 + length: 0x00010000 + } + f5: { + type: fixed + name: "power_manager" + offset: 0x00040000 + length: 0x00010000 + } + f6: { + type: fixed + name: "rv_timer" + suffix: "ao" + offset: 0x00050000 + length: 0x00010000 + } + f7: { + type: fixed + name: "fast_intr_ctrl" + offset: 0x00060000 + length: 0x00010000 + } + f8: { + type: fixed + name: "ext_peripheral" + offset: 0x00070000 + length: 0x00010000 + } + f9: { + type: fixed + name: "pad_control" + offset: 0x00080000 + length: 0x00010000 + } + } + } + peripheral: { + clock_domain: false # not used yet + address: 0x30000000 + length: 0x00100000 + peripherals: { + timer: { + type: rv_timer + } + spi0: { + type: spi_host + event_is_fast_intr: true + dma: true + } + spi1: { + type: spi_host + dma: false + } + i2c: { + type: i2c + } + i2s: { + type: i2s + dma: true + } + rv_plic: { + type: rv_plic + } + gpio0: { + type: gpio + gpios_used: range + start: 0 + end: 7 + intr: fast + } + gpio1: { + type: gpio + gpios_used: range + start: 8 + end: 31 + intr: plic + } + uart: { + type: uart + } + + } + } + } + + external_interrupts: 2 + + pad_file: "pad_cfg.hjson" # relative to project root } \ No newline at end of file diff --git a/configs/general.hjson b/configs/general.hjson index d3465c500..821cc1ebf 100644 --- a/configs/general.hjson +++ b/configs/general.hjson @@ -21,4 +21,126 @@ start: 0x00000C800 } ] + + peripheral_domains: { + ao_peripheral: { + type: "fixed" + address: 0x20000000 + length: 0x00100000 + peripherals: { + f0: { + type: fixed + name: "soc_ctrl" + offset: 0x00000000 + length: 0x00010000 + } + f1: { + type: fixed + name: "bootrom" + offset: 0x00010000 + length: 0x00010000 + } + f2: { + type: fixed + name: "spi_flash" + offset: 0x00020000 + length: 0x00008000 + } + f3: { + type: fixed + name: "spi_memio" + offset: 0x00028000 + length: 0x00008000 + } + f4: { + type: fixed + name: "dma" + offset: 0x00030000 + length: 0x00010000 + } + f5: { + type: fixed + name: "power_manager" + offset: 0x00040000 + length: 0x00010000 + } + f6: { + type: fixed + name: "rv_timer" + suffix: "ao" + offset: 0x00050000 + length: 0x00010000 + } + f7: { + type: fixed + name: "fast_intr_ctrl" + offset: 0x00060000 + length: 0x00010000 + } + f8: { + type: fixed + name: "ext_peripheral" + offset: 0x00070000 + length: 0x00010000 + } + f9: { + type: fixed + name: "pad_control" + offset: 0x00080000 + length: 0x00010000 + } + } + } + peripheral: { + clock_domain: false # not used yet + address: 0x30000000 + length: 0x00100000 + peripherals: { + timer: { + type: rv_timer + } + spi0: { + type: spi_host + event_is_fast_intr: true + dma: true + } + spi1: { + type: spi_host + dma: false + } + i2c: { + type: i2c + } + i2s: { + type: i2s + dma: true + } + rv_plic: { + type: rv_plic + } + gpio0: { + type: gpio + gpios_used: range + start: 0 + end: 7 + intr: fast + } + gpio1: { + type: gpio + gpios_used: range + start: 8 + end: 31 + intr: plic + } + uart: { + type: uart + } + + } + } + } + + external_interrupts: 2 + + pad_file: "pad_cfg.hjson" # relative to project root } \ No newline at end of file diff --git a/configs/minimal.hjson b/configs/minimal.hjson new file mode 100644 index 000000000..c64497951 --- /dev/null +++ b/configs/minimal.hjson @@ -0,0 +1,109 @@ +{ + ram_address: 0 + bus_type: "onetoM", + ram_banks: { + code_and_data: { + num: 2 + sizes: [32] + } + } + + linker_sections: + [ + { + name: code + start: 0 + #minimum size for freeRTOS and clang + size: 0x00000C800 + }, + { + name: data + start: 0x00000C800 + } + ] + + peripheral_domains: { + ao_peripheral: { + type: "fixed" + address: 0x20000000 + length: 0x00100000 + peripherals: { + f0: { + type: fixed + name: "soc_ctrl" + offset: 0x00000000 + length: 0x00010000 + } + f1: { + type: fixed + name: "bootrom" + offset: 0x00010000 + length: 0x00010000 + } + f2: { + type: fixed + name: "spi_flash" + offset: 0x00020000 + length: 0x00008000 + } + f3: { + type: fixed + name: "spi_memio" + offset: 0x00028000 + length: 0x00008000 + } + f4: { + type: fixed + name: "dma" + offset: 0x00030000 + length: 0x00010000 + } + f5: { + type: fixed + name: "power_manager" + offset: 0x00040000 + length: 0x00010000 + } + f6: { + type: fixed + name: "rv_timer" + suffix: "ao" + offset: 0x00050000 + length: 0x00010000 + } + f7: { + type: fixed + name: "fast_intr_ctrl" + offset: 0x00060000 + length: 0x00010000 + } + f8: { + type: fixed + name: "ext_peripheral" + offset: 0x00070000 + length: 0x00010000 + } + f9: { + type: fixed + name: "pad_control" + offset: 0x00080000 + length: 0x00010000 + } + } + } + peripheral: { + clock_domain: false # not used yet + address: 0x30000000 + length: 0x00100000 + peripherals: { + rv_plic: { + type: rv_plic + } + } + } + } + + external_interrupts: 2 + + pad_file: "pad_cfg.hjson" # relative to project root +} \ No newline at end of file diff --git a/configs/testall.hjson b/configs/testall.hjson index 07a96b645..12189a2fb 100644 --- a/configs/testall.hjson +++ b/configs/testall.hjson @@ -20,4 +20,129 @@ start: 0x00000C800 } ] + + peripheral_domains: { + ao_peripheral: { + type: "fixed" + address: 0x20000000 + length: 0x00100000 + peripherals: { + f0: { + type: fixed + name: "soc_ctrl" + offset: 0x00000000 + length: 0x00010000 + } + f1: { + type: fixed + name: "bootrom" + offset: 0x00010000 + length: 0x00010000 + } + f2: { + type: fixed + name: "spi_flash" + offset: 0x00020000 + length: 0x00008000 + } + f3: { + type: fixed + name: "spi_memio" + offset: 0x00028000 + length: 0x00008000 + } + f4: { + type: fixed + name: "dma" + offset: 0x00030000 + length: 0x00010000 + } + f5: { + type: fixed + name: "power_manager" + offset: 0x00040000 + length: 0x00010000 + } + f6: { + type: fixed + name: "rv_timer" + suffix: "ao" + offset: 0x00050000 + length: 0x00010000 + } + f7: { + type: fixed + name: "fast_intr_ctrl" + offset: 0x00060000 + length: 0x00010000 + } + f8: { + type: fixed + name: "ext_peripheral" + offset: 0x00070000 + length: 0x00010000 + } + f9: { + type: fixed + name: "pad_control" + offset: 0x00080000 + length: 0x00010000 + } + } + } + peripheral: { + clock_domain: false # not used yet + address: 0x30000000 + length: 0x00100000 + peripherals: { + timer: { + type: rv_timer + } + spi0: { + type: spi_host + event_is_fast_intr: true + dma: true + } + spi1: { + type: spi_host + dma: false + } + i2c: { + type: i2c + } + i2s: { + type: i2s + dma: true + } + rv_plic: { + type: rv_plic + } + gpio0: { + type: gpio + gpios_used: range + start: 0 + end: 7 + intr: fast + } + gpio1: { + type: gpio + gpios_used: range + start: 8 + end: 31 + intr: plic + } + uart: { + type: uart + } + pdm2pcm: { + type: pdm2pcm + } + + } + } + } + + external_interrupts: 2 + + pad_file: "pad_cfg.hjson" # relative to project root } \ No newline at end of file diff --git a/core-v-mini-mcu.core b/core-v-mini-mcu.core index 8dac12332..b79b38d58 100644 --- a/core-v-mini-mcu.core +++ b/core-v-mini-mcu.core @@ -47,6 +47,7 @@ filesets: - hw/core-v-mini-mcu/debug_subsystem.sv - hw/core-v-mini-mcu/peripheral_subsystem.sv - hw/core-v-mini-mcu/ao_peripheral_subsystem.sv + - hw/core-v-mini-mcu/generated_if.sv file_type: systemVerilogSource rtl-simulation: diff --git a/docs/requirements.txt b/docs/requirements.txt index a4cd7e7b5..6c3e7cc97 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,3 @@ sphinx-rtd-theme myst-parser -sphinxcontrib-apidoc +sphinx-autoapi diff --git a/docs/source/Peripherals/DMA.md b/docs/source/Peripherals/DMA.md index 4580f148c..0335d1fb5 100644 --- a/docs/source/Peripherals/DMA.md +++ b/docs/source/Peripherals/DMA.md @@ -247,7 +247,7 @@ static uint32_t *spi_flash_fifo_tx = ADDRESS_SPI_FLASH_TX_FIFO; static dma_target_t tgt2= { .inc_du = 0, - .trig = DMA_TRIG_SLOT_SPI_FLASH_TX, + .trig = DMA_TRIG_SLOT_SPI_FLASH_DMA_TX, }; tgt2.ptr = spi_flash_fifo_tx; @@ -261,7 +261,7 @@ There is no need to assign a value of transaction size or data type. By default, The increment needs to be set to zero as the pointer should always be set to the FIFO address. -Because the SPI FLASH transmission FIFO has a line connected to slot number 4 (codified as a `1` in the fourth bit of the `trig` element) to let the DMA know if the FIFO is full, a trigger is set in that position by passing `.trig = DMA_TRIG_SLOT_SPI_FLASH_TX`. +Because the SPI FLASH transmission FIFO has a line connected to slot number 4 (codified as a `1` in the fourth bit of the `trig` element) to let the DMA know if the FIFO is full, a trigger is set in that position by passing `.trig = DMA_TRIG_SLOT_SPI_FLASH_DMA_TX`. The transaction is formed by selecting the source and destination targets @@ -401,7 +401,7 @@ The source of the data will be a peripheral connected to the SPI, which will be tgt2.ptr = spi_peripheral_fifo_rx; tgt2.size_du = 2048; tgt2.type = DMA_DATA_TYPE_HALF_WORD; -tgt2.trig = DMA_TRIG_SLOT_SPI_RX; +tgt2.trig = DMA_TRIG_SLOT_SPI_HOST_0_RX; ``` The source pointer is set to the reception FIFO of the SPI, and the appropriate slot is chosen. diff --git a/docs/source/conf.py b/docs/source/conf.py index 44ce6b68c..8d7c45b1b 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -5,8 +5,6 @@ # Author: Embedded Systems Laboratory (EPFL) import os -import sys -sys.path.insert(0, os.path.abspath("../../util")) project = 'X-HEEP' copyright = '2023, EPFL' @@ -21,8 +19,8 @@ 'sphinx.ext.autodoc', 'sphinx.ext.autosummary', 'sphinx.ext.intersphinx', - 'sphinxcontrib.apidoc', 'myst_parser', + 'autoapi.extension', ] html_static_path = ['_static'] @@ -41,6 +39,20 @@ epub_show_urls = 'footnote' -apidoc_module_dir = '../../util/x_heep_gen' +apidoc_module_dir = '../../util/x_heep_gen/' apidoc_output_dir = 'Configuration/generated' -apidoc_separate_modules = True \ No newline at end of file + +autoapi_dirs = [apidoc_module_dir] +autoapi_root = apidoc_output_dir +autoapi_python_use_implicit_namespaces = False +autoapi_python_class_content = "both" +autoapi_options = [ + 'members', + 'undoc-members', + 'private-members', + 'show-inheritance', + 'show-module-summary', + 'special-members', +] + +os.environ["X_HEEP_PROJECT_ROOT"] = "../" \ No newline at end of file diff --git a/docs/source/index.rst b/docs/source/index.rst index a0d4c7463..57048be89 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -84,9 +84,9 @@ Index ./Peripherals/* .. toctree:: - :maxdepth: 5 + :maxdepth: 7 :glob: :caption: Configuration ./Configuration/* - ./Configuration/generated/modules.rst \ No newline at end of file + ./Configuration/generated/index.rst \ No newline at end of file diff --git a/hw/core-v-mini-mcu/ao_peripheral_subsystem.sv b/hw/core-v-mini-mcu/ao_peripheral_subsystem.sv.tpl similarity index 65% rename from hw/core-v-mini-mcu/ao_peripheral_subsystem.sv rename to hw/core-v-mini-mcu/ao_peripheral_subsystem.sv.tpl index 64d90ab3e..08ad16fbb 100644 --- a/hw/core-v-mini-mcu/ao_peripheral_subsystem.sv +++ b/hw/core-v-mini-mcu/ao_peripheral_subsystem.sv.tpl @@ -17,30 +17,12 @@ module ao_peripheral_subsystem output obi_resp_t slave_resp_o, // SOC CTRL - input logic boot_select_i, - input logic execute_from_flash_i, - output logic exit_valid_o, output logic [31:0] exit_value_o, // Memory Map SPI Region input obi_req_t spimemio_req_i, output obi_resp_t spimemio_resp_o, - // SPI Interface to flash (YosysHW SPI and OpenTitan SPI multiplexed) - output logic spi_flash_sck_o, - output logic spi_flash_sck_en_o, - output logic [spi_host_reg_pkg::NumCS-1:0] spi_flash_csb_o, - output logic [spi_host_reg_pkg::NumCS-1:0] spi_flash_csb_en_o, - output logic [ 3:0] spi_flash_sd_o, - output logic [ 3:0] spi_flash_sd_en_o, - input logic [ 3:0] spi_flash_sd_i, - - // OpenTitan SPI interface to external spi slaves - input logic spi_rx_valid_i, - input logic spi_tx_ready_i, - - output logic spi_flash_intr_event_o, - // POWER MANAGER input logic [31:0] intr_i, input logic [NEXT_INT_RND-1:0] intr_vector_ext_i, @@ -68,10 +50,6 @@ module ao_peripheral_subsystem output logic [core_v_mini_mcu_pkg::NUM_BANKS-1:0] memory_subsystem_clkgate_en_no, output logic [EXT_DOMAINS_RND-1:0] external_subsystem_clkgate_en_no, - // RV TIMER - output logic rv_timer_0_intr_o, - output logic rv_timer_1_intr_o, - // DMA output obi_req_t dma_read_ch0_req_o, input obi_resp_t dma_read_ch0_resp_i, @@ -79,8 +57,6 @@ module ao_peripheral_subsystem input obi_resp_t dma_write_ch0_resp_i, output obi_req_t dma_addr_ch0_req_o, input obi_resp_t dma_addr_ch0_resp_i, - output logic dma_done_intr_o, - output logic dma_window_intr_o, // External PADs output reg_req_t pad_req_o, @@ -90,33 +66,11 @@ module ao_peripheral_subsystem input logic [14:0] fast_intr_i, output logic [14:0] fast_intr_o, - // GPIO - input logic [7:0] cio_gpio_i, - output logic [7:0] cio_gpio_o, - output logic [7:0] cio_gpio_en_o, - output logic [7:0] intr_gpio_o, - - // UART - input logic uart_rx_i, - output logic uart_tx_o, - output logic uart_intr_tx_watermark_o, - output logic uart_intr_rx_watermark_o, - output logic uart_intr_tx_empty_o, - output logic uart_intr_rx_overflow_o, - output logic uart_intr_rx_frame_err_o, - output logic uart_intr_rx_break_err_o, - output logic uart_intr_rx_timeout_o, - output logic uart_intr_rx_parity_err_o, - - // I2s - input logic i2s_rx_valid_i, - // EXTERNAL PERIPH output reg_req_t ext_peripheral_slave_req_o, input reg_rsp_t ext_peripheral_slave_resp_i, - - input logic ext_dma_slot_tx_i, - input logic ext_dma_slot_rx_i + + ${xheep.get_rh().get_node_ports(xheep.get_ao_node()).strip(",")} ); import core_v_mini_mcu_pkg::*; @@ -126,25 +80,17 @@ module ao_peripheral_subsystem reg_pkg::reg_req_t peripheral_req; reg_pkg::reg_rsp_t peripheral_rsp; - reg_pkg::reg_req_t [core_v_mini_mcu_pkg::AO_PERIPHERALS-1:0] ao_peripheral_slv_req; - reg_pkg::reg_rsp_t [core_v_mini_mcu_pkg::AO_PERIPHERALS-1:0] ao_peripheral_slv_rsp; + reg_pkg::reg_req_t [core_v_mini_mcu_pkg::AO_PERIPHERAL_COUNT-1:0] ao_peripheral_slv_req; + reg_pkg::reg_rsp_t [core_v_mini_mcu_pkg::AO_PERIPHERAL_COUNT-1:0] ao_peripheral_slv_rsp; tlul_pkg::tl_h2d_t rv_timer_tl_h2d; tlul_pkg::tl_d2h_t rv_timer_tl_d2h; - tlul_pkg::tl_h2d_t uart_tl_h2d; - tlul_pkg::tl_d2h_t uart_tl_d2h; - - logic [AO_PERIPHERALS_PORT_SEL_WIDTH-1:0] peripheral_select; + logic [AO_PERIPHERAL_PORT_SEL_WIDTH-1:0] peripheral_select; logic use_spimemio; - logic spi_flash_rx_valid; - logic spi_flash_tx_ready; - - logic [23:0] intr_gpio_unused; - logic [23:0] cio_gpio_unused; - logic [23:0] cio_gpio_en_unused; + ${xheep.get_rh().get_node_local_signals(xheep.get_ao_node())} obi_pkg::obi_req_t slave_fifo_req_sel; @@ -205,13 +151,13 @@ module ao_peripheral_subsystem ); addr_decode #( - .NoIndices(core_v_mini_mcu_pkg::AO_PERIPHERALS), - .NoRules(core_v_mini_mcu_pkg::AO_PERIPHERALS), + .NoIndices(core_v_mini_mcu_pkg::AO_PERIPHERAL_COUNT), + .NoRules(core_v_mini_mcu_pkg::AO_PERIPHERAL_COUNT), .addr_t(logic [31:0]), .rule_t(addr_map_rule_pkg::addr_map_rule_t) ) i_addr_decode_soc_regbus_periph_xbar ( .addr_i(peripheral_req.addr), - .addr_map_i(core_v_mini_mcu_pkg::AO_PERIPHERALS_ADDR_RULES), + .addr_map_i(core_v_mini_mcu_pkg::AO_PERIPHERAL_ADDR_RULES), .idx_o(peripheral_select), .dec_valid_o(), .dec_error_o(), @@ -220,7 +166,7 @@ module ao_peripheral_subsystem ); reg_demux #( - .NoPorts(core_v_mini_mcu_pkg::AO_PERIPHERALS), + .NoPorts(core_v_mini_mcu_pkg::AO_PERIPHERAL_COUNT), .req_t (reg_pkg::reg_req_t), .rsp_t (reg_pkg::reg_rsp_t) ) reg_demux_i ( @@ -241,10 +187,10 @@ module ao_peripheral_subsystem .rst_ni, .reg_req_i(ao_peripheral_slv_req[core_v_mini_mcu_pkg::SOC_CTRL_IDX]), .reg_rsp_o(ao_peripheral_slv_rsp[core_v_mini_mcu_pkg::SOC_CTRL_IDX]), - .boot_select_i, - .execute_from_flash_i, + .boot_select_i(${xheep.get_rh().use_source_as_sv("boot_select", xheep.get_ao_node())}), + .execute_from_flash_i(${xheep.get_rh().use_source_as_sv("execute_from_flash", xheep.get_ao_node())}), .use_spimemio_o(use_spimemio), - .exit_valid_o, + .exit_valid_o(${xheep.get_rh().use_source_as_sv("exit_valid", xheep.get_ao_node())}), .exit_value_o ); @@ -263,17 +209,38 @@ module ao_peripheral_subsystem .yo_reg_rsp_o(ao_peripheral_slv_rsp[core_v_mini_mcu_pkg::SPI_MEMIO_IDX]), .ot_reg_req_i(ao_peripheral_slv_req[core_v_mini_mcu_pkg::SPI_FLASH_IDX]), .ot_reg_rsp_o(ao_peripheral_slv_rsp[core_v_mini_mcu_pkg::SPI_FLASH_IDX]), - .spi_flash_sck_o, - .spi_flash_sck_en_o, - .spi_flash_csb_o, - .spi_flash_csb_en_o, - .spi_flash_sd_o, - .spi_flash_sd_en_o, - .spi_flash_sd_i, + .spi_flash_sck_o(${xheep.get_rh().use_source_as_sv("spi_flash_sck_o", xheep.get_ao_node())}), + .spi_flash_sck_en_o(${xheep.get_rh().use_source_as_sv("spi_flash_sck_en_o", xheep.get_ao_node())}), + .spi_flash_csb_o({ + ${xheep.get_rh().use_source_as_sv("spi_flash_csb_1_o", xheep.get_ao_node())}, + ${xheep.get_rh().use_source_as_sv("spi_flash_csb_0_o", xheep.get_ao_node())} + }), + .spi_flash_csb_en_o({ + ${xheep.get_rh().use_source_as_sv("spi_flash_csb_1_en_o", xheep.get_ao_node())}, + ${xheep.get_rh().use_source_as_sv("spi_flash_csb_0_en_o", xheep.get_ao_node())} + }), + .spi_flash_sd_o({ + ${xheep.get_rh().use_source_as_sv("spi_flash_sd_3_o", xheep.get_ao_node())}, + ${xheep.get_rh().use_source_as_sv("spi_flash_sd_2_o", xheep.get_ao_node())}, + ${xheep.get_rh().use_source_as_sv("spi_flash_sd_1_o", xheep.get_ao_node())}, + ${xheep.get_rh().use_source_as_sv("spi_flash_sd_0_o", xheep.get_ao_node())} + }), + .spi_flash_sd_en_o({ + ${xheep.get_rh().use_source_as_sv("spi_flash_sd_3_en_o", xheep.get_ao_node())}, + ${xheep.get_rh().use_source_as_sv("spi_flash_sd_2_en_o", xheep.get_ao_node())}, + ${xheep.get_rh().use_source_as_sv("spi_flash_sd_1_en_o", xheep.get_ao_node())}, + ${xheep.get_rh().use_source_as_sv("spi_flash_sd_0_en_o", xheep.get_ao_node())} + }), + .spi_flash_sd_i({ + ${xheep.get_rh().use_source_as_sv("spi_flash_sd_3_i", xheep.get_ao_node())}, + ${xheep.get_rh().use_source_as_sv("spi_flash_sd_2_i", xheep.get_ao_node())}, + ${xheep.get_rh().use_source_as_sv("spi_flash_sd_1_i", xheep.get_ao_node())}, + ${xheep.get_rh().use_source_as_sv("spi_flash_sd_0_i", xheep.get_ao_node())} + }), .spi_flash_intr_error_o(), - .spi_flash_intr_event_o, - .spi_flash_rx_valid_o(spi_flash_rx_valid), - .spi_flash_tx_ready_o(spi_flash_tx_ready) + .spi_flash_intr_event_o(${xheep.get_rh().use_source_as_sv("spi_flash_intr", xheep.get_ao_node())}), + .spi_flash_rx_valid_o(${xheep.get_rh().use_source_as_sv("spi_flash_dma_rx", xheep.get_ao_node())}), + .spi_flash_tx_ready_o(${xheep.get_rh().use_source_as_sv("spi_flash_dma_tx", xheep.get_ao_node())}) ); power_manager #( @@ -331,19 +298,13 @@ module ao_peripheral_subsystem .rst_ni, .tl_i(rv_timer_tl_h2d), .tl_o(rv_timer_tl_d2h), - .intr_timer_expired_0_0_o(rv_timer_0_intr_o), - .intr_timer_expired_1_0_o(rv_timer_1_intr_o) + .intr_timer_expired_0_0_o(${xheep.get_rh().use_source_as_sv("rv_timer_0_intr", xheep.get_ao_node())}), + .intr_timer_expired_1_0_o(${xheep.get_rh().use_source_as_sv("rv_timer_1_intr", xheep.get_ao_node())}) ); - parameter DMA_TRIGGER_SLOT_NUM = 7; + parameter DMA_TRIGGER_SLOT_NUM = ${xheep.get_rh().get_target_ep_copy("dma_default_target").count}; logic [DMA_TRIGGER_SLOT_NUM-1:0] dma_trigger_slots; - assign dma_trigger_slots[0] = spi_rx_valid_i; - assign dma_trigger_slots[1] = spi_tx_ready_i; - assign dma_trigger_slots[2] = spi_flash_rx_valid; - assign dma_trigger_slots[3] = spi_flash_tx_ready; - assign dma_trigger_slots[4] = i2s_rx_valid_i; - assign dma_trigger_slots[5] = ext_dma_slot_tx_i; - assign dma_trigger_slots[6] = ext_dma_slot_rx_i; + assign dma_trigger_slots = ${xheep.get_rh().use_target_as_sv_array_multi("dma_default_target", xheep.get_ao_node(), xheep.get_rh().get_target_ep_copy("dma_default_target").count)}; dma #( .reg_req_t (reg_pkg::reg_req_t), @@ -363,8 +324,8 @@ module ao_peripheral_subsystem .dma_addr_ch0_req_o, .dma_addr_ch0_resp_i, .trigger_slot_i(dma_trigger_slots), - .dma_done_intr_o(dma_done_intr_o), - .dma_window_intr_o(dma_window_intr_o) + .dma_done_intr_o(${xheep.get_rh().use_source_as_sv("dma_done_intr", xheep.get_ao_node())}), + .dma_window_intr_o(${xheep.get_rh().use_source_as_sv("dma_window_intr", xheep.get_ao_node())}) ); assign pad_req_o = ao_peripheral_slv_req[core_v_mini_mcu_pkg::PAD_CONTROL_IDX]; @@ -382,55 +343,5 @@ module ao_peripheral_subsystem .fast_intr_o ); - gpio #( - .reg_req_t(reg_pkg::reg_req_t), - .reg_rsp_t(reg_pkg::reg_rsp_t) - ) gpio_ao_i ( - .clk_i, - .rst_ni, - .reg_req_i(ao_peripheral_slv_req[core_v_mini_mcu_pkg::GPIO_AO_IDX]), - .reg_rsp_o(ao_peripheral_slv_rsp[core_v_mini_mcu_pkg::GPIO_AO_IDX]), - .gpio_in({24'b0, cio_gpio_i}), - .gpio_out({cio_gpio_unused, cio_gpio_o}), - .gpio_tx_en_o({cio_gpio_en_unused, cio_gpio_en_o}), - .gpio_in_sync_o(), - .pin_level_interrupts_o({intr_gpio_unused, intr_gpio_o}), - .global_interrupt_o() - ); - - reg_to_tlul #( - .req_t(reg_pkg::reg_req_t), - .rsp_t(reg_pkg::reg_rsp_t), - .tl_h2d_t(tlul_pkg::tl_h2d_t), - .tl_d2h_t(tlul_pkg::tl_d2h_t), - .tl_a_user_t(tlul_pkg::tl_a_user_t), - .tl_a_op_e(tlul_pkg::tl_a_op_e), - .TL_A_USER_DEFAULT(tlul_pkg::TL_A_USER_DEFAULT), - .PutFullData(tlul_pkg::PutFullData), - .Get(tlul_pkg::Get) - ) reg_to_tlul_uart_i ( - .tl_o(uart_tl_h2d), - .tl_i(uart_tl_d2h), - .reg_req_i(ao_peripheral_slv_req[core_v_mini_mcu_pkg::UART_IDX]), - .reg_rsp_o(ao_peripheral_slv_rsp[core_v_mini_mcu_pkg::UART_IDX]) - ); - - uart uart_i ( - .clk_i, - .rst_ni, - .tl_i(uart_tl_h2d), - .tl_o(uart_tl_d2h), - .cio_rx_i(uart_rx_i), - .cio_tx_o(uart_tx_o), - .cio_tx_en_o(), - .intr_tx_watermark_o(uart_intr_tx_watermark_o), - .intr_rx_watermark_o(uart_intr_rx_watermark_o), - .intr_tx_empty_o(uart_intr_tx_empty_o), - .intr_rx_overflow_o(uart_intr_rx_overflow_o), - .intr_rx_frame_err_o(uart_intr_rx_frame_err_o), - .intr_rx_break_err_o(uart_intr_rx_break_err_o), - .intr_rx_timeout_o(uart_intr_rx_timeout_o), - .intr_rx_parity_err_o(uart_intr_rx_parity_err_o) - ); endmodule : ao_peripheral_subsystem diff --git a/hw/core-v-mini-mcu/core_v_mini_mcu.sv b/hw/core-v-mini-mcu/core_v_mini_mcu.sv deleted file mode 100644 index 31f045e80..000000000 --- a/hw/core-v-mini-mcu/core_v_mini_mcu.sv +++ /dev/null @@ -1,796 +0,0 @@ -// Copyright 2022 OpenHW Group -// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. -// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 - -module core_v_mini_mcu - import obi_pkg::*; - import reg_pkg::*; -#( - parameter COREV_PULP = 0, - parameter FPU = 0, - parameter ZFINX = 0, - parameter EXT_XBAR_NMASTER = 0, - parameter X_EXT = 0, // eXtension interface in cv32e40x - //do not touch these parameters - parameter EXT_XBAR_NMASTER_RND = EXT_XBAR_NMASTER == 0 ? 1 : EXT_XBAR_NMASTER, - parameter EXT_DOMAINS_RND = core_v_mini_mcu_pkg::EXTERNAL_DOMAINS == 0 ? 1 : core_v_mini_mcu_pkg::EXTERNAL_DOMAINS, - parameter NEXT_INT_RND = core_v_mini_mcu_pkg::NEXT_INT == 0 ? 1 : core_v_mini_mcu_pkg::NEXT_INT -) ( - - input logic rst_ni, - - input logic clk_i, - - - input logic boot_select_i, - - input logic execute_from_flash_i, - - input logic jtag_tck_i, - - input logic jtag_tms_i, - - input logic jtag_trst_ni, - - input logic jtag_tdi_i, - - output logic jtag_tdo_o, - - input logic uart_rx_i, - - output logic uart_tx_o, - - output logic exit_valid_o, - - output logic gpio_0_o, - input logic gpio_0_i, - output logic gpio_0_oe_o, - - output logic gpio_1_o, - input logic gpio_1_i, - output logic gpio_1_oe_o, - - output logic gpio_2_o, - input logic gpio_2_i, - output logic gpio_2_oe_o, - - output logic gpio_3_o, - input logic gpio_3_i, - output logic gpio_3_oe_o, - - output logic gpio_4_o, - input logic gpio_4_i, - output logic gpio_4_oe_o, - - output logic gpio_5_o, - input logic gpio_5_i, - output logic gpio_5_oe_o, - - output logic gpio_6_o, - input logic gpio_6_i, - output logic gpio_6_oe_o, - - output logic gpio_7_o, - input logic gpio_7_i, - output logic gpio_7_oe_o, - - output logic gpio_8_o, - input logic gpio_8_i, - output logic gpio_8_oe_o, - - output logic gpio_9_o, - input logic gpio_9_i, - output logic gpio_9_oe_o, - - output logic gpio_10_o, - input logic gpio_10_i, - output logic gpio_10_oe_o, - - output logic gpio_11_o, - input logic gpio_11_i, - output logic gpio_11_oe_o, - - output logic gpio_12_o, - input logic gpio_12_i, - output logic gpio_12_oe_o, - - output logic gpio_13_o, - input logic gpio_13_i, - output logic gpio_13_oe_o, - - output logic gpio_14_o, - input logic gpio_14_i, - output logic gpio_14_oe_o, - - output logic gpio_15_o, - input logic gpio_15_i, - output logic gpio_15_oe_o, - - output logic gpio_16_o, - input logic gpio_16_i, - output logic gpio_16_oe_o, - - output logic gpio_17_o, - input logic gpio_17_i, - output logic gpio_17_oe_o, - - output logic spi_flash_sck_o, - input logic spi_flash_sck_i, - output logic spi_flash_sck_oe_o, - - output logic spi_flash_cs_0_o, - input logic spi_flash_cs_0_i, - output logic spi_flash_cs_0_oe_o, - - output logic spi_flash_cs_1_o, - input logic spi_flash_cs_1_i, - output logic spi_flash_cs_1_oe_o, - - output logic spi_flash_sd_0_o, - input logic spi_flash_sd_0_i, - output logic spi_flash_sd_0_oe_o, - - output logic spi_flash_sd_1_o, - input logic spi_flash_sd_1_i, - output logic spi_flash_sd_1_oe_o, - - output logic spi_flash_sd_2_o, - input logic spi_flash_sd_2_i, - output logic spi_flash_sd_2_oe_o, - - output logic spi_flash_sd_3_o, - input logic spi_flash_sd_3_i, - output logic spi_flash_sd_3_oe_o, - - output logic spi_sck_o, - input logic spi_sck_i, - output logic spi_sck_oe_o, - - output logic spi_cs_0_o, - input logic spi_cs_0_i, - output logic spi_cs_0_oe_o, - - output logic spi_cs_1_o, - input logic spi_cs_1_i, - output logic spi_cs_1_oe_o, - - output logic spi_sd_0_o, - input logic spi_sd_0_i, - output logic spi_sd_0_oe_o, - - output logic spi_sd_1_o, - input logic spi_sd_1_i, - output logic spi_sd_1_oe_o, - - output logic spi_sd_2_o, - input logic spi_sd_2_i, - output logic spi_sd_2_oe_o, - - output logic spi_sd_3_o, - input logic spi_sd_3_i, - output logic spi_sd_3_oe_o, - - output logic pdm2pcm_pdm_o, - input logic pdm2pcm_pdm_i, - output logic pdm2pcm_pdm_oe_o, - output logic gpio_18_o, - input logic gpio_18_i, - output logic gpio_18_oe_o, - - output logic pdm2pcm_clk_o, - input logic pdm2pcm_clk_i, - output logic pdm2pcm_clk_oe_o, - output logic gpio_19_o, - input logic gpio_19_i, - output logic gpio_19_oe_o, - - output logic i2s_sck_o, - input logic i2s_sck_i, - output logic i2s_sck_oe_o, - output logic gpio_20_o, - input logic gpio_20_i, - output logic gpio_20_oe_o, - - output logic i2s_ws_o, - input logic i2s_ws_i, - output logic i2s_ws_oe_o, - output logic gpio_21_o, - input logic gpio_21_i, - output logic gpio_21_oe_o, - - output logic i2s_sd_o, - input logic i2s_sd_i, - output logic i2s_sd_oe_o, - output logic gpio_22_o, - input logic gpio_22_i, - output logic gpio_22_oe_o, - - output logic spi2_cs_0_o, - input logic spi2_cs_0_i, - output logic spi2_cs_0_oe_o, - output logic gpio_23_o, - input logic gpio_23_i, - output logic gpio_23_oe_o, - - output logic spi2_cs_1_o, - input logic spi2_cs_1_i, - output logic spi2_cs_1_oe_o, - output logic gpio_24_o, - input logic gpio_24_i, - output logic gpio_24_oe_o, - - output logic spi2_sck_o, - input logic spi2_sck_i, - output logic spi2_sck_oe_o, - output logic gpio_25_o, - input logic gpio_25_i, - output logic gpio_25_oe_o, - - output logic spi2_sd_0_o, - input logic spi2_sd_0_i, - output logic spi2_sd_0_oe_o, - output logic gpio_26_o, - input logic gpio_26_i, - output logic gpio_26_oe_o, - - output logic spi2_sd_1_o, - input logic spi2_sd_1_i, - output logic spi2_sd_1_oe_o, - output logic gpio_27_o, - input logic gpio_27_i, - output logic gpio_27_oe_o, - - output logic spi2_sd_2_o, - input logic spi2_sd_2_i, - output logic spi2_sd_2_oe_o, - output logic gpio_28_o, - input logic gpio_28_i, - output logic gpio_28_oe_o, - - output logic spi2_sd_3_o, - input logic spi2_sd_3_i, - output logic spi2_sd_3_oe_o, - output logic gpio_29_o, - input logic gpio_29_i, - output logic gpio_29_oe_o, - - output logic i2c_scl_o, - input logic i2c_scl_i, - output logic i2c_scl_oe_o, - output logic gpio_31_o, - input logic gpio_31_i, - output logic gpio_31_oe_o, - - output logic i2c_sda_o, - input logic i2c_sda_i, - output logic i2c_sda_oe_o, - output logic gpio_30_o, - input logic gpio_30_i, - output logic gpio_30_oe_o, - - - // eXtension interface - if_xif.cpu_compressed xif_compressed_if, - if_xif.cpu_issue xif_issue_if, - if_xif.cpu_commit xif_commit_if, - if_xif.cpu_mem xif_mem_if, - if_xif.cpu_mem_result xif_mem_result_if, - if_xif.cpu_result xif_result_if, - - output reg_req_t pad_req_o, - input reg_rsp_t pad_resp_i, - - input obi_req_t [EXT_XBAR_NMASTER_RND-1:0] ext_xbar_master_req_i, - output obi_resp_t [EXT_XBAR_NMASTER_RND-1:0] ext_xbar_master_resp_o, - - // External slave ports - output obi_req_t ext_core_instr_req_o, - input obi_resp_t ext_core_instr_resp_i, - output obi_req_t ext_core_data_req_o, - input obi_resp_t ext_core_data_resp_i, - output obi_req_t ext_debug_master_req_o, - input obi_resp_t ext_debug_master_resp_i, - output obi_req_t ext_dma_read_ch0_req_o, - input obi_resp_t ext_dma_read_ch0_resp_i, - output obi_req_t ext_dma_write_ch0_req_o, - input obi_resp_t ext_dma_write_ch0_resp_i, - output obi_req_t ext_dma_addr_ch0_req_o, - input obi_resp_t ext_dma_addr_ch0_resp_i, - - output reg_req_t ext_peripheral_slave_req_o, - input reg_rsp_t ext_peripheral_slave_resp_i, - - input logic [NEXT_INT_RND-1:0] intr_vector_ext_i, - - output logic cpu_subsystem_powergate_switch_no, - input logic cpu_subsystem_powergate_switch_ack_ni, - output logic peripheral_subsystem_powergate_switch_no, - input logic peripheral_subsystem_powergate_switch_ack_ni, - output logic [core_v_mini_mcu_pkg::NUM_BANKS-1:0] memory_subsystem_banks_powergate_switch_no, - input logic [core_v_mini_mcu_pkg::NUM_BANKS-1:0] memory_subsystem_banks_powergate_switch_ack_ni, - output logic [EXT_DOMAINS_RND-1:0] external_subsystem_powergate_switch_no, - input logic [EXT_DOMAINS_RND-1:0] external_subsystem_powergate_switch_ack_ni, - output logic [EXT_DOMAINS_RND-1:0] external_subsystem_powergate_iso_no, - output logic [EXT_DOMAINS_RND-1:0] external_subsystem_rst_no, - output logic [EXT_DOMAINS_RND-1:0] external_ram_banks_set_retentive_no, - output logic [EXT_DOMAINS_RND-1:0] external_subsystem_clkgate_en_no, - - output logic [31:0] exit_value_o, - - input logic ext_dma_slot_tx_i, - input logic ext_dma_slot_rx_i -); - - import core_v_mini_mcu_pkg::*; - import cv32e40p_apu_core_pkg::*; - - localparam NUM_BYTES = core_v_mini_mcu_pkg::MEM_SIZE; - localparam DM_HALTADDRESS = core_v_mini_mcu_pkg::DEBUG_START_ADDRESS + 32'h00000800; //debug rom code (section .text in linker) starts at 0x800 - - localparam JTAG_IDCODE = 32'h10001c05; - localparam BOOT_ADDR = core_v_mini_mcu_pkg::BOOTROM_START_ADDRESS; - localparam NUM_MHPMCOUNTERS = 1; - - // Log top level parameter values -`ifndef SYNTHESIS - initial begin - $display("[X-HEEP]: NUM_BYTES = %dKB", NUM_BYTES / 1024); - end -`endif - - // masters signals - obi_req_t core_instr_req; - obi_resp_t core_instr_resp; - obi_req_t core_data_req; - obi_resp_t core_data_resp; - obi_req_t debug_master_req; - obi_resp_t debug_master_resp; - obi_req_t dma_read_ch0_req; - obi_resp_t dma_read_ch0_resp; - obi_req_t dma_write_ch0_req; - obi_resp_t dma_write_ch0_resp; - obi_req_t dma_addr_ch0_req; - obi_resp_t dma_addr_ch0_resp; - - // ram signals - obi_req_t [core_v_mini_mcu_pkg::NUM_BANKS-1:0] ram_slave_req; - obi_resp_t [core_v_mini_mcu_pkg::NUM_BANKS-1:0] ram_slave_resp; - - // debug signals - obi_req_t debug_slave_req; - obi_resp_t debug_slave_resp; - - // peripherals signals - obi_req_t ao_peripheral_slave_req; - obi_resp_t ao_peripheral_slave_resp; - obi_req_t peripheral_slave_req; - obi_resp_t peripheral_slave_resp; - - // signals to debug unit - logic debug_core_req; - logic debug_reset_n; - - // core - logic core_sleep; - - // irq signals - logic irq_ack; - logic [4:0] irq_id_out; - logic irq_software; - logic irq_external; - logic [14:0] irq_fast; - - // Memory Map SPI Region - obi_req_t flash_mem_slave_req; - obi_resp_t flash_mem_slave_resp; - - // rv_timer - logic [3:0] rv_timer_intr; - - // interrupt array - logic [31:0] intr; - logic [14:0] fast_intr; - - // Power manager - logic cpu_subsystem_powergate_iso_n; - logic cpu_subsystem_rst_n; - logic peripheral_subsystem_powergate_iso_n; - logic peripheral_subsystem_rst_n; - logic [core_v_mini_mcu_pkg::NUM_BANKS-1:0] memory_subsystem_banks_powergate_iso_n; - logic [core_v_mini_mcu_pkg::NUM_BANKS-1:0] memory_subsystem_banks_set_retentive_n; - - // Clock gating signals - logic peripheral_subsystem_clkgate_en_n; - logic [core_v_mini_mcu_pkg::NUM_BANKS-1:0] memory_subsystem_clkgate_en_n; - - // DMA - logic dma_done_intr; - logic dma_window_intr; - - // SPI - logic spi_flash_intr, spi_intr, spi_rx_valid, spi_tx_ready; - - // GPIO - logic [31:8] gpio_in; - logic [31:8] gpio_out; - logic [31:8] gpio_oe; - - // GPIO_AO - logic [7:0] gpio_ao_in; - logic [7:0] gpio_ao_out; - logic [7:0] gpio_ao_oe; - logic [7:0] gpio_ao_intr; - - // UART PLIC interrupts - logic uart_intr_tx_watermark; - logic uart_intr_rx_watermark; - logic uart_intr_tx_empty; - logic uart_intr_rx_overflow; - logic uart_intr_rx_frame_err; - logic uart_intr_rx_break_err; - logic uart_intr_rx_timeout; - logic uart_intr_rx_parity_err; - - // I2s - logic i2s_rx_valid; - - assign intr = { - 1'b0, irq_fast, 4'b0, irq_external, 3'b0, rv_timer_intr[0], 3'b0, irq_software, 3'b0 - }; - - assign fast_intr = { - 1'b0, - gpio_ao_intr, - spi_flash_intr, - spi_intr, - dma_done_intr, - rv_timer_intr[3], - rv_timer_intr[2], - rv_timer_intr[1] - }; - - cpu_subsystem #( - .BOOT_ADDR(BOOT_ADDR), - .COREV_PULP(COREV_PULP), - .FPU(FPU), - .ZFINX(ZFINX), - .NUM_MHPMCOUNTERS(NUM_MHPMCOUNTERS), - .DM_HALTADDRESS(DM_HALTADDRESS), - .X_EXT(X_EXT) - ) cpu_subsystem_i ( - // Clock and Reset - .clk_i, - .rst_ni(cpu_subsystem_rst_n && debug_reset_n), - .core_instr_req_o(core_instr_req), - .core_instr_resp_i(core_instr_resp), - .core_data_req_o(core_data_req), - .core_data_resp_i(core_data_resp), - .xif_compressed_if, - .xif_issue_if, - .xif_commit_if, - .xif_mem_if, - .xif_mem_result_if, - .xif_result_if, - .irq_i(intr), - .irq_ack_o(irq_ack), - .irq_id_o(irq_id_out), - .debug_req_i(debug_core_req), - .core_sleep_o(core_sleep) - ); - - debug_subsystem #( - .JTAG_IDCODE(JTAG_IDCODE) - ) debug_subsystem_i ( - .clk_i, - .rst_ni, - .jtag_tck_i, - .jtag_tms_i, - .jtag_trst_ni, - .jtag_tdi_i, - .jtag_tdo_o, - .debug_core_req_o(debug_core_req), - .debug_ndmreset_no(debug_reset_n), - .debug_slave_req_i(debug_slave_req), - .debug_slave_resp_o(debug_slave_resp), - .debug_master_req_o(debug_master_req), - .debug_master_resp_i(debug_master_resp) - ); - - system_bus #( - .NUM_BANKS(core_v_mini_mcu_pkg::NUM_BANKS), - .EXT_XBAR_NMASTER(EXT_XBAR_NMASTER) - ) system_bus_i ( - .clk_i, - .rst_ni(rst_ni && debug_reset_n), - .core_instr_req_i(core_instr_req), - .core_instr_resp_o(core_instr_resp), - .core_data_req_i(core_data_req), - .core_data_resp_o(core_data_resp), - .debug_master_req_i(debug_master_req), - .debug_master_resp_o(debug_master_resp), - .dma_read_ch0_req_i(dma_read_ch0_req), - .dma_read_ch0_resp_o(dma_read_ch0_resp), - .dma_write_ch0_req_i(dma_write_ch0_req), - .dma_write_ch0_resp_o(dma_write_ch0_resp), - .dma_addr_ch0_req_i(dma_addr_ch0_req), - .dma_addr_ch0_resp_o(dma_addr_ch0_resp), - .ext_xbar_master_req_i(ext_xbar_master_req_i), - .ext_xbar_master_resp_o(ext_xbar_master_resp_o), - .ram_req_o(ram_slave_req), - .ram_resp_i(ram_slave_resp), - .debug_slave_req_o(debug_slave_req), - .debug_slave_resp_i(debug_slave_resp), - .ao_peripheral_slave_req_o(ao_peripheral_slave_req), - .ao_peripheral_slave_resp_i(ao_peripheral_slave_resp), - .peripheral_slave_req_o(peripheral_slave_req), - .peripheral_slave_resp_i(peripheral_slave_resp), - .flash_mem_slave_req_o(flash_mem_slave_req), - .flash_mem_slave_resp_i(flash_mem_slave_resp), - .ext_core_instr_req_o(ext_core_instr_req_o), - .ext_core_instr_resp_i(ext_core_instr_resp_i), - .ext_core_data_req_o(ext_core_data_req_o), - .ext_core_data_resp_i(ext_core_data_resp_i), - .ext_debug_master_req_o(ext_debug_master_req_o), - .ext_debug_master_resp_i(ext_debug_master_resp_i), - .ext_dma_read_ch0_req_o(ext_dma_read_ch0_req_o), - .ext_dma_read_ch0_resp_i(ext_dma_read_ch0_resp_i), - .ext_dma_write_ch0_req_o(ext_dma_write_ch0_req_o), - .ext_dma_write_ch0_resp_i(ext_dma_write_ch0_resp_i), - .ext_dma_addr_ch0_req_o(ext_dma_addr_ch0_req_o), - .ext_dma_addr_ch0_resp_i(ext_dma_addr_ch0_resp_i) - ); - - memory_subsystem #( - .NUM_BANKS(core_v_mini_mcu_pkg::NUM_BANKS) - ) memory_subsystem_i ( - .clk_i, - .rst_ni(rst_ni && debug_reset_n), - .clk_gate_en_ni(memory_subsystem_clkgate_en_n), - .ram_req_i(ram_slave_req), - .ram_resp_o(ram_slave_resp), - .set_retentive_ni(memory_subsystem_banks_set_retentive_n) - ); - - ao_peripheral_subsystem ao_peripheral_subsystem_i ( - .clk_i, - .rst_ni(rst_ni && debug_reset_n), - .slave_req_i(ao_peripheral_slave_req), - .slave_resp_o(ao_peripheral_slave_resp), - .boot_select_i, - .execute_from_flash_i, - .exit_valid_o, - .exit_value_o, - .spimemio_req_i(flash_mem_slave_req), - .spimemio_resp_o(flash_mem_slave_resp), - .spi_flash_sck_o, - .spi_flash_sck_en_o(spi_flash_sck_oe_o), - .spi_flash_csb_o({spi_flash_cs_1_o, spi_flash_cs_0_o}), - .spi_flash_csb_en_o({spi_flash_cs_1_oe_o, spi_flash_cs_0_oe_o}), - .spi_flash_sd_o({spi_flash_sd_3_o, spi_flash_sd_2_o, spi_flash_sd_1_o, spi_flash_sd_0_o}), - .spi_flash_sd_en_o({ - spi_flash_sd_3_oe_o, spi_flash_sd_2_oe_o, spi_flash_sd_1_oe_o, spi_flash_sd_0_oe_o - }), - .spi_flash_sd_i({spi_flash_sd_3_i, spi_flash_sd_2_i, spi_flash_sd_1_i, spi_flash_sd_0_i}), - .intr_i(intr), - .intr_vector_ext_i, - .core_sleep_i(core_sleep), - .cpu_subsystem_powergate_switch_no, - .cpu_subsystem_powergate_switch_ack_ni, - .cpu_subsystem_powergate_iso_no(cpu_subsystem_powergate_iso_n), - .cpu_subsystem_rst_no(cpu_subsystem_rst_n), - .peripheral_subsystem_powergate_switch_no, - .peripheral_subsystem_powergate_switch_ack_ni, - .peripheral_subsystem_powergate_iso_no(peripheral_subsystem_powergate_iso_n), - .peripheral_subsystem_rst_no(peripheral_subsystem_rst_n), - .memory_subsystem_banks_powergate_switch_no, - .memory_subsystem_banks_powergate_switch_ack_ni, - .memory_subsystem_banks_powergate_iso_no(memory_subsystem_banks_powergate_iso_n), - .memory_subsystem_banks_set_retentive_no(memory_subsystem_banks_set_retentive_n), - .external_subsystem_powergate_switch_no, - .external_subsystem_powergate_switch_ack_ni, - .external_subsystem_powergate_iso_no, - .external_subsystem_rst_no, - .external_ram_banks_set_retentive_no, - .peripheral_subsystem_clkgate_en_no(peripheral_subsystem_clkgate_en_n), - .memory_subsystem_clkgate_en_no(memory_subsystem_clkgate_en_n), - .external_subsystem_clkgate_en_no, - .rv_timer_0_intr_o(rv_timer_intr[0]), - .rv_timer_1_intr_o(rv_timer_intr[1]), - .dma_read_ch0_req_o(dma_read_ch0_req), - .dma_read_ch0_resp_i(dma_read_ch0_resp), - .dma_write_ch0_req_o(dma_write_ch0_req), - .dma_write_ch0_resp_i(dma_write_ch0_resp), - .dma_addr_ch0_req_o(dma_addr_ch0_req), - .dma_addr_ch0_resp_i(dma_addr_ch0_resp), - .dma_done_intr_o(dma_done_intr), - .dma_window_intr_o(dma_window_intr), - .spi_flash_intr_event_o(spi_flash_intr), - .pad_req_o, - .pad_resp_i, - .fast_intr_i(fast_intr), - .fast_intr_o(irq_fast), - .cio_gpio_i(gpio_ao_in), - .cio_gpio_o(gpio_ao_out), - .cio_gpio_en_o(gpio_ao_oe), - .intr_gpio_o(gpio_ao_intr), - .uart_rx_i, - .uart_tx_o, - .uart_intr_tx_watermark_o(uart_intr_tx_watermark), - .uart_intr_rx_watermark_o(uart_intr_rx_watermark), - .uart_intr_tx_empty_o(uart_intr_tx_empty), - .uart_intr_rx_overflow_o(uart_intr_rx_overflow), - .uart_intr_rx_frame_err_o(uart_intr_rx_frame_err), - .uart_intr_rx_break_err_o(uart_intr_rx_break_err), - .uart_intr_rx_timeout_o(uart_intr_rx_timeout), - .uart_intr_rx_parity_err_o(uart_intr_rx_parity_err), - .spi_rx_valid_i(spi_rx_valid), - .spi_tx_ready_i(spi_tx_ready), - .i2s_rx_valid_i(i2s_rx_valid), - .ext_peripheral_slave_req_o, - .ext_peripheral_slave_resp_i, - .ext_dma_slot_tx_i, - .ext_dma_slot_rx_i - ); - - peripheral_subsystem peripheral_subsystem_i ( - .clk_i, - .rst_ni(peripheral_subsystem_rst_n && debug_reset_n), - .clk_gate_en_ni(peripheral_subsystem_clkgate_en_n), - .slave_req_i(peripheral_slave_req), - .slave_resp_o(peripheral_slave_resp), - .intr_vector_ext_i, - .irq_plic_o(irq_external), - .msip_o(irq_software), - .uart_intr_tx_watermark_i(uart_intr_tx_watermark), - .uart_intr_rx_watermark_i(uart_intr_rx_watermark), - .uart_intr_tx_empty_i(uart_intr_tx_empty), - .uart_intr_rx_overflow_i(uart_intr_rx_overflow), - .uart_intr_rx_frame_err_i(uart_intr_rx_frame_err), - .uart_intr_rx_break_err_i(uart_intr_rx_break_err), - .uart_intr_rx_timeout_i(uart_intr_rx_timeout), - .uart_intr_rx_parity_err_i(uart_intr_rx_parity_err), - .dma_window_intr_i(dma_window_intr), - .cio_gpio_i(gpio_in), - .cio_gpio_o(gpio_out), - .cio_gpio_en_o(gpio_oe), - .cio_scl_i(i2c_scl_i), - .cio_scl_o(i2c_scl_o), - .cio_scl_en_o(i2c_scl_oe_o), - .cio_sda_i(i2c_sda_i), - .cio_sda_o(i2c_sda_o), - .cio_sda_en_o(i2c_sda_oe_o), - .spi_sck_o, - .spi_sck_en_o(spi_sck_oe_o), - .spi_csb_o({spi_cs_1_o, spi_cs_0_o}), - .spi_csb_en_o({spi_cs_1_oe_o, spi_cs_0_oe_o}), - .spi_sd_o({spi_sd_3_o, spi_sd_2_o, spi_sd_1_o, spi_sd_0_o}), - .spi_sd_en_o({spi_sd_3_oe_o, spi_sd_2_oe_o, spi_sd_1_oe_o, spi_sd_0_oe_o}), - .spi_sd_i({spi_sd_3_i, spi_sd_2_i, spi_sd_1_i, spi_sd_0_i}), - .spi_intr_event_o(spi_intr), - .spi_rx_valid_o(spi_rx_valid), - .spi_tx_ready_o(spi_tx_ready), - .spi2_sck_o, - .spi2_sck_en_o(spi2_sck_oe_o), - .spi2_csb_o({spi2_cs_1_o, spi2_cs_0_o}), - .spi2_csb_en_o({spi2_cs_1_oe_o, spi2_cs_0_oe_o}), - .spi2_sd_o({spi2_sd_3_o, spi2_sd_2_o, spi2_sd_1_o, spi2_sd_0_o}), - .spi2_sd_en_o({spi2_sd_3_oe_o, spi2_sd_2_oe_o, spi2_sd_1_oe_o, spi2_sd_0_oe_o}), - .spi2_sd_i({spi2_sd_3_i, spi2_sd_2_i, spi2_sd_1_i, spi2_sd_0_i}), - .rv_timer_2_intr_o(rv_timer_intr[2]), - .rv_timer_3_intr_o(rv_timer_intr[3]), - .pdm2pcm_clk_o(pdm2pcm_clk_o), - .pdm2pcm_clk_en_o(pdm2pcm_clk_oe_o), - .pdm2pcm_pdm_i(pdm2pcm_pdm_i), - .i2s_sck_o(i2s_sck_o), - .i2s_sck_oe_o(i2s_sck_oe_o), - .i2s_sck_i(i2s_sck_i), - .i2s_ws_o(i2s_ws_o), - .i2s_ws_oe_o(i2s_ws_oe_o), - .i2s_ws_i(i2s_ws_i), - .i2s_sd_o(i2s_sd_o), - .i2s_sd_oe_o(i2s_sd_oe_o), - .i2s_sd_i(i2s_sd_i), - .i2s_rx_valid_o(i2s_rx_valid) - ); - - assign pdm2pcm_pdm_o = 0; - assign pdm2pcm_pdm_oe_o = 0; - - assign gpio_ao_in[0] = gpio_0_i; - assign gpio_0_o = gpio_ao_out[0]; - assign gpio_0_oe_o = gpio_ao_oe[0]; - assign gpio_ao_in[1] = gpio_1_i; - assign gpio_1_o = gpio_ao_out[1]; - assign gpio_1_oe_o = gpio_ao_oe[1]; - assign gpio_ao_in[2] = gpio_2_i; - assign gpio_2_o = gpio_ao_out[2]; - assign gpio_2_oe_o = gpio_ao_oe[2]; - assign gpio_ao_in[3] = gpio_3_i; - assign gpio_3_o = gpio_ao_out[3]; - assign gpio_3_oe_o = gpio_ao_oe[3]; - assign gpio_ao_in[4] = gpio_4_i; - assign gpio_4_o = gpio_ao_out[4]; - assign gpio_4_oe_o = gpio_ao_oe[4]; - assign gpio_ao_in[5] = gpio_5_i; - assign gpio_5_o = gpio_ao_out[5]; - assign gpio_5_oe_o = gpio_ao_oe[5]; - assign gpio_ao_in[6] = gpio_6_i; - assign gpio_6_o = gpio_ao_out[6]; - assign gpio_6_oe_o = gpio_ao_oe[6]; - assign gpio_ao_in[7] = gpio_7_i; - assign gpio_7_o = gpio_ao_out[7]; - assign gpio_7_oe_o = gpio_ao_oe[7]; - assign gpio_in[8] = gpio_8_i; - assign gpio_8_o = gpio_out[8]; - assign gpio_8_oe_o = gpio_oe[8]; - assign gpio_in[9] = gpio_9_i; - assign gpio_9_o = gpio_out[9]; - assign gpio_9_oe_o = gpio_oe[9]; - assign gpio_in[10] = gpio_10_i; - assign gpio_10_o = gpio_out[10]; - assign gpio_10_oe_o = gpio_oe[10]; - assign gpio_in[11] = gpio_11_i; - assign gpio_11_o = gpio_out[11]; - assign gpio_11_oe_o = gpio_oe[11]; - assign gpio_in[12] = gpio_12_i; - assign gpio_12_o = gpio_out[12]; - assign gpio_12_oe_o = gpio_oe[12]; - assign gpio_in[13] = gpio_13_i; - assign gpio_13_o = gpio_out[13]; - assign gpio_13_oe_o = gpio_oe[13]; - assign gpio_in[14] = gpio_14_i; - assign gpio_14_o = gpio_out[14]; - assign gpio_14_oe_o = gpio_oe[14]; - assign gpio_in[15] = gpio_15_i; - assign gpio_15_o = gpio_out[15]; - assign gpio_15_oe_o = gpio_oe[15]; - assign gpio_in[16] = gpio_16_i; - assign gpio_16_o = gpio_out[16]; - assign gpio_16_oe_o = gpio_oe[16]; - assign gpio_in[17] = gpio_17_i; - assign gpio_17_o = gpio_out[17]; - assign gpio_17_oe_o = gpio_oe[17]; - assign gpio_in[18] = gpio_18_i; - assign gpio_18_o = gpio_out[18]; - assign gpio_18_oe_o = gpio_oe[18]; - assign gpio_in[19] = gpio_19_i; - assign gpio_19_o = gpio_out[19]; - assign gpio_19_oe_o = gpio_oe[19]; - assign gpio_in[20] = gpio_20_i; - assign gpio_20_o = gpio_out[20]; - assign gpio_20_oe_o = gpio_oe[20]; - assign gpio_in[21] = gpio_21_i; - assign gpio_21_o = gpio_out[21]; - assign gpio_21_oe_o = gpio_oe[21]; - assign gpio_in[22] = gpio_22_i; - assign gpio_22_o = gpio_out[22]; - assign gpio_22_oe_o = gpio_oe[22]; - assign gpio_in[23] = gpio_23_i; - assign gpio_23_o = gpio_out[23]; - assign gpio_23_oe_o = gpio_oe[23]; - assign gpio_in[24] = gpio_24_i; - assign gpio_24_o = gpio_out[24]; - assign gpio_24_oe_o = gpio_oe[24]; - assign gpio_in[25] = gpio_25_i; - assign gpio_25_o = gpio_out[25]; - assign gpio_25_oe_o = gpio_oe[25]; - assign gpio_in[26] = gpio_26_i; - assign gpio_26_o = gpio_out[26]; - assign gpio_26_oe_o = gpio_oe[26]; - assign gpio_in[27] = gpio_27_i; - assign gpio_27_o = gpio_out[27]; - assign gpio_27_oe_o = gpio_oe[27]; - assign gpio_in[28] = gpio_28_i; - assign gpio_28_o = gpio_out[28]; - assign gpio_28_oe_o = gpio_oe[28]; - assign gpio_in[29] = gpio_29_i; - assign gpio_29_o = gpio_out[29]; - assign gpio_29_oe_o = gpio_oe[29]; - assign gpio_in[30] = gpio_30_i; - assign gpio_30_o = gpio_out[30]; - assign gpio_30_oe_o = gpio_oe[30]; - assign gpio_in[31] = gpio_31_i; - assign gpio_31_o = gpio_out[31]; - assign gpio_31_oe_o = gpio_oe[31]; - -endmodule // core_v_mini_mcu diff --git a/hw/core-v-mini-mcu/core_v_mini_mcu.sv.tpl b/hw/core-v-mini-mcu/core_v_mini_mcu.sv.tpl index d6d0ef5ba..1d4247e10 100644 --- a/hw/core-v-mini-mcu/core_v_mini_mcu.sv.tpl +++ b/hw/core-v-mini-mcu/core_v_mini_mcu.sv.tpl @@ -18,10 +18,8 @@ module core_v_mini_mcu ) ( input logic rst_ni, + input logic clk_i, -% for pad in pad_list: -${pad.core_v_mini_mcu_interface} -% endfor // eXtension interface if_xif.cpu_compressed xif_compressed_if, @@ -71,8 +69,7 @@ ${pad.core_v_mini_mcu_interface} output logic [31:0] exit_value_o, - input logic ext_dma_slot_tx_i, - input logic ext_dma_slot_rx_i + ${xheep.get_rh().get_node_ports(xheep.get_mcu_node()).strip(",")} ); import core_v_mini_mcu_pkg::*; @@ -130,17 +127,12 @@ ${pad.core_v_mini_mcu_interface} // irq signals logic irq_ack; logic [4:0] irq_id_out; - logic irq_software; - logic irq_external; logic [14:0] irq_fast; // Memory Map SPI Region obi_req_t flash_mem_slave_req; obi_resp_t flash_mem_slave_resp; - // rv_timer - logic [3:0] rv_timer_intr; - // interrupt array logic [31:0] intr; logic [14:0] fast_intr; @@ -157,52 +149,25 @@ ${pad.core_v_mini_mcu_interface} logic peripheral_subsystem_clkgate_en_n; logic [core_v_mini_mcu_pkg::NUM_BANKS-1:0]memory_subsystem_clkgate_en_n; - // DMA - logic dma_done_intr; - logic dma_window_intr; - - // SPI - logic spi_flash_intr, spi_intr, spi_rx_valid, spi_tx_ready; - - // GPIO - logic [31:8] gpio_in; - logic [31:8] gpio_out; - logic [31:8] gpio_oe; - - // GPIO_AO - logic [7:0] gpio_ao_in; - logic [7:0] gpio_ao_out; - logic [7:0] gpio_ao_oe; - logic [7:0] gpio_ao_intr; - - // UART PLIC interrupts - logic uart_intr_tx_watermark; - logic uart_intr_rx_watermark; - logic uart_intr_tx_empty; - logic uart_intr_rx_overflow; - logic uart_intr_rx_frame_err; - logic uart_intr_rx_break_err; - logic uart_intr_rx_timeout; - logic uart_intr_rx_parity_err; - - // I2s - logic i2s_rx_valid; - assign intr = { - 1'b0, irq_fast, 4'b0, irq_external, 3'b0, rv_timer_intr[0], 3'b0, irq_software, 3'b0 - }; + // Auto generated + ${xheep.get_rh().get_node_local_signals(xheep.get_mcu_node())} - assign fast_intr = { + assign intr = { 1'b0, - gpio_ao_intr, - spi_flash_intr, - spi_intr, - dma_done_intr, - rv_timer_intr[3], - rv_timer_intr[2], - rv_timer_intr[1] + irq_fast, + 4'b0, + ${xheep.get_rh().use_target_as_sv("irq_external", xheep.get_mcu_node())}, + 3'b0, + ${xheep.get_rh().use_target_as_sv("rv_timer_0_direct_irq", xheep.get_mcu_node())}, + 3'b0, + ${xheep.get_rh().use_target_as_sv("irq_software", xheep.get_mcu_node())}, + 3'b0 }; + assign fast_intr = ${xheep.get_rh().use_target_as_sv_array_multi("fast_irq_target", xheep.get_mcu_node(), 15)}; + + cpu_subsystem #( .BOOT_ADDR(BOOT_ADDR), .COREV_PULP(COREV_PULP), @@ -237,11 +202,11 @@ ${pad.core_v_mini_mcu_interface} ) debug_subsystem_i ( .clk_i, .rst_ni, - .jtag_tck_i, - .jtag_tms_i, - .jtag_trst_ni, - .jtag_tdi_i, - .jtag_tdo_o, + .jtag_tck_i(${xheep.get_rh().use_source_as_sv("jtag_tck", xheep.get_mcu_node())}), + .jtag_tms_i(${xheep.get_rh().use_source_as_sv("jtag_tms", xheep.get_mcu_node())}), + .jtag_trst_ni(${xheep.get_rh().use_source_as_sv("jtag_trst_n", xheep.get_mcu_node())}), + .jtag_tdi_i(${xheep.get_rh().use_source_as_sv("jtag_tdi", xheep.get_mcu_node())}), + .jtag_tdo_o(${xheep.get_rh().use_source_as_sv("jtag_tdo", xheep.get_mcu_node())}), .debug_core_req_o(debug_core_req), .debug_ndmreset_no(debug_reset_n), .debug_slave_req_i(debug_slave_req), @@ -310,19 +275,9 @@ ${pad.core_v_mini_mcu_interface} .rst_ni(rst_ni && debug_reset_n), .slave_req_i(ao_peripheral_slave_req), .slave_resp_o(ao_peripheral_slave_resp), - .boot_select_i, - .execute_from_flash_i, - .exit_valid_o, .exit_value_o, .spimemio_req_i(flash_mem_slave_req), .spimemio_resp_o(flash_mem_slave_resp), - .spi_flash_sck_o, - .spi_flash_sck_en_o(spi_flash_sck_oe_o), - .spi_flash_csb_o({spi_flash_cs_1_o,spi_flash_cs_0_o}), - .spi_flash_csb_en_o({spi_flash_cs_1_oe_o, spi_flash_cs_0_oe_o}), - .spi_flash_sd_o({spi_flash_sd_3_o,spi_flash_sd_2_o, spi_flash_sd_1_o, spi_flash_sd_0_o}), - .spi_flash_sd_en_o({spi_flash_sd_3_oe_o,spi_flash_sd_2_oe_o, spi_flash_sd_1_oe_o, spi_flash_sd_0_oe_o}), - .spi_flash_sd_i({spi_flash_sd_3_i,spi_flash_sd_2_i, spi_flash_sd_1_i, spi_flash_sd_0_i}), .intr_i(intr), .intr_vector_ext_i, .core_sleep_i(core_sleep), @@ -346,203 +301,30 @@ ${pad.core_v_mini_mcu_interface} .peripheral_subsystem_clkgate_en_no(peripheral_subsystem_clkgate_en_n), .memory_subsystem_clkgate_en_no(memory_subsystem_clkgate_en_n), .external_subsystem_clkgate_en_no, - .rv_timer_0_intr_o(rv_timer_intr[0]), - .rv_timer_1_intr_o(rv_timer_intr[1]), .dma_read_ch0_req_o(dma_read_ch0_req), .dma_read_ch0_resp_i(dma_read_ch0_resp), .dma_write_ch0_req_o(dma_write_ch0_req), .dma_write_ch0_resp_i(dma_write_ch0_resp), .dma_addr_ch0_req_o(dma_addr_ch0_req), .dma_addr_ch0_resp_i(dma_addr_ch0_resp), - .dma_done_intr_o(dma_done_intr), - .dma_window_intr_o(dma_window_intr), - .spi_flash_intr_event_o(spi_flash_intr), .pad_req_o, .pad_resp_i, .fast_intr_i(fast_intr), .fast_intr_o(irq_fast), - .cio_gpio_i(gpio_ao_in), - .cio_gpio_o(gpio_ao_out), - .cio_gpio_en_o(gpio_ao_oe), - .intr_gpio_o(gpio_ao_intr), - .uart_rx_i, - .uart_tx_o, - .uart_intr_tx_watermark_o(uart_intr_tx_watermark), - .uart_intr_rx_watermark_o(uart_intr_rx_watermark), - .uart_intr_tx_empty_o(uart_intr_tx_empty), - .uart_intr_rx_overflow_o(uart_intr_rx_overflow), - .uart_intr_rx_frame_err_o(uart_intr_rx_frame_err), - .uart_intr_rx_break_err_o(uart_intr_rx_break_err), - .uart_intr_rx_timeout_o(uart_intr_rx_timeout), - .uart_intr_rx_parity_err_o(uart_intr_rx_parity_err), - .spi_rx_valid_i(spi_rx_valid), - .spi_tx_ready_i(spi_tx_ready), - .i2s_rx_valid_i(i2s_rx_valid), .ext_peripheral_slave_req_o, .ext_peripheral_slave_resp_i, - .ext_dma_slot_tx_i, - .ext_dma_slot_rx_i + ${xheep.get_rh().get_instantiation_signals(xheep.get_ao_node()).strip(",")} ); - +<% + domain = next(xheep.iter_peripheral_domains_normal()) +%> peripheral_subsystem peripheral_subsystem_i ( .clk_i, .rst_ni(peripheral_subsystem_rst_n && debug_reset_n), .clk_gate_en_ni(peripheral_subsystem_clkgate_en_n), .slave_req_i(peripheral_slave_req), .slave_resp_o(peripheral_slave_resp), - .intr_vector_ext_i, - .irq_plic_o(irq_external), - .msip_o(irq_software), - .uart_intr_tx_watermark_i(uart_intr_tx_watermark), - .uart_intr_rx_watermark_i(uart_intr_rx_watermark), - .uart_intr_tx_empty_i(uart_intr_tx_empty), - .uart_intr_rx_overflow_i(uart_intr_rx_overflow), - .uart_intr_rx_frame_err_i(uart_intr_rx_frame_err), - .uart_intr_rx_break_err_i(uart_intr_rx_break_err), - .uart_intr_rx_timeout_i(uart_intr_rx_timeout), - .uart_intr_rx_parity_err_i(uart_intr_rx_parity_err), - .dma_window_intr_i(dma_window_intr), - .cio_gpio_i(gpio_in), - .cio_gpio_o(gpio_out), - .cio_gpio_en_o(gpio_oe), - .cio_scl_i(i2c_scl_i), - .cio_scl_o(i2c_scl_o), - .cio_scl_en_o(i2c_scl_oe_o), - .cio_sda_i(i2c_sda_i), - .cio_sda_o(i2c_sda_o), - .cio_sda_en_o(i2c_sda_oe_o), - .spi_sck_o, - .spi_sck_en_o(spi_sck_oe_o), - .spi_csb_o({spi_cs_1_o,spi_cs_0_o}), - .spi_csb_en_o({spi_cs_1_oe_o, spi_cs_0_oe_o}), - .spi_sd_o({spi_sd_3_o,spi_sd_2_o, spi_sd_1_o, spi_sd_0_o}), - .spi_sd_en_o({spi_sd_3_oe_o,spi_sd_2_oe_o, spi_sd_1_oe_o, spi_sd_0_oe_o}), - .spi_sd_i({spi_sd_3_i,spi_sd_2_i, spi_sd_1_i, spi_sd_0_i}), - .spi_intr_event_o(spi_intr), - .spi_rx_valid_o(spi_rx_valid), - .spi_tx_ready_o(spi_tx_ready), - .spi2_sck_o, - .spi2_sck_en_o(spi2_sck_oe_o), - .spi2_csb_o({spi2_cs_1_o, spi2_cs_0_o}), - .spi2_csb_en_o({spi2_cs_1_oe_o, spi2_cs_0_oe_o}), - .spi2_sd_o({spi2_sd_3_o, spi2_sd_2_o, spi2_sd_1_o, spi2_sd_0_o}), - .spi2_sd_en_o({spi2_sd_3_oe_o, spi2_sd_2_oe_o, spi2_sd_1_oe_o, spi2_sd_0_oe_o}), - .spi2_sd_i({spi2_sd_3_i, spi2_sd_2_i, spi2_sd_1_i, spi2_sd_0_i}), - .rv_timer_2_intr_o(rv_timer_intr[2]), - .rv_timer_3_intr_o(rv_timer_intr[3]), - .pdm2pcm_clk_o(pdm2pcm_clk_o), - .pdm2pcm_clk_en_o(pdm2pcm_clk_oe_o), - .pdm2pcm_pdm_i(pdm2pcm_pdm_i), - .i2s_sck_o(i2s_sck_o), - .i2s_sck_oe_o(i2s_sck_oe_o), - .i2s_sck_i(i2s_sck_i), - .i2s_ws_o(i2s_ws_o), - .i2s_ws_oe_o(i2s_ws_oe_o), - .i2s_ws_i(i2s_ws_i), - .i2s_sd_o(i2s_sd_o), - .i2s_sd_oe_o(i2s_sd_oe_o), - .i2s_sd_i(i2s_sd_i), - .i2s_rx_valid_o(i2s_rx_valid) + ${xheep.get_rh().get_instantiation_signals(domain.get_node()).strip(",")} ); - assign pdm2pcm_pdm_o = 0; - assign pdm2pcm_pdm_oe_o = 0; - - assign gpio_ao_in[0] = gpio_0_i; - assign gpio_0_o = gpio_ao_out[0]; - assign gpio_0_oe_o = gpio_ao_oe[0]; - assign gpio_ao_in[1] = gpio_1_i; - assign gpio_1_o = gpio_ao_out[1]; - assign gpio_1_oe_o = gpio_ao_oe[1]; - assign gpio_ao_in[2] = gpio_2_i; - assign gpio_2_o = gpio_ao_out[2]; - assign gpio_2_oe_o = gpio_ao_oe[2]; - assign gpio_ao_in[3] = gpio_3_i; - assign gpio_3_o = gpio_ao_out[3]; - assign gpio_3_oe_o = gpio_ao_oe[3]; - assign gpio_ao_in[4] = gpio_4_i; - assign gpio_4_o = gpio_ao_out[4]; - assign gpio_4_oe_o = gpio_ao_oe[4]; - assign gpio_ao_in[5] = gpio_5_i; - assign gpio_5_o = gpio_ao_out[5]; - assign gpio_5_oe_o = gpio_ao_oe[5]; - assign gpio_ao_in[6] = gpio_6_i; - assign gpio_6_o = gpio_ao_out[6]; - assign gpio_6_oe_o = gpio_ao_oe[6]; - assign gpio_ao_in[7] = gpio_7_i; - assign gpio_7_o = gpio_ao_out[7]; - assign gpio_7_oe_o = gpio_ao_oe[7]; - assign gpio_in[8] = gpio_8_i; - assign gpio_8_o = gpio_out[8]; - assign gpio_8_oe_o = gpio_oe[8]; - assign gpio_in[9] = gpio_9_i; - assign gpio_9_o = gpio_out[9]; - assign gpio_9_oe_o = gpio_oe[9]; - assign gpio_in[10] = gpio_10_i; - assign gpio_10_o = gpio_out[10]; - assign gpio_10_oe_o = gpio_oe[10]; - assign gpio_in[11] = gpio_11_i; - assign gpio_11_o = gpio_out[11]; - assign gpio_11_oe_o = gpio_oe[11]; - assign gpio_in[12] = gpio_12_i; - assign gpio_12_o = gpio_out[12]; - assign gpio_12_oe_o = gpio_oe[12]; - assign gpio_in[13] = gpio_13_i; - assign gpio_13_o = gpio_out[13]; - assign gpio_13_oe_o = gpio_oe[13]; - assign gpio_in[14] = gpio_14_i; - assign gpio_14_o = gpio_out[14]; - assign gpio_14_oe_o = gpio_oe[14]; - assign gpio_in[15] = gpio_15_i; - assign gpio_15_o = gpio_out[15]; - assign gpio_15_oe_o = gpio_oe[15]; - assign gpio_in[16] = gpio_16_i; - assign gpio_16_o = gpio_out[16]; - assign gpio_16_oe_o = gpio_oe[16]; - assign gpio_in[17] = gpio_17_i; - assign gpio_17_o = gpio_out[17]; - assign gpio_17_oe_o = gpio_oe[17]; - assign gpio_in[18] = gpio_18_i; - assign gpio_18_o = gpio_out[18]; - assign gpio_18_oe_o = gpio_oe[18]; - assign gpio_in[19] = gpio_19_i; - assign gpio_19_o = gpio_out[19]; - assign gpio_19_oe_o = gpio_oe[19]; - assign gpio_in[20] = gpio_20_i; - assign gpio_20_o = gpio_out[20]; - assign gpio_20_oe_o = gpio_oe[20]; - assign gpio_in[21] = gpio_21_i; - assign gpio_21_o = gpio_out[21]; - assign gpio_21_oe_o = gpio_oe[21]; - assign gpio_in[22] = gpio_22_i; - assign gpio_22_o = gpio_out[22]; - assign gpio_22_oe_o = gpio_oe[22]; - assign gpio_in[23] = gpio_23_i; - assign gpio_23_o = gpio_out[23]; - assign gpio_23_oe_o = gpio_oe[23]; - assign gpio_in[24] = gpio_24_i; - assign gpio_24_o = gpio_out[24]; - assign gpio_24_oe_o = gpio_oe[24]; - assign gpio_in[25] = gpio_25_i; - assign gpio_25_o = gpio_out[25]; - assign gpio_25_oe_o = gpio_oe[25]; - assign gpio_in[26] = gpio_26_i; - assign gpio_26_o = gpio_out[26]; - assign gpio_26_oe_o = gpio_oe[26]; - assign gpio_in[27] = gpio_27_i; - assign gpio_27_o = gpio_out[27]; - assign gpio_27_oe_o = gpio_oe[27]; - assign gpio_in[28] = gpio_28_i; - assign gpio_28_o = gpio_out[28]; - assign gpio_28_oe_o = gpio_oe[28]; - assign gpio_in[29] = gpio_29_i; - assign gpio_29_o = gpio_out[29]; - assign gpio_29_oe_o = gpio_oe[29]; - assign gpio_in[30] = gpio_30_i; - assign gpio_30_o = gpio_out[30]; - assign gpio_30_oe_o = gpio_oe[30]; - assign gpio_in[31] = gpio_31_i; - assign gpio_31_o = gpio_out[31]; - assign gpio_31_oe_o = gpio_oe[31]; - endmodule // core_v_mini_mcu diff --git a/hw/core-v-mini-mcu/generated_if.sv.tpl b/hw/core-v-mini-mcu/generated_if.sv.tpl new file mode 100644 index 000000000..4bd680b91 --- /dev/null +++ b/hw/core-v-mini-mcu/generated_if.sv.tpl @@ -0,0 +1,8 @@ +/* verilator lint_off DECLFILENAME */ + +% for intf in xheep.get_rh().get_intf_sv_helpers(): +${intf.get_def()} + +% endfor + +/* verilator lint_on DECLFILENAME */ diff --git a/hw/core-v-mini-mcu/include/core_v_mini_mcu_pkg.sv.tpl b/hw/core-v-mini-mcu/include/core_v_mini_mcu_pkg.sv.tpl index c8732ce6d..1914752b8 100644 --- a/hw/core-v-mini-mcu/include/core_v_mini_mcu_pkg.sv.tpl +++ b/hw/core-v-mini-mcu/include/core_v_mini_mcu_pkg.sv.tpl @@ -48,7 +48,7 @@ package core_v_mini_mcu_pkg; //must be power of two localparam int unsigned MEM_SIZE = 32'h${f'{xheep.ram_size_address():08X}'}; - localparam SYSTEM_XBAR_NSLAVE = ${xheep.ram_numbanks() + 5}; + localparam SYSTEM_XBAR_NSLAVE = ${xheep.ram_numbanks() + 3 + xheep.num_peripheral_domains()}; localparam int unsigned LOG_SYSTEM_XBAR_NMASTER = SYSTEM_XBAR_NMASTER > 1 ? $clog2(SYSTEM_XBAR_NMASTER) : 32'd1; localparam int unsigned LOG_SYSTEM_XBAR_NSLAVE = SYSTEM_XBAR_NSLAVE > 1 ? $clog2(SYSTEM_XBAR_NSLAVE) : 32'd1; @@ -81,20 +81,17 @@ package core_v_mini_mcu_pkg; localparam logic[31:0] DEBUG_END_ADDRESS = DEBUG_START_ADDRESS + DEBUG_SIZE; localparam logic[31:0] DEBUG_IDX = 32'd${xheep.ram_numbanks() + 1}; - localparam logic[31:0] AO_PERIPHERAL_START_ADDRESS = 32'h${ao_peripheral_start_address}; - localparam logic[31:0] AO_PERIPHERAL_SIZE = 32'h${ao_peripheral_size_address}; - localparam logic[31:0] AO_PERIPHERAL_END_ADDRESS = AO_PERIPHERAL_START_ADDRESS + AO_PERIPHERAL_SIZE; - localparam logic[31:0] AO_PERIPHERAL_IDX = 32'd${xheep.ram_numbanks() + 2}; - - localparam logic[31:0] PERIPHERAL_START_ADDRESS = 32'h${peripheral_start_address}; - localparam logic[31:0] PERIPHERAL_SIZE = 32'h${peripheral_size_address}; - localparam logic[31:0] PERIPHERAL_END_ADDRESS = PERIPHERAL_START_ADDRESS + PERIPHERAL_SIZE; - localparam logic[31:0] PERIPHERAL_IDX = 32'd${xheep.ram_numbanks() + 3}; +% for i, domain in enumerate(xheep.iter_peripheral_domains()): + localparam logic[31:0] ${domain.get_name().upper()}_START_ADDRESS = 32'h${f"{domain.get_address():08X}"}; + localparam logic[31:0] ${domain.get_name().upper()}_SIZE = 32'h${f"{domain.get_address_length():08X}"}; + localparam logic[31:0] ${domain.get_name().upper()}_END_ADDRESS = ${domain.get_name().upper()}_START_ADDRESS + ${domain.get_name().upper()}_SIZE; + localparam logic[31:0] ${domain.get_name().upper()}_IDX = 32'd${xheep.ram_numbanks() + 2 + i}; +% endfor localparam logic[31:0] FLASH_MEM_START_ADDRESS = 32'h${flash_mem_start_address}; localparam logic[31:0] FLASH_MEM_SIZE = 32'h${flash_mem_size_address}; localparam logic[31:0] FLASH_MEM_END_ADDRESS = FLASH_MEM_START_ADDRESS + FLASH_MEM_SIZE; - localparam logic[31:0] FLASH_MEM_IDX = 32'd${xheep.ram_numbanks() + 4}; + localparam logic[31:0] FLASH_MEM_IDX = 32'd${xheep.ram_numbanks() + 3 + i}; localparam addr_map_rule_t [SYSTEM_XBAR_NSLAVE-1:0] XBAR_ADDR_RULES = '{ '{ idx: ERROR_IDX, start_addr: ERROR_START_ADDRESS, end_addr: ERROR_END_ADDRESS }, @@ -102,8 +99,9 @@ package core_v_mini_mcu_pkg; '{ idx: RAM${bank.name()}_IDX, start_addr: RAM${bank.name()}_START_ADDRESS, end_addr: RAM${bank.name()}_END_ADDRESS }, % endfor '{ idx: DEBUG_IDX, start_addr: DEBUG_START_ADDRESS, end_addr: DEBUG_END_ADDRESS }, - '{ idx: AO_PERIPHERAL_IDX, start_addr: AO_PERIPHERAL_START_ADDRESS, end_addr: AO_PERIPHERAL_END_ADDRESS }, - '{ idx: PERIPHERAL_IDX, start_addr: PERIPHERAL_START_ADDRESS, end_addr: PERIPHERAL_END_ADDRESS }, +% for domain in xheep.iter_peripheral_domains(): + '{ idx: ${domain.get_name().upper()}_IDX, start_addr: ${domain.get_name().upper()}_START_ADDRESS, end_addr: ${domain.get_name().upper()}_END_ADDRESS }, +% endfor '{ idx: FLASH_MEM_IDX, start_addr: FLASH_MEM_START_ADDRESS, end_addr: FLASH_MEM_END_ADDRESS } }; @@ -131,62 +129,41 @@ package core_v_mini_mcu_pkg; } }; -###################################################################### -## Automatically add all always on peripherals listed -###################################################################### - // always-on peripherals - // --------------------- - localparam AO_PERIPHERALS = ${ao_peripherals_count}; - -% for peripheral, addr in ao_peripherals.items(): - localparam logic [31:0] ${peripheral.upper()}_START_ADDRESS = AO_PERIPHERAL_START_ADDRESS + 32'h${addr["offset"]}; - localparam logic [31:0] ${peripheral.upper()}_SIZE = 32'h${addr["length"]}; - localparam logic [31:0] ${peripheral.upper()}_END_ADDRESS = ${peripheral.upper()}_START_ADDRESS + ${peripheral.upper()}_SIZE; - localparam logic [31:0] ${peripheral.upper()}_IDX = 32'd${loop.index}; - -% endfor - localparam addr_map_rule_t [AO_PERIPHERALS-1:0] AO_PERIPHERALS_ADDR_RULES = '{ -% for peripheral, addr in ao_peripherals.items(): - '{ idx: ${peripheral.upper()}_IDX, start_addr: ${peripheral.upper()}_START_ADDRESS, end_addr: ${peripheral.upper()}_END_ADDRESS }${"," if not loop.last else ""} -% endfor - }; - localparam int unsigned AO_PERIPHERALS_PORT_SEL_WIDTH = AO_PERIPHERALS > 1 ? $clog2(AO_PERIPHERALS) : 32'd1; ###################################################################### ## Automatically add all peripherals listed ###################################################################### - // switch-on/off peripherals - // ------------------------- - localparam PERIPHERALS = ${peripherals_count}; - -% for peripheral, addr in peripherals.items(): - localparam logic [31:0] ${peripheral.upper()}_START_ADDRESS = PERIPHERAL_START_ADDRESS + 32'h${addr["offset"]}; - localparam logic [31:0] ${peripheral.upper()}_SIZE = 32'h${addr["length"]}; - localparam logic [31:0] ${peripheral.upper()}_END_ADDRESS = ${peripheral.upper()}_START_ADDRESS + ${peripheral.upper()}_SIZE; - localparam logic [31:0] ${peripheral.upper()}_IDX = 32'd${loop.index}; +% for domain in xheep.iter_peripheral_domains(): + localparam ${domain.get_name().upper()}_COUNT = ${domain.peripheral_count()}; + +% for i, periph in enumerate(domain.iter_peripherals()): + localparam logic [31:0] ${periph.full_name.upper()}_START_ADDRESS = ${domain.get_name().upper()}_START_ADDRESS + 32'h${f"{periph.get_offset():08X}"}; + localparam logic [31:0] ${periph.full_name.upper()}_SIZE = 32'h${f"{periph.get_address_length():08X}"}; + localparam logic [31:0] ${periph.full_name.upper()}_END_ADDRESS = ${periph.full_name.upper()}_START_ADDRESS + ${periph.full_name.upper()}_SIZE; + localparam logic [31:0] ${periph.full_name.upper()}_IDX = 32'd${i}; % endfor - localparam addr_map_rule_t [PERIPHERALS-1:0] PERIPHERALS_ADDR_RULES = '{ -% for peripheral, addr in peripherals.items(): - '{ idx: ${peripheral.upper()}_IDX, start_addr: ${peripheral.upper()}_START_ADDRESS, end_addr: ${peripheral.upper()}_END_ADDRESS }${"," if not loop.last else ""} + localparam addr_map_rule_t [${domain.get_name().upper()}_COUNT-1:0] ${domain.get_name().upper()}_ADDR_RULES = '{ +% for i, periph in enumerate(domain.iter_peripherals()): + '{ idx: ${periph.full_name.upper()}_IDX, start_addr: ${periph.full_name.upper()}_START_ADDRESS, end_addr: ${periph.full_name.upper()}_END_ADDRESS }${"," if i < domain.peripheral_count()-1 else ""} % endfor }; - localparam int unsigned PERIPHERALS_PORT_SEL_WIDTH = PERIPHERALS > 1 ? $clog2(PERIPHERALS) : 32'd1; + localparam int unsigned ${domain.get_name().upper()}_PORT_SEL_WIDTH = ${domain.get_name().upper()}_COUNT > 1 ? $clog2(${domain.get_name().upper()}_COUNT) : 32'd1; + +% endfor // Interrupts // ---------- - localparam PLIC_NINT = ${plit_n_interrupts}; - localparam PLIC_USED_NINT = ${plic_used_n_interrupts}; - localparam NEXT_INT = PLIC_NINT - PLIC_USED_NINT; + localparam NEXT_INT = ${xheep.get_ext_intr()}; -% for pad in total_pad_list: - localparam ${pad.localparam} = ${pad.index}; +% for i, name in enumerate(xheep.get_pad_manager().iterate_pad_index()): + localparam ${name} = ${i}; % endfor - localparam NUM_PAD = ${total_pad}; - localparam NUM_PAD_MUXED = ${total_pad_muxed}; + localparam NUM_PAD = ${xheep.get_pad_manager().get_pad_num()}; + localparam NUM_PAD_MUXED = ${xheep.get_pad_manager().get_muxed_pad_num()}; localparam int unsigned NUM_PAD_PORT_SEL_WIDTH = NUM_PAD > 1 ? $clog2(NUM_PAD) : 32'd1; diff --git a/hw/core-v-mini-mcu/peripheral_subsystem.sv b/hw/core-v-mini-mcu/peripheral_subsystem.sv deleted file mode 100644 index fd7ac4c31..000000000 --- a/hw/core-v-mini-mcu/peripheral_subsystem.sv +++ /dev/null @@ -1,473 +0,0 @@ -// Copyright(// Copyright) 2022 OpenHW Group -// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. -// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 - -module peripheral_subsystem - import obi_pkg::*; - import reg_pkg::*; -#( - //do not touch these parameters - parameter NEXT_INT_RND = core_v_mini_mcu_pkg::NEXT_INT == 0 ? 1 : core_v_mini_mcu_pkg::NEXT_INT -) ( - input logic clk_i, - input logic rst_ni, - - // Clock-gating signal - input logic clk_gate_en_ni, - - input obi_req_t slave_req_i, - output obi_resp_t slave_resp_o, - - //PLIC - input logic [NEXT_INT_RND-1:0] intr_vector_ext_i, - output logic irq_plic_o, - output logic msip_o, - - //UART PLIC interrupts - input logic uart_intr_tx_watermark_i, - input logic uart_intr_rx_watermark_i, - input logic uart_intr_tx_empty_i, - input logic uart_intr_rx_overflow_i, - input logic uart_intr_rx_frame_err_i, - input logic uart_intr_rx_break_err_i, - input logic uart_intr_rx_timeout_i, - input logic uart_intr_rx_parity_err_i, - - // DMA window PLIC interrupt - input logic dma_window_intr_i, - - //GPIO - input logic [31:8] cio_gpio_i, - output logic [31:8] cio_gpio_o, - output logic [31:8] cio_gpio_en_o, - - // I2C Interface - input logic cio_scl_i, - output logic cio_scl_o, - output logic cio_scl_en_o, - input logic cio_sda_i, - output logic cio_sda_o, - output logic cio_sda_en_o, - - // SPI Host - output logic spi_sck_o, - output logic spi_sck_en_o, - output logic [spi_host_reg_pkg::NumCS-1:0] spi_csb_o, - output logic [spi_host_reg_pkg::NumCS-1:0] spi_csb_en_o, - output logic [ 3:0] spi_sd_o, - output logic [ 3:0] spi_sd_en_o, - input logic [ 3:0] spi_sd_i, - output logic spi_intr_event_o, - output logic spi_rx_valid_o, - output logic spi_tx_ready_o, - - // SPI 2 Host - output logic spi2_sck_o, - output logic spi2_sck_en_o, - output logic [spi_host_reg_pkg::NumCS-1:0] spi2_csb_o, - output logic [spi_host_reg_pkg::NumCS-1:0] spi2_csb_en_o, - output logic [ 3:0] spi2_sd_o, - output logic [ 3:0] spi2_sd_en_o, - input logic [ 3:0] spi2_sd_i, - - //RV TIMER - output logic rv_timer_2_intr_o, - output logic rv_timer_3_intr_o, - - //I2s - output logic i2s_sck_o, - output logic i2s_sck_oe_o, - input logic i2s_sck_i, - output logic i2s_ws_o, - output logic i2s_ws_oe_o, - input logic i2s_ws_i, - output logic i2s_sd_o, - output logic i2s_sd_oe_o, - input logic i2s_sd_i, - output logic i2s_rx_valid_o, - - // PDM2PCM Interface - output logic pdm2pcm_clk_o, - output logic pdm2pcm_clk_en_o, - input logic pdm2pcm_pdm_i -); - - import core_v_mini_mcu_pkg::*; - import tlul_pkg::*; - import rv_plic_reg_pkg::*; - - reg_pkg::reg_req_t peripheral_req; - reg_pkg::reg_rsp_t peripheral_rsp; - - reg_pkg::reg_req_t [core_v_mini_mcu_pkg::PERIPHERALS-1:0] peripheral_slv_req; - reg_pkg::reg_rsp_t [core_v_mini_mcu_pkg::PERIPHERALS-1:0] peripheral_slv_rsp; - - tlul_pkg::tl_h2d_t plic_tl_h2d; - tlul_pkg::tl_d2h_t plic_tl_d2h; - - tlul_pkg::tl_h2d_t i2c_tl_h2d; - tlul_pkg::tl_d2h_t i2c_tl_d2h; - - tlul_pkg::tl_h2d_t rv_timer_tl_h2d; - tlul_pkg::tl_d2h_t rv_timer_tl_d2h; - - logic [rv_plic_reg_pkg::NumTarget-1:0] irq_plic; - logic [rv_plic_reg_pkg::NumSrc-1:0] intr_vector; - logic [$clog2(rv_plic_reg_pkg::NumSrc)-1:0] irq_id[rv_plic_reg_pkg::NumTarget]; - logic [$clog2(rv_plic_reg_pkg::NumSrc)-1:0] unused_irq_id[rv_plic_reg_pkg::NumTarget]; - - logic [31:8] gpio_intr; - logic [7:0] cio_gpio_unused; - logic [7:0] cio_gpio_en_unused; - logic [7:0] gpio_int_unused; - - logic i2c_intr_fmt_watermark; - logic i2c_intr_rx_watermark; - logic i2c_intr_fmt_overflow; - logic i2c_intr_rx_overflow; - logic i2c_intr_nak; - logic i2c_intr_scl_interference; - logic i2c_intr_sda_interference; - logic i2c_intr_stretch_timeout; - logic i2c_intr_sda_unstable; - logic i2c_intr_trans_complete; - logic i2c_intr_tx_empty; - logic i2c_intr_tx_nonempty; - logic i2c_intr_tx_overflow; - logic i2c_intr_acq_overflow; - logic i2c_intr_ack_stop; - logic i2c_intr_host_timeout; - logic spi2_intr_event; - logic i2s_intr_event; - - // this avoids lint errors - assign unused_irq_id = irq_id; - - // Assign internal interrupts - assign intr_vector[0] = 1'b0; // ID [0] is a special case and must be tied to zero. - assign intr_vector[1] = uart_intr_tx_watermark_i; - assign intr_vector[2] = uart_intr_rx_watermark_i; - assign intr_vector[3] = uart_intr_tx_empty_i; - assign intr_vector[4] = uart_intr_rx_overflow_i; - assign intr_vector[5] = uart_intr_rx_frame_err_i; - assign intr_vector[6] = uart_intr_rx_break_err_i; - assign intr_vector[7] = uart_intr_rx_timeout_i; - assign intr_vector[8] = uart_intr_rx_parity_err_i; - assign intr_vector[32:9] = gpio_intr; - assign intr_vector[33] = i2c_intr_fmt_watermark; - assign intr_vector[34] = i2c_intr_rx_watermark; - assign intr_vector[35] = i2c_intr_fmt_overflow; - assign intr_vector[36] = i2c_intr_rx_overflow; - assign intr_vector[37] = i2c_intr_nak; - assign intr_vector[38] = i2c_intr_scl_interference; - assign intr_vector[39] = i2c_intr_sda_interference; - assign intr_vector[40] = i2c_intr_stretch_timeout; - assign intr_vector[41] = i2c_intr_sda_unstable; - assign intr_vector[42] = i2c_intr_trans_complete; - assign intr_vector[43] = i2c_intr_tx_empty; - assign intr_vector[44] = i2c_intr_tx_nonempty; - assign intr_vector[45] = i2c_intr_tx_overflow; - assign intr_vector[46] = i2c_intr_acq_overflow; - assign intr_vector[47] = i2c_intr_ack_stop; - assign intr_vector[48] = i2c_intr_host_timeout; - assign intr_vector[49] = spi2_intr_event; - assign intr_vector[50] = i2s_intr_event; - assign intr_vector[51] = dma_window_intr_i; - - // External interrupts assignement - for (genvar i = 0; i < NEXT_INT; i++) begin - assign intr_vector[i+PLIC_USED_NINT] = intr_vector_ext_i[i]; - end - - //Address Decoder - logic [PERIPHERALS_PORT_SEL_WIDTH-1:0] peripheral_select; - - obi_pkg::obi_req_t slave_fifo_req_sel; - obi_pkg::obi_resp_t slave_fifo_resp_sel; - - // Clock-gating - logic clk_cg; - tc_clk_gating clk_gating_cell ( - .clk_i, - .en_i(clk_gate_en_ni), - .test_en_i(1'b0), - .clk_o(clk_cg) - ); - - -`ifdef REMOVE_OBI_FIFO - - assign slave_fifo_req_sel = slave_req_i; - assign slave_resp_o = slave_fifo_resp_sel; - -`else - - obi_pkg::obi_req_t slave_fifoin_req; - obi_pkg::obi_resp_t slave_fifoin_resp; - - obi_pkg::obi_req_t slave_fifoout_req; - obi_pkg::obi_resp_t slave_fifoout_resp; - - obi_fifo obi_fifo_i ( - .clk_i(clk_cg), - .rst_ni, - .producer_req_i(slave_fifoin_req), - .producer_resp_o(slave_fifoin_resp), - .consumer_req_o(slave_fifoout_req), - .consumer_resp_i(slave_fifoout_resp) - ); - - assign slave_fifo_req_sel = slave_fifoout_req; - assign slave_fifoout_resp = slave_fifo_resp_sel; - assign slave_fifoin_req = slave_req_i; - assign slave_resp_o = slave_fifoin_resp; - -`endif - - periph_to_reg #( - .req_t(reg_pkg::reg_req_t), - .rsp_t(reg_pkg::reg_rsp_t), - .IW(1) - ) periph_to_reg_i ( - .clk_i(clk_cg), - .rst_ni, - .req_i(slave_fifo_req_sel.req), - .add_i(slave_fifo_req_sel.addr), - .wen_i(~slave_fifo_req_sel.we), - .wdata_i(slave_fifo_req_sel.wdata), - .be_i(slave_fifo_req_sel.be), - .id_i('0), - .gnt_o(slave_fifo_resp_sel.gnt), - .r_rdata_o(slave_fifo_resp_sel.rdata), - .r_opc_o(), - .r_id_o(), - .r_valid_o(slave_fifo_resp_sel.rvalid), - .reg_req_o(peripheral_req), - .reg_rsp_i(peripheral_rsp) - ); - - addr_decode #( - .NoIndices(core_v_mini_mcu_pkg::PERIPHERALS), - .NoRules(core_v_mini_mcu_pkg::PERIPHERALS), - .addr_t(logic [31:0]), - .rule_t(addr_map_rule_pkg::addr_map_rule_t) - ) i_addr_decode_soc_regbus_periph_xbar ( - .addr_i(peripheral_req.addr), - .addr_map_i(core_v_mini_mcu_pkg::PERIPHERALS_ADDR_RULES), - .idx_o(peripheral_select), - .dec_valid_o(), - .dec_error_o(), - .en_default_idx_i(1'b0), - .default_idx_i('0) - ); - - reg_demux #( - .NoPorts(core_v_mini_mcu_pkg::PERIPHERALS), - .req_t (reg_pkg::reg_req_t), - .rsp_t (reg_pkg::reg_rsp_t) - ) reg_demux_i ( - .clk_i(clk_cg), - .rst_ni, - .in_select_i(peripheral_select), - .in_req_i(peripheral_req), - .in_rsp_o(peripheral_rsp), - .out_req_o(peripheral_slv_req), - .out_rsp_i(peripheral_slv_rsp) - ); - - reg_to_tlul #( - .req_t(reg_pkg::reg_req_t), - .rsp_t(reg_pkg::reg_rsp_t), - .tl_h2d_t(tlul_pkg::tl_h2d_t), - .tl_d2h_t(tlul_pkg::tl_d2h_t), - .tl_a_user_t(tlul_pkg::tl_a_user_t), - .tl_a_op_e(tlul_pkg::tl_a_op_e), - .TL_A_USER_DEFAULT(tlul_pkg::TL_A_USER_DEFAULT), - .PutFullData(tlul_pkg::PutFullData), - .Get(tlul_pkg::Get) - ) reg_to_tlul_plic_i ( - .tl_o(plic_tl_h2d), - .tl_i(plic_tl_d2h), - .reg_req_i(peripheral_slv_req[core_v_mini_mcu_pkg::RV_PLIC_IDX]), - .reg_rsp_o(peripheral_slv_rsp[core_v_mini_mcu_pkg::RV_PLIC_IDX]) - ); - - rv_plic rv_plic_i ( - .clk_i(clk_cg), - .rst_ni, - .tl_i(plic_tl_h2d), - .tl_o(plic_tl_d2h), - .intr_src_i(intr_vector), - .irq_o(irq_plic_o), - .irq_id_o(irq_id), - .msip_o(msip_o) - ); - - spi_host #( - .reg_req_t(reg_pkg::reg_req_t), - .reg_rsp_t(reg_pkg::reg_rsp_t) - ) spi_host_dma_i ( - .clk_i(clk_cg), - .rst_ni, - .reg_req_i(peripheral_slv_req[core_v_mini_mcu_pkg::SPI_HOST_IDX]), - .reg_rsp_o(peripheral_slv_rsp[core_v_mini_mcu_pkg::SPI_HOST_IDX]), - .alert_rx_i(), - .alert_tx_o(), - .passthrough_i(spi_device_pkg::PASSTHROUGH_REQ_DEFAULT), - .passthrough_o(), - .cio_sck_o(spi_sck_o), - .cio_sck_en_o(spi_sck_en_o), - .cio_csb_o(spi_csb_o), - .cio_csb_en_o(spi_csb_en_o), - .cio_sd_o(spi_sd_o), - .cio_sd_en_o(spi_sd_en_o), - .cio_sd_i(spi_sd_i), - .rx_valid_o(spi_rx_valid_o), - .tx_ready_o(spi_tx_ready_o), - .intr_error_o(), - .intr_spi_event_o(spi_intr_event_o) - ); - - - - gpio #( - .reg_req_t(reg_pkg::reg_req_t), - .reg_rsp_t(reg_pkg::reg_rsp_t) - ) gpio_i ( - .clk_i(clk_cg), - .rst_ni, - .reg_req_i(peripheral_slv_req[core_v_mini_mcu_pkg::GPIO_IDX]), - .reg_rsp_o(peripheral_slv_rsp[core_v_mini_mcu_pkg::GPIO_IDX]), - .gpio_in({cio_gpio_i, 8'b0}), - .gpio_out({cio_gpio_o, cio_gpio_unused}), - .gpio_tx_en_o({cio_gpio_en_o, cio_gpio_en_unused}), - .gpio_in_sync_o(), - .pin_level_interrupts_o({gpio_intr, gpio_int_unused}), - .global_interrupt_o() - ); - - reg_to_tlul #( - .req_t(reg_pkg::reg_req_t), - .rsp_t(reg_pkg::reg_rsp_t), - .tl_h2d_t(tlul_pkg::tl_h2d_t), - .tl_d2h_t(tlul_pkg::tl_d2h_t), - .tl_a_user_t(tlul_pkg::tl_a_user_t), - .tl_a_op_e(tlul_pkg::tl_a_op_e), - .TL_A_USER_DEFAULT(tlul_pkg::TL_A_USER_DEFAULT), - .PutFullData(tlul_pkg::PutFullData), - .Get(tlul_pkg::Get) - ) reg_to_tlul_i2c_i ( - .tl_o(i2c_tl_h2d), - .tl_i(i2c_tl_d2h), - .reg_req_i(peripheral_slv_req[core_v_mini_mcu_pkg::I2C_IDX]), - .reg_rsp_o(peripheral_slv_rsp[core_v_mini_mcu_pkg::I2C_IDX]) - ); - - i2c i2c_i ( - .clk_i(clk_cg), - .rst_ni, - .tl_i(i2c_tl_h2d), - .tl_o(i2c_tl_d2h), - .cio_scl_i, - .cio_scl_o, - .cio_scl_en_o, - .cio_sda_i, - .cio_sda_o, - .cio_sda_en_o, - .intr_fmt_watermark_o(i2c_intr_fmt_watermark), - .intr_rx_watermark_o(i2c_intr_rx_watermark), - .intr_fmt_overflow_o(i2c_intr_fmt_overflow), - .intr_rx_overflow_o(i2c_intr_rx_overflow), - .intr_nak_o(i2c_intr_nak), - .intr_scl_interference_o(i2c_intr_scl_interference), - .intr_sda_interference_o(i2c_intr_sda_interference), - .intr_stretch_timeout_o(i2c_intr_stretch_timeout), - .intr_sda_unstable_o(i2c_intr_sda_unstable), - .intr_trans_complete_o(i2c_intr_trans_complete), - .intr_tx_empty_o(i2c_intr_tx_empty), - .intr_tx_nonempty_o(i2c_intr_tx_nonempty), - .intr_tx_overflow_o(i2c_intr_tx_overflow), - .intr_acq_overflow_o(i2c_intr_acq_overflow), - .intr_ack_stop_o(i2c_intr_ack_stop), - .intr_host_timeout_o(i2c_intr_host_timeout) - ); - - reg_to_tlul #( - .req_t(reg_pkg::reg_req_t), - .rsp_t(reg_pkg::reg_rsp_t), - .tl_h2d_t(tlul_pkg::tl_h2d_t), - .tl_d2h_t(tlul_pkg::tl_d2h_t), - .tl_a_user_t(tlul_pkg::tl_a_user_t), - .tl_a_op_e(tlul_pkg::tl_a_op_e), - .TL_A_USER_DEFAULT(tlul_pkg::TL_A_USER_DEFAULT), - .PutFullData(tlul_pkg::PutFullData), - .Get(tlul_pkg::Get) - ) rv_timer_reg_to_tlul_i ( - .tl_o(rv_timer_tl_h2d), - .tl_i(rv_timer_tl_d2h), - .reg_req_i(peripheral_slv_req[core_v_mini_mcu_pkg::RV_TIMER_IDX]), - .reg_rsp_o(peripheral_slv_rsp[core_v_mini_mcu_pkg::RV_TIMER_IDX]) - ); - - rv_timer rv_timer_2_3_i ( - .clk_i(clk_cg), - .rst_ni, - .tl_i(rv_timer_tl_h2d), - .tl_o(rv_timer_tl_d2h), - .intr_timer_expired_0_0_o(rv_timer_2_intr_o), - .intr_timer_expired_1_0_o(rv_timer_3_intr_o) - ); - - spi_host #( - .reg_req_t(reg_pkg::reg_req_t), - .reg_rsp_t(reg_pkg::reg_rsp_t) - ) spi2_host ( - .clk_i(clk_cg), - .rst_ni, - .reg_req_i(peripheral_slv_req[core_v_mini_mcu_pkg::SPI2_IDX]), - .reg_rsp_o(peripheral_slv_rsp[core_v_mini_mcu_pkg::SPI2_IDX]), - .alert_rx_i(), - .alert_tx_o(), - .passthrough_i(spi_device_pkg::PASSTHROUGH_REQ_DEFAULT), - .passthrough_o(), - .cio_sck_o(spi2_sck_o), - .cio_sck_en_o(spi2_sck_en_o), - .cio_csb_o(spi2_csb_o), - .cio_csb_en_o(spi2_csb_en_o), - .cio_sd_o(spi2_sd_o), - .cio_sd_en_o(spi2_sd_en_o), - .cio_sd_i(spi2_sd_i), - .rx_valid_o(), - .tx_ready_o(), - .intr_error_o(), - .intr_spi_event_o(spi2_intr_event) - ); - - assign peripheral_slv_rsp[core_v_mini_mcu_pkg::PDM2PCM_IDX] = '0; - assign pdm2pcm_clk_o = '0; - - assign pdm2pcm_clk_en_o = 1; - - i2s #( - .reg_req_t(reg_pkg::reg_req_t), - .reg_rsp_t(reg_pkg::reg_rsp_t) - ) i2s_i ( - .clk_i, - .rst_ni, - .reg_req_i(peripheral_slv_req[core_v_mini_mcu_pkg::I2S_IDX]), - .reg_rsp_o(peripheral_slv_rsp[core_v_mini_mcu_pkg::I2S_IDX]), - - .i2s_sck_o(i2s_sck_o), - .i2s_sck_oe_o(i2s_sck_oe_o), - .i2s_sck_i(i2s_sck_i), - .i2s_ws_o(i2s_ws_o), - .i2s_ws_oe_o(i2s_ws_oe_o), - .i2s_ws_i(i2s_ws_i), - .i2s_sd_o(i2s_sd_o), - .i2s_sd_oe_o(i2s_sd_oe_o), - .i2s_sd_i(i2s_sd_i), - .intr_i2s_event_o(i2s_intr_event), - .i2s_rx_valid_o(i2s_rx_valid_o) - ); - -endmodule : peripheral_subsystem diff --git a/hw/core-v-mini-mcu/peripheral_subsystem.sv.tpl b/hw/core-v-mini-mcu/peripheral_subsystem.sv.tpl index 12fc624fd..6131a2d8f 100644 --- a/hw/core-v-mini-mcu/peripheral_subsystem.sv.tpl +++ b/hw/core-v-mini-mcu/peripheral_subsystem.sv.tpl @@ -2,6 +2,10 @@ // Solderpad Hardware License, Version 2.1, see LICENSE.md for details. // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +<% + domain = next(xheep.iter_peripheral_domains_normal()) +%> + module peripheral_subsystem import obi_pkg::*; import reg_pkg::*; @@ -18,78 +22,8 @@ module peripheral_subsystem input obi_req_t slave_req_i, output obi_resp_t slave_resp_o, - //PLIC - input logic [NEXT_INT_RND-1:0] intr_vector_ext_i, - output logic irq_plic_o, - output logic msip_o, - - //UART PLIC interrupts - input logic uart_intr_tx_watermark_i, - input logic uart_intr_rx_watermark_i, - input logic uart_intr_tx_empty_i, - input logic uart_intr_rx_overflow_i, - input logic uart_intr_rx_frame_err_i, - input logic uart_intr_rx_break_err_i, - input logic uart_intr_rx_timeout_i, - input logic uart_intr_rx_parity_err_i, - - // DMA window PLIC interrupt - input logic dma_window_intr_i, - - //GPIO - input logic [31:8] cio_gpio_i, - output logic [31:8] cio_gpio_o, - output logic [31:8] cio_gpio_en_o, - - // I2C Interface - input logic cio_scl_i, - output logic cio_scl_o, - output logic cio_scl_en_o, - input logic cio_sda_i, - output logic cio_sda_o, - output logic cio_sda_en_o, - - // SPI Host - output logic spi_sck_o, - output logic spi_sck_en_o, - output logic [spi_host_reg_pkg::NumCS-1:0] spi_csb_o, - output logic [spi_host_reg_pkg::NumCS-1:0] spi_csb_en_o, - output logic [ 3:0] spi_sd_o, - output logic [ 3:0] spi_sd_en_o, - input logic [ 3:0] spi_sd_i, - output logic spi_intr_event_o, - output logic spi_rx_valid_o, - output logic spi_tx_ready_o, - - // SPI 2 Host - output logic spi2_sck_o, - output logic spi2_sck_en_o, - output logic [spi_host_reg_pkg::NumCS-1:0] spi2_csb_o, - output logic [spi_host_reg_pkg::NumCS-1:0] spi2_csb_en_o, - output logic [ 3:0] spi2_sd_o, - output logic [ 3:0] spi2_sd_en_o, - input logic [ 3:0] spi2_sd_i, - - //RV TIMER - output logic rv_timer_2_intr_o, - output logic rv_timer_3_intr_o, - - //I2s - output logic i2s_sck_o, - output logic i2s_sck_oe_o, - input logic i2s_sck_i, - output logic i2s_ws_o, - output logic i2s_ws_oe_o, - input logic i2s_ws_i, - output logic i2s_sd_o, - output logic i2s_sd_oe_o, - input logic i2s_sd_i, - output logic i2s_rx_valid_o, - - // PDM2PCM Interface - output logic pdm2pcm_clk_o, - output logic pdm2pcm_clk_en_o, - input logic pdm2pcm_pdm_i + + ${xheep.get_rh().get_node_ports(domain.get_node()).strip(",")} ); import core_v_mini_mcu_pkg::*; @@ -99,88 +33,21 @@ module peripheral_subsystem reg_pkg::reg_req_t peripheral_req; reg_pkg::reg_rsp_t peripheral_rsp; - reg_pkg::reg_req_t [core_v_mini_mcu_pkg::PERIPHERALS-1:0] peripheral_slv_req; - reg_pkg::reg_rsp_t [core_v_mini_mcu_pkg::PERIPHERALS-1:0] peripheral_slv_rsp; - - tlul_pkg::tl_h2d_t plic_tl_h2d; - tlul_pkg::tl_d2h_t plic_tl_d2h; - - tlul_pkg::tl_h2d_t i2c_tl_h2d; - tlul_pkg::tl_d2h_t i2c_tl_d2h; - - tlul_pkg::tl_h2d_t rv_timer_tl_h2d; - tlul_pkg::tl_d2h_t rv_timer_tl_d2h; - - logic [rv_plic_reg_pkg::NumTarget-1:0] irq_plic; - logic [rv_plic_reg_pkg::NumSrc-1:0] intr_vector; - logic [$clog2(rv_plic_reg_pkg::NumSrc)-1:0] irq_id[rv_plic_reg_pkg::NumTarget]; - logic [$clog2(rv_plic_reg_pkg::NumSrc)-1:0] unused_irq_id[rv_plic_reg_pkg::NumTarget]; + reg_pkg::reg_req_t [core_v_mini_mcu_pkg::PERIPHERAL_COUNT-1:0] peripheral_slv_req; + reg_pkg::reg_rsp_t [core_v_mini_mcu_pkg::PERIPHERAL_COUNT-1:0] peripheral_slv_rsp; - logic [31:8] gpio_intr; - logic [7:0] cio_gpio_unused; - logic [7:0] cio_gpio_en_unused; - logic [7:0] gpio_int_unused; - logic i2c_intr_fmt_watermark; - logic i2c_intr_rx_watermark; - logic i2c_intr_fmt_overflow; - logic i2c_intr_rx_overflow; - logic i2c_intr_nak; - logic i2c_intr_scl_interference; - logic i2c_intr_sda_interference; - logic i2c_intr_stretch_timeout; - logic i2c_intr_sda_unstable; - logic i2c_intr_trans_complete; - logic i2c_intr_tx_empty; - logic i2c_intr_tx_nonempty; - logic i2c_intr_tx_overflow; - logic i2c_intr_acq_overflow; - logic i2c_intr_ack_stop; - logic i2c_intr_host_timeout; - logic spi2_intr_event; - logic i2s_intr_event; - - // this avoids lint errors - assign unused_irq_id = irq_id; +% for periph in domain.iter_peripherals(): +% for sig in periph.make_local_signals(): + ${sig.t} ${sig.name}; +% endfor +% endfor - // Assign internal interrupts - assign intr_vector[${interrupts["null_intr"]}] = 1'b0; // ID [0] is a special case and must be tied to zero. - assign intr_vector[${interrupts["uart_intr_tx_watermark"]}] = uart_intr_tx_watermark_i; - assign intr_vector[${interrupts["uart_intr_rx_watermark"]}] = uart_intr_rx_watermark_i; - assign intr_vector[${interrupts["uart_intr_tx_empty"]}] = uart_intr_tx_empty_i; - assign intr_vector[${interrupts["uart_intr_rx_overflow"]}] = uart_intr_rx_overflow_i; - assign intr_vector[${interrupts["uart_intr_rx_frame_err"]}] = uart_intr_rx_frame_err_i; - assign intr_vector[${interrupts["uart_intr_rx_break_err"]}] = uart_intr_rx_break_err_i; - assign intr_vector[${interrupts["uart_intr_rx_timeout"]}] = uart_intr_rx_timeout_i; - assign intr_vector[${interrupts["uart_intr_rx_parity_err"]}] = uart_intr_rx_parity_err_i; - assign intr_vector[${interrupts["gpio_intr_31"]}:${interrupts["gpio_intr_8"]}] = gpio_intr; - assign intr_vector[${interrupts["intr_fmt_watermark"]}] = i2c_intr_fmt_watermark; - assign intr_vector[${interrupts["intr_rx_watermark"]}] = i2c_intr_rx_watermark; - assign intr_vector[${interrupts["intr_fmt_overflow"]}] = i2c_intr_fmt_overflow; - assign intr_vector[${interrupts["intr_rx_overflow"]}] = i2c_intr_rx_overflow; - assign intr_vector[${interrupts["intr_nak"]}] = i2c_intr_nak; - assign intr_vector[${interrupts["intr_scl_interference"]}] = i2c_intr_scl_interference; - assign intr_vector[${interrupts["intr_sda_interference"]}] = i2c_intr_sda_interference; - assign intr_vector[${interrupts["intr_stretch_timeout"]}] = i2c_intr_stretch_timeout; - assign intr_vector[${interrupts["intr_sda_unstable"]}] = i2c_intr_sda_unstable; - assign intr_vector[${interrupts["intr_trans_complete"]}] = i2c_intr_trans_complete; - assign intr_vector[${interrupts["intr_tx_empty"]}] = i2c_intr_tx_empty; - assign intr_vector[${interrupts["intr_tx_nonempty"]}] = i2c_intr_tx_nonempty; - assign intr_vector[${interrupts["intr_tx_overflow"]}] = i2c_intr_tx_overflow; - assign intr_vector[${interrupts["intr_acq_overflow"]}] = i2c_intr_acq_overflow; - assign intr_vector[${interrupts["intr_ack_stop"]}] = i2c_intr_ack_stop; - assign intr_vector[${interrupts["intr_host_timeout"]}] = i2c_intr_host_timeout; - assign intr_vector[${interrupts["spi2_intr_event"]}] = spi2_intr_event; - assign intr_vector[${interrupts["i2s_intr_event"]}] = i2s_intr_event; - assign intr_vector[${interrupts["dma_window_intr"]}] = dma_window_intr_i; + ${xheep.get_rh().get_node_local_signals(domain.get_node())} - // External interrupts assignement - for (genvar i = 0; i < NEXT_INT; i++) begin - assign intr_vector[i+PLIC_USED_NINT] = intr_vector_ext_i[i]; - end //Address Decoder - logic [PERIPHERALS_PORT_SEL_WIDTH-1:0] peripheral_select; + logic [PERIPHERAL_PORT_SEL_WIDTH-1:0] peripheral_select; obi_pkg::obi_req_t slave_fifo_req_sel; obi_pkg::obi_resp_t slave_fifo_resp_sel; @@ -247,13 +114,13 @@ module peripheral_subsystem ); addr_decode #( - .NoIndices(core_v_mini_mcu_pkg::PERIPHERALS), - .NoRules(core_v_mini_mcu_pkg::PERIPHERALS), + .NoIndices(core_v_mini_mcu_pkg::PERIPHERAL_COUNT), + .NoRules(core_v_mini_mcu_pkg::PERIPHERAL_COUNT), .addr_t(logic [31:0]), .rule_t(addr_map_rule_pkg::addr_map_rule_t) ) i_addr_decode_soc_regbus_periph_xbar ( .addr_i(peripheral_req.addr), - .addr_map_i(core_v_mini_mcu_pkg::PERIPHERALS_ADDR_RULES), + .addr_map_i(core_v_mini_mcu_pkg::PERIPHERAL_ADDR_RULES), .idx_o(peripheral_select), .dec_valid_o(), .dec_error_o(), @@ -262,7 +129,7 @@ module peripheral_subsystem ); reg_demux #( - .NoPorts(core_v_mini_mcu_pkg::PERIPHERALS), + .NoPorts(core_v_mini_mcu_pkg::PERIPHERAL_COUNT), .req_t (reg_pkg::reg_req_t), .rsp_t (reg_pkg::reg_rsp_t) ) reg_demux_i ( @@ -275,330 +142,10 @@ module peripheral_subsystem .out_rsp_i(peripheral_slv_rsp) ); - reg_to_tlul #( - .req_t(reg_pkg::reg_req_t), - .rsp_t(reg_pkg::reg_rsp_t), - .tl_h2d_t(tlul_pkg::tl_h2d_t), - .tl_d2h_t(tlul_pkg::tl_d2h_t), - .tl_a_user_t(tlul_pkg::tl_a_user_t), - .tl_a_op_e(tlul_pkg::tl_a_op_e), - .TL_A_USER_DEFAULT(tlul_pkg::TL_A_USER_DEFAULT), - .PutFullData(tlul_pkg::PutFullData), - .Get(tlul_pkg::Get) - ) reg_to_tlul_plic_i ( - .tl_o(plic_tl_h2d), - .tl_i(plic_tl_d2h), - .reg_req_i(peripheral_slv_req[core_v_mini_mcu_pkg::RV_PLIC_IDX]), - .reg_rsp_o(peripheral_slv_rsp[core_v_mini_mcu_pkg::RV_PLIC_IDX]) - ); - -% for peripheral in peripherals.items(): -% if peripheral[0] in ("rv_plic"): -% if peripheral[1]['is_included'] in ("yes"): - rv_plic rv_plic_i ( - .clk_i(clk_cg), - .rst_ni, - .tl_i(plic_tl_h2d), - .tl_o(plic_tl_d2h), - .intr_src_i(intr_vector), - .irq_o(irq_plic_o), - .irq_id_o(irq_id), - .msip_o(msip_o) - ); -% else: - assign msip_o = '0; - - for(genvar i=0; i 16) begin - assign hw2reg.intr_state.d[31:16] = ext_irq_i[15:0]; + if (core_v_mini_mcu_pkg::NEXT_INT >= 15) begin + assign hw2reg.intr_state.d[31:17] = ext_irq_i[14:0]; end else begin - assign hw2reg.intr_state.d[31:16] = $unsigned(ext_irq_i); + assign hw2reg.intr_state.d[31:17+NEXT_INT_RND] = 'b0; + assign hw2reg.intr_state.d[17+NEXT_INT_RND-1:17] = ext_irq_i; end assign hw2reg.intr_state.de = 1'b1; diff --git a/hw/system/pad_control/data/pad_control.hjson.tpl b/hw/system/pad_control/data/pad_control.hjson.tpl index 605843dcd..28b56cb59 100644 --- a/hw/system/pad_control/data/pad_control.hjson.tpl +++ b/hw/system/pad_control/data/pad_control.hjson.tpl @@ -9,28 +9,28 @@ regwidth: "32", registers: [ -% for pad in pad_muxed_list: - { name: "PAD_MUX_${pad.name.upper()}", - desc: "Used to mux pad ${pad.name.upper()}", +% for pad, num in xheep.get_pad_manager().iterate_muxed_pad_index_with_num(): + { name: "PAD_MUX_${pad}", + desc: "Used to mux pad ${pad}", resval: "0x0" swaccess: "rw", hwaccess: "hro", fields: [ - { bits: "${(len(pad.pad_mux_list)-1).bit_length()-1}:0", name: "PAD_MUX_${pad.name.upper()}", desc: "Pad Mux ${pad.name.upper()} Reg" } + { bits: "${(num-1).bit_length()-1}:0", name: "PAD_MUX_${pad}", desc: "Pad Mux ${pad} Reg" } ] } % endfor -% if pads_attributes != None: -% for pad in total_pad_list: - { name: "PAD_ATTRIBUTE_${pad.name.upper()}", - desc: "${pad.name} Attributes (Pull Up En, Pull Down En, etc. It is technology specific.", +% if xheep.get_pad_manager().get_attr_bits() != 0: +% for pad in xheep.get_pad_manager().iterate_pad_index(): + { name: "PAD_ATTRIBUTE_${pad}", + desc: "${pad} Attributes (Pull Up En, Pull Down En, etc. It is technology specific.", resval: "0x00" swaccess: "rw", hwaccess: "hro", fields: [ - { bits: "${pads_attributes['bits']}", name: "PAD_ATTRIBUTE_${pad.name.upper()}", desc: "Pad Attribute ${pad.name.upper()} Reg" } + { bits: "${xheep.get_pad_manager().get_attr_bits()-1}:0", name: "PAD_ATTRIBUTE_${pad}", desc: "Pad Attribute ${pad} Reg" } ] } diff --git a/hw/system/pad_control/rtl/pad_control.sv.tpl b/hw/system/pad_control/rtl/pad_control.sv.tpl index e3be46c3d..a6dd7516c 100644 --- a/hw/system/pad_control/rtl/pad_control.sv.tpl +++ b/hw/system/pad_control/rtl/pad_control.sv.tpl @@ -5,45 +5,45 @@ module pad_control #( parameter type reg_req_t = logic, parameter type reg_rsp_t = logic, -% if not (total_pad_muxed > 0 or pads_attributes != None): +% if not xheep.get_pad_manager().get_mk_ctrl(): /* verilator lint_off UNUSED */ % endif parameter NUM_PAD = 1 ) ( -% if not (total_pad_muxed > 0 or pads_attributes != None): +% if not xheep.get_pad_manager().get_mk_ctrl(): /* verilator lint_off UNUSED */ % endif input logic clk_i, -% if not (total_pad_muxed > 0 or pads_attributes != None): +% if not xheep.get_pad_manager().get_mk_ctrl(): /* verilator lint_off UNUSED */ % endif input logic rst_ni, // Bus Interface -% if not (total_pad_muxed > 0 or pads_attributes != None): +% if not xheep.get_pad_manager().get_mk_ctrl(): /* verilator lint_off UNUSED */ % endif input reg_req_t reg_req_i, -% if not (total_pad_muxed > 0 or pads_attributes != None): +% if not xheep.get_pad_manager().get_mk_ctrl(): /* verilator lint_off UNDRIVEN */ % endif output reg_rsp_t reg_rsp_o -% if total_pad_muxed > 0 or pads_attributes != None: +% if xheep.get_pad_manager().get_mk_ctrl(): , % endif -% if pads_attributes != None: - output logic [NUM_PAD-1:0][${pads_attributes['bits']}] pad_attributes_o -% if total_pad_muxed > 0: +% if xheep.get_pad_manager().get_attr_bits() != 0: + output logic [NUM_PAD-1:0][${xheep.get_pad_manager().get_attr_bits()}-1:0] pad_attributes_o +% if xheep.get_pad_manager().get_muxed_pad_num() > 0: , % endif % endif -% if total_pad_muxed > 0: - output logic [NUM_PAD-1:0][${max_total_pad_mux_bitlengh-1}:0] pad_muxes_o +% if xheep.get_pad_manager().get_muxed_pad_num() > 0: + output logic [NUM_PAD-1:0][${xheep.get_pad_manager().get_max_mux_bitlengh()-1}:0] pad_muxes_o % endif ); -% if total_pad_muxed > 0 or pads_attributes != None: +% if xheep.get_pad_manager().get_mk_ctrl(): import core_v_mini_mcu_pkg::*; @@ -64,15 +64,15 @@ module pad_control #( ); % endif -% if pads_attributes != None: -% for pad in total_pad_list: - assign pad_attributes_o[${pad.localparam}] = reg2hw.pad_attribute_${pad.name.lower()}.q; +% if xheep.get_pad_manager().get_attr_bits != 0: +% for pad in xheep.get_pad_manager().iterate_pad_index(): + assign pad_attributes_o[${pad}] = reg2hw.pad_attribute_${pad.lower()}.q; % endfor % endif -% for pad in pad_muxed_list: - assign pad_muxes_o[${pad.localparam}] = $unsigned(reg2hw.pad_mux_${pad.name.lower()}.q); +% for pad in xheep.get_pad_manager().iterate_muxed_pad_index(): + assign pad_muxes_o[${pad}] = $unsigned(reg2hw.pad_mux_${pad.lower()}.q); % endfor endmodule : pad_control diff --git a/hw/system/pad_ring.sv.tpl b/hw/system/pad_ring.sv.tpl index a10c0bb98..d1c3a9778 100644 --- a/hw/system/pad_ring.sv.tpl +++ b/hw/system/pad_ring.sv.tpl @@ -3,32 +3,37 @@ // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 module pad_ring ( -% for pad in pad_list: -${pad.pad_ring_io_interface} -${pad.pad_ring_ctrl_interface} -% endfor - -% for external_pad in external_pad_list: -${external_pad.pad_ring_io_interface} -${external_pad.pad_ring_ctrl_interface} -% endfor - -% if pads_attributes != None: - input logic [core_v_mini_mcu_pkg::NUM_PAD-1:0][${pads_attributes['bits']}] pad_attributes_i +${xheep.get_pad_manager().make_root_io_ports(internal=True)} +##% for pad in pad_list: +##${pad.pad_ring_io_interface} +##${pad.pad_ring_ctrl_interface} +##% endfor + +##% for external_pad in external_pad_list: +##${external_pad.pad_ring_io_interface} +##${external_pad.pad_ring_ctrl_interface} +##% endfor + +${xheep.get_rh().get_node_ports(xheep.get_pad_manager().get_pad_ring_node())} +% if xheep.get_pad_manager().get_attr_bits() != 0: + input logic [core_v_mini_mcu_pkg::NUM_PAD-1:0][${xheep.get_pad_manager().get_attr_bits()}-1:0] pad_attributes_i % else: // here just for simplicity /* verilator lint_off UNUSED */ input logic [core_v_mini_mcu_pkg::NUM_PAD-1:0][0:0] pad_attributes_i % endif + ); -% for pad in pad_list: -${pad.pad_ring_instance} -% endfor +##% for pad in pad_list: +##${pad.pad_ring_instance} +##% endfor +## +##% for external_pad in external_pad_list: +##${external_pad.pad_ring_instance} +##% endfor -% for external_pad in external_pad_list: -${external_pad.pad_ring_instance} -% endfor +${xheep.get_pad_manager().make_pad_cells(xheep.get_rh())} endmodule // pad_ring diff --git a/hw/system/x_heep_system.sv.tpl b/hw/system/x_heep_system.sv.tpl index c88bdacad..536e72a0e 100644 --- a/hw/system/x_heep_system.sv.tpl +++ b/hw/system/x_heep_system.sv.tpl @@ -59,13 +59,13 @@ module x_heep_system if_xif.cpu_mem_result xif_mem_result_if, if_xif.cpu_result xif_result_if, -% for pad in total_pad_list: -${pad.x_heep_system_interface} -% endfor + ${xheep.get_pad_manager().make_root_io_ports(internal=True).strip(",")} ); import core_v_mini_mcu_pkg::*; + ${xheep.get_rh().get_node_local_signals(xheep.get_rh().get_root_node())} + // PM signals logic cpu_subsystem_powergate_switch_n; logic cpu_subsystem_powergate_switch_ack_n; @@ -77,19 +77,16 @@ ${pad.x_heep_system_interface} // PAD controller reg_req_t pad_req; reg_rsp_t pad_resp; -% if pads_attributes != None: - logic [core_v_mini_mcu_pkg::NUM_PAD-1:0][${pads_attributes['bits']}] pad_attributes; +% if xheep.get_pad_manager().get_attr_bits() != 0: + logic [core_v_mini_mcu_pkg::NUM_PAD-1:0][${xheep.get_pad_manager().get_attr_bits()}-1:0] pad_attributes; % endif - % if total_pad_muxed > 0: - logic [core_v_mini_mcu_pkg::NUM_PAD-1:0][${max_total_pad_mux_bitlengh-1}:0] pad_muxes; + % if xheep.get_pad_manager().get_muxed_pad_num() > 0: + logic [core_v_mini_mcu_pkg::NUM_PAD-1:0][${xheep.get_pad_manager().get_max_mux_bitlengh()-1}:0] pad_muxes; % endif logic rst_ngen; //input, output pins from core_v_mini_mcu -% for pad in total_pad_list: -${pad.internal_signals} -% endfor core_v_mini_mcu #( .COREV_PULP(COREV_PULP), @@ -98,11 +95,8 @@ ${pad.internal_signals} .EXT_XBAR_NMASTER(EXT_XBAR_NMASTER), .X_EXT(X_EXT) ) core_v_mini_mcu_i ( - + .clk_i(${xheep.get_rh().use_source_as_sv("clk", xheep.get_rh().get_root_node())}), .rst_ni(rst_ngen), -% for pad in pad_list: -${pad.core_v_mini_mcu_bonding} -% endfor .intr_vector_ext_i, .xif_compressed_if, .xif_issue_if, @@ -141,55 +135,57 @@ ${pad.core_v_mini_mcu_bonding} .external_ram_banks_set_retentive_no, .external_subsystem_clkgate_en_no, .exit_value_o, - .ext_dma_slot_tx_i, - .ext_dma_slot_rx_i + ${xheep.get_rh().get_instantiation_signals(xheep.get_mcu_node()).strip(",")} ); pad_ring pad_ring_i ( -% for pad in total_pad_list: -${pad.pad_ring_bonding_bonding} -% endfor -% if pads_attributes != None: + ${xheep.get_rh().get_instantiation_signals(xheep.get_pad_manager().get_pad_ring_node())} + ${xheep.get_pad_manager().make_root_io_ports_use()} +% if xheep.get_pad_manager().get_attr_bits() != 0: .pad_attributes_i(pad_attributes) % else: .pad_attributes_i('0) % endif ); -${pad_constant_driver_assign} - -${pad_mux_process} - pad_control #( .reg_req_t(reg_pkg::reg_req_t), .reg_rsp_t(reg_pkg::reg_rsp_t), .NUM_PAD (core_v_mini_mcu_pkg::NUM_PAD) ) pad_control_i ( - .clk_i(clk_in_x), + .clk_i(${xheep.get_rh().use_source_as_sv("clk", xheep.get_rh().get_root_node())}), .rst_ni(rst_ngen), .reg_req_i(pad_req), .reg_rsp_o(pad_resp) -% if total_pad_muxed > 0 or pads_attributes != None: +% if xheep.get_pad_manager().get_mk_ctrl(): , % endif -% if pads_attributes != None: +% if xheep.get_pad_manager().get_attr_bits() != 0: .pad_attributes_o(pad_attributes) -% if total_pad_muxed > 0: +% if xheep.get_pad_manager().get_muxed_pad_num() > 0: , % endif % endif -% if total_pad_muxed > 0: +% if xheep.get_pad_manager().get_muxed_pad_num() > 0: .pad_muxes_o(pad_muxes) % endif ); +${xheep.get_pad_manager().make_muxers(xheep.get_rh())} + rstgen rstgen_i ( - .clk_i(clk_in_x), - .rst_ni(rst_nin_x), + .clk_i(${xheep.get_rh().use_source_as_sv("clk", xheep.get_rh().get_root_node())}), + .rst_ni(${xheep.get_rh().use_source_as_sv("rst_n", xheep.get_rh().get_root_node())}), .test_mode_i(1'b0), .rst_no(rst_ngen), .init_no() ); +% for i in range(xheep.get_ext_intr() -1, -1, -1): +assign ${xheep.get_rh().use_source_as_sv(f"ext_intr_{i}", xheep.get_rh().get_root_node())} = intr_vector_ext_i[${i}]; +% endfor + +assign ${xheep.get_rh().use_source_as_sv("dma_ext_rx", xheep.get_rh().get_root_node())} = ext_dma_slot_rx_i; +assign ${xheep.get_rh().use_source_as_sv("dma_ext_tx", xheep.get_rh().get_root_node())} = ext_dma_slot_tx_i; endmodule // x_heep_system diff --git a/ides/ses/xheep.emProject b/ides/ses/xheep.emProject index 404008ba2..88bf07118 100644 --- a/ides/ses/xheep.emProject +++ b/ides/ses/xheep.emProject @@ -140,6 +140,7 @@ + diff --git a/mcu_cfg.hjson b/mcu_cfg.hjson index 2e6f33f19..0817d910d 100644 --- a/mcu_cfg.hjson +++ b/mcu_cfg.hjson @@ -17,117 +17,6 @@ length: 0x00100000, }, - ao_peripherals: { - address: 0x20000000, - length: 0x00100000, - soc_ctrl: { - offset: 0x00000000, - length: 0x00010000, - path: "./hw/ip/soc_ctrl/data/soc_ctrl.hjson" - }, - bootrom: { - offset: 0x00010000, - length: 0x00010000, - }, - spi_flash: { - offset: 0x00020000, - length: 0x00008000, - }, - spi_memio: { - offset: 0x00028000, - length: 0x00008000, - }, - dma: { - offset: 0x00030000, - length: 0x00010000, - path: "./hw/ip/dma/data/dma.hjson" - }, - power_manager: { - offset: 0x00040000, - length: 0x00010000, - path: "./hw/ip/power_manager/data/power_manager.hjson" - }, - rv_timer_ao: { - offset: 0x00050000, - length: 0x00010000, - }, - fast_intr_ctrl: { - offset: 0x00060000, - length: 0x00010000, - path: "./hw/ip/fast_intr_ctrl/data/fast_intr_ctrl.hjson" - }, - ext_peripheral: { - offset: 0x00070000, - length: 0x00010000, - }, - pad_control: { - offset: 0x00080000, - length: 0x00010000, - }, - gpio_ao: { - offset: 0x00090000, - length: 0x00010000, - }, - uart: { - offset: 0x000A0000, - length: 0x00010000, - path: "./hw/vendor/lowrisc_opentitan/hw/ip/uart/data/uart.hjson" - }, - }, - - peripherals: { - address: 0x30000000, - length: 0x00100000, - rv_plic: { - offset: 0x00000000, - length: 0x00010000, - is_included: "yes", - path: "./hw/vendor/lowrisc_opentitan/hw/ip/rv_plic/data/rv_plic.hjson" - }, - spi_host: { - offset: 0x00010000, - length: 0x00010000, - is_included: "yes", - path: "./hw/vendor/lowrisc_opentitan_spi_host/data/spi_host.hjson" - }, - gpio: { - offset: 0x00020000, - length: 0x00010000, - is_included: "yes", - path: "./hw/vendor/pulp_platform_gpio/gpio_regs.hjson" - }, - i2c: { - offset: 0x00030000, - length: 0x00010000, - is_included: "yes", - path: "./hw/vendor/lowrisc_opentitan/hw/ip/i2c/data/i2c.hjson" - }, - rv_timer: { - offset: 0x00040000, - length: 0x00010000, - is_included: "yes", - path: "./hw/vendor/lowrisc_opentitan/hw/ip/rv_timer/data/rv_timer.hjson" - }, - spi2: { - offset: 0x00050000, - length: 0x00010000, - is_included: "yes", - }, - pdm2pcm: { - offset: 0x00060000, - length: 0x00010000, - is_included: "no", - path: "./hw/ip/pdm2pcm/data/pdm2pcm.hjson" - }, - i2s: { - offset: 0x00070000, - length: 0x00010000, - is_included: "yes", - path: "./hw/ip/i2s/data/i2s.hjson" - }, - - }, - flash_mem: { address: 0x40000000, length: 0x01000000, @@ -138,62 +27,4 @@ length: 0x01000000, }, - interrupts: { - number: 64, // Do not change this number! - list: { - // First one is always zero - null_intr: 0, - uart_intr_tx_watermark: 1, - uart_intr_rx_watermark: 2, - uart_intr_tx_empty: 3, - uart_intr_rx_overflow: 4, - uart_intr_rx_frame_err: 5, - uart_intr_rx_break_err: 6, - uart_intr_rx_timeout: 7, - uart_intr_rx_parity_err: 8, - gpio_intr_8: 9, - gpio_intr_9: 10, - gpio_intr_10: 11, - gpio_intr_11: 12, - gpio_intr_12: 13, - gpio_intr_13: 14, - gpio_intr_14: 15, - gpio_intr_15: 16, - gpio_intr_16: 17, - gpio_intr_17: 18, - gpio_intr_18: 19, - gpio_intr_19: 20, - gpio_intr_20: 21, - gpio_intr_21: 22, - gpio_intr_22: 23, - gpio_intr_23: 24, - gpio_intr_24: 25, - gpio_intr_25: 26, - gpio_intr_26: 27, - gpio_intr_27: 28, - gpio_intr_28: 29, - gpio_intr_29: 30, - gpio_intr_30: 31, - gpio_intr_31: 32, - intr_fmt_watermark: 33, - intr_rx_watermark: 34, - intr_fmt_overflow: 35, - intr_rx_overflow: 36, - intr_nak: 37, - intr_scl_interference: 38, - intr_sda_interference: 39, - intr_stretch_timeout: 40, - intr_sda_unstable: 41, - intr_trans_complete: 42, - intr_tx_empty: 43, - intr_tx_nonempty: 44, - intr_tx_overflow: 45, - intr_acq_overflow: 46, - intr_ack_stop: 47, - intr_host_timeout: 48, - spi2_intr_event: 49, - i2s_intr_event: 50, - dma_window_intr: 51, - } - } } diff --git a/mcu_cfg_minimal.hjson b/mcu_cfg_minimal.hjson deleted file mode 100644 index 271bcf7ac..000000000 --- a/mcu_cfg_minimal.hjson +++ /dev/null @@ -1,198 +0,0 @@ -// Copyright 2020 ETH Zurich and University of Bologna. -// Solderpad Hardware License, Version 0.51, see LICENSE for details. -// SPDX-License-Identifier: SHL-0.51 -// Derived from Occamy: https://github.com/pulp-platform/snitch/blob/master/hw/system/occamy/src/occamy_cfg.hjson -// Peripherals configuration for core-v-mini-mcu. -{ - - cpu_type: cv32e20 - - linker_script: { - stack_size: 0x800, - heap_size: 0x800, - } - - debug: { - address: 0x10000000, - length: 0x00100000, - }, - - ao_peripherals: { - address: 0x20000000, - length: 0x00100000, - soc_ctrl: { - offset: 0x00000000, - length: 0x00010000, - path: "./hw/ip/soc_ctrl/data/soc_ctrl.hjson" - }, - bootrom: { - offset: 0x00010000, - length: 0x00010000, - }, - spi_flash: { - offset: 0x00020000, - length: 0x00008000, - }, - spi_memio: { - offset: 0x00028000, - length: 0x00008000, - }, - dma: { - offset: 0x00030000, - length: 0x00010000, - path: "./hw/ip/dma/data/dma.hjson" - }, - power_manager: { - offset: 0x00040000, - length: 0x00010000, - path: "./hw/ip/power_manager/data/power_manager.hjson" - }, - rv_timer_ao: { - offset: 0x00050000, - length: 0x00010000, - }, - fast_intr_ctrl: { - offset: 0x00060000, - length: 0x00010000, - path: "./hw/ip/fast_intr_ctrl/data/fast_intr_ctrl.hjson" - }, - ext_peripheral: { - offset: 0x00070000, - length: 0x00010000, - }, - pad_control: { - offset: 0x00080000, - length: 0x00010000, - }, - gpio_ao: { - offset: 0x00090000, - length: 0x00010000, - }, - uart: { - offset: 0x000A0000, - length: 0x00010000, - path: "./hw/vendor/lowrisc_opentitan/hw/ip/uart/data/uart.hjson" - }, - }, - - peripherals: { - address: 0x30000000, - length: 0x00100000, - rv_plic: { - offset: 0x00000000, - length: 0x00010000, - is_included: "no", - path: "./hw/vendor/lowrisc_opentitan/hw/ip/rv_plic/data/rv_plic.hjson" - }, - spi_host: { - offset: 0x00010000, - length: 0x00010000, - is_included: "no", - path: "./hw/vendor/lowrisc_opentitan_spi_host/data/spi_host.hjson" - }, - gpio: { - offset: 0x00020000, - length: 0x00010000, - is_included: "no", - path: "./hw/vendor/pulp_platform_gpio/gpio_regs.hjson" - }, - i2c: { - offset: 0x00030000, - length: 0x00010000, - is_included: "no", - path: "./hw/vendor/lowrisc_opentitan/hw/ip/i2c/data/i2c.hjson" - }, - rv_timer: { - offset: 0x00040000, - length: 0x00010000, - is_included: "no", - path: "./hw/vendor/lowrisc_opentitan/hw/ip/rv_timer/data/rv_timer.hjson" - }, - spi2: { - offset: 0x00050000, - length: 0x00010000, - is_included: "no", - }, - pdm2pcm: { - offset: 0x00060000, - length: 0x00010000, - is_included: "no", - path: "./hw/ip/pdm2pcm/data/pdm2pcm.hjson" - }, - i2s: { - offset: 0x00070000, - length: 0x00010000, - is_included: "no", - path: "./hw/ip/i2s/data/i2s.hjson" - }, - }, - - flash_mem: { - address: 0x40000000, - length: 0x01000000, - }, - - ext_slaves: { - address: 0xF0000000, - length: 0x01000000, - }, - - interrupts: { - number: 64, // Do not change this number! - list: { - // First one is always zero - null_intr: 0, - uart_intr_tx_watermark: 1, - uart_intr_rx_watermark: 2, - uart_intr_tx_empty: 3, - uart_intr_rx_overflow: 4, - uart_intr_rx_frame_err: 5, - uart_intr_rx_break_err: 6, - uart_intr_rx_timeout: 7, - uart_intr_rx_parity_err: 8, - gpio_intr_8: 9, - gpio_intr_9: 10, - gpio_intr_10: 11, - gpio_intr_11: 12, - gpio_intr_12: 13, - gpio_intr_13: 14, - gpio_intr_14: 15, - gpio_intr_15: 16, - gpio_intr_16: 17, - gpio_intr_17: 18, - gpio_intr_18: 19, - gpio_intr_19: 20, - gpio_intr_20: 21, - gpio_intr_21: 22, - gpio_intr_22: 23, - gpio_intr_23: 24, - gpio_intr_24: 25, - gpio_intr_25: 26, - gpio_intr_26: 27, - gpio_intr_27: 28, - gpio_intr_28: 29, - gpio_intr_29: 30, - gpio_intr_30: 31, - gpio_intr_31: 32, - intr_fmt_watermark: 33, - intr_rx_watermark: 34, - intr_fmt_overflow: 35, - intr_rx_overflow: 36, - intr_nak: 37, - intr_scl_interference: 38, - intr_sda_interference: 39, - intr_stretch_timeout: 40, - intr_sda_unstable: 41, - intr_trans_complete: 42, - intr_tx_empty: 43, - intr_tx_nonempty: 44, - intr_tx_overflow: 45, - intr_acq_overflow: 46, - intr_ack_stop: 47, - intr_host_timeout: 48, - spi2_intr_event: 49, - i2s_intr_event: 50, - dma_window_intr: 51, - } - } -} diff --git a/pad_cfg.hjson b/pad_cfg.hjson index a469f1c81..14de4133c 100644 --- a/pad_cfg.hjson +++ b/pad_cfg.hjson @@ -12,69 +12,80 @@ // num_offset: (optional) - the offset to the first pad of this type (default 0) // mapping: (optional) - the mapping of the pad in the design. Useful for ASICs (default top) // active: (optional) - the active level of the pad (default high) -// driven_manually: (optional) - the pad is driven manually (default False) // mux: (optional) - the muxing options for the pad // skip_declaration: (optional) - skip the declaration of the pad in the top level (default False) // keep_internal: (optional) - keep the pad internal to the design (default False) // -// Add this field at the same level of pads (not inside) if you want to define PADs attributes +// Add this field at the same level of pads (not inside) if you want to define PADs attributes (n bits) // attributes: { -// bits: 7:0 +// bits: n // }, { - + attributes: { + bits: 4 + } pads: { clk: { num: 1, + no_num: True type: input }, rst: { num: 1, - active: low, + no_num: True + active: low driven_manually: True type: input }, boot_select: { num: 1, + no_num: True type: input }, execute_from_flash: { num: 1, + no_num: True type: input }, jtag_tck: { num: 1, + no_num: True type: input }, jtag_tms: { num: 1, + no_num: True type: input }, jtag_trst: { num: 1, - active: low, + no_num: True + active: low type: input }, jtag_tdi: { num: 1, + no_num: True type: input }, jtag_tdo: { num: 1, + no_num: True type: output }, - uart_rx: { + uart0_rx: { num: 1, type: input }, - uart_tx: { + uart0_tx: { num: 1, type: output }, exit_valid: { num: 1, + no_num: True type: output }, gpio: { @@ -86,7 +97,7 @@ num: 1, type: inout }, - spi_flash_cs: { + spi_flash_csb: { num: 2, #carefull, the x-heep uses the CS from the spi pkg, change it type: inout }, @@ -94,183 +105,154 @@ num: 4, type: inout }, - spi_sck: { + spi_host0_sck: { num: 1, type: inout }, - spi_cs: { + spi_host0_csb: { num: 2, type: inout }, - spi_sd: { + spi_host0_sd: { num: 4, type: inout }, - pdm2pcm_pdm: { + pdm2pcm0_pdm: { num: 1, type: inout mux: { - pdm2pcm_pdm: { - type: inout + pdm2pcm0_pdm: { + type: input }, - gpio_18: { + gpio: { + num_offset: 18 type: inout } } }, - pdm2pcm_clk: { + pdm2pcm0_pdm_clk: { num: 1, type: inout mux: { - pdm2pcm_clk: { - type: inout + pdm2pcm0_pdm_clk: { + type: output }, - gpio_19: { + gpio: { + num_offset: 19 type: inout } } }, - i2s_sck: { + i2s0_sck: { num: 1, type: inout mux: { - i2s_sck: { + i2s0_sck: { type: inout }, - gpio_20: { + gpio: { + num_offset:20 type: inout } } }, - i2s_ws: { + i2s0_ws: { num: 1, type: inout mux: { - i2s_ws: { + i2s0_ws: { type: inout }, - gpio_21: { + gpio: { + num_offset: 21 type: inout } } }, - i2s_sd: { + i2s0_sd: { num: 1, type: inout mux: { - i2s_sd: { + i2s0_sd: { type: inout }, - gpio_22: { + gpio: { + num_offset: 22 type: inout } } }, - spi2_cs_0: { - num: 1, - type: inout - mux: { - spi2_cs_0: { - type: inout - }, - gpio_23: { - type: inout - }, - } - }, - spi2_cs_1: { - num: 1, - type: inout - mux: { - spi2_cs_1: { - type: inout - }, - gpio_24: { - type: inout - }, - }, - }, - spi2_sck: { - num: 1, - type: inout - mux: { - spi2_sck: { - type: inout - }, - gpio_25: { - type: inout - }, - } - }, - spi2_sd_0: { - num: 1, - type: inout - mux: { - spi2_sd_0: { - type: inout - }, - gpio_26: { - type: inout - }, - } - }, - spi2_sd_1: { - num: 1, + spi_host1_csb: { + num: 2, + num_offset: 0, type: inout mux: { - spi2_sd_1: { - type: inout + spi_host1_csb: { + num: 2, + num_offset: 0, + type: output }, - gpio_27: { + gpio: { + num: 2, + num_offset: 23, type: inout }, } }, - spi2_sd_2: { + spi_host1_sck: { num: 1, type: inout mux: { - spi2_sd_2: { - type: inout + spi_host1_sck: { + type: output }, - gpio_28: { + gpio: { + num_offset: 25, type: inout }, } }, - spi2_sd_3: { - num: 1, + spi_host1_sd: { + num: 4, + num_offset: 0, type: inout mux: { - spi2_sd_3: { + spi_host1_sd: { + num: 4, + num_offset: 0, type: inout }, - gpio_29: { + gpio: { + num: 4, + num_offset: 26, type: inout }, } }, - i2c_scl: { + + i2c0_scl: { num: 1, type: inout mux: { - i2c_scl: { + i2c0_scl: { type: inout }, - gpio_31: { + gpio: { + num_offset: 31 type: inout }, } }, - i2c_sda: { + i2c0_sda: { num: 1, type: inout mux: { - i2c_sda: { + i2c0_sda: { type: inout }, - gpio_30: { + gpio: { + num_offset: 30 type: inout }, } diff --git a/sw/applications/example_dma/main.c b/sw/applications/example_dma/main.c index ea842d8a4..bc0e1cbff 100644 --- a/sw/applications/example_dma/main.c +++ b/sw/applications/example_dma/main.c @@ -344,9 +344,9 @@ int main(int argc, char *argv[]) PRINTF(" TESTING WINDOW INTERRUPT "); PRINTF("\n\n\r===================================\n\n\r"); - plic_Init(); - plic_irq_set_priority( DMA_WINDOW_INTR, 1); - plic_irq_set_enabled( DMA_WINDOW_INTR, kPlicToggleEnabled); + plic_Init(&rv_plic_0_inf); + plic_irq_set_priority(&rv_plic_0_inf, DMA_WINDOW_INTR, 1); + plic_irq_set_enabled(&rv_plic_0_inf, DMA_WINDOW_INTR, kPlicToggleEnabled); window_intr_flag = 0; diff --git a/sw/applications/example_freertos_blinky/main.c b/sw/applications/example_freertos_blinky/main.c index fbb9941f4..3801ca66e 100644 --- a/sw/applications/example_freertos_blinky/main.c +++ b/sw/applications/example_freertos_blinky/main.c @@ -254,16 +254,16 @@ void system_init(void) .pin= GPIO_LD5_R, .mode= GpioModeOutPushPull }; - gpio_res = gpio_config(pin_cfg); + gpio_res = gpio_config(gpio_1_peri, pin_cfg); pin_cfg.pin = GPIO_LD5_B; - gpio_res |= gpio_config(pin_cfg); + gpio_res |= gpio_config(gpio_1_peri, pin_cfg); pin_cfg.pin = GPIO_LD5_G; - gpio_res |= gpio_config(pin_cfg); + gpio_res |= gpio_config(gpio_1_peri, pin_cfg); if (gpio_res != GpioOk) printf("Failed\n;"); - gpio_write(GPIO_LD5_R, false); - gpio_write(GPIO_LD5_B, false); - gpio_write(GPIO_LD5_G, false); + gpio_write(gpio_1_peri, GPIO_LD5_R, false); + gpio_write(gpio_1_peri, GPIO_LD5_B, false); + gpio_write(gpio_1_peri, GPIO_LD5_G, false); // Setup rv_timer_0_1 mmio_region_t timer_0_1_reg = mmio_region_from_addr(RV_TIMER_AO_START_ADDRESS); @@ -438,30 +438,30 @@ void vToggleLED( void ) { if (intr_blink == 0) { - gpio_write(GPIO_LD5_R, true); - gpio_write(GPIO_LD5_B, false); - gpio_write(GPIO_LD5_G, false); + gpio_write(gpio_1_peri, GPIO_LD5_R, true); + gpio_write(gpio_1_peri, GPIO_LD5_B, false); + gpio_write(gpio_1_peri, GPIO_LD5_G, false); intr_blink++; } else if (intr_blink == 1) { - gpio_write(GPIO_LD5_R, false); - gpio_write(GPIO_LD5_B, true); - gpio_write(GPIO_LD5_G, false); + gpio_write(gpio_1_peri, GPIO_LD5_R, false); + gpio_write(gpio_1_peri, GPIO_LD5_B, true); + gpio_write(gpio_1_peri, GPIO_LD5_G, false); intr_blink++; } else if (intr_blink == 2) { - gpio_write(GPIO_LD5_R, false); - gpio_write(GPIO_LD5_B, false); - gpio_write(GPIO_LD5_G, true); + gpio_write(gpio_1_peri, GPIO_LD5_R, false); + gpio_write(gpio_1_peri, GPIO_LD5_B, false); + gpio_write(gpio_1_peri, GPIO_LD5_G, true); intr_blink++; } else { - gpio_write(GPIO_LD5_R, false); - gpio_write(GPIO_LD5_B, false); - gpio_write(GPIO_LD5_G, false); + gpio_write(gpio_1_peri, GPIO_LD5_R, false); + gpio_write(gpio_1_peri, GPIO_LD5_B, false); + gpio_write(gpio_1_peri, GPIO_LD5_G, false); intr_blink = 0; } diff --git a/sw/applications/example_gpio_intr/main.c b/sw/applications/example_gpio_intr/main.c index acad473a9..6c7d240d8 100644 --- a/sw/applications/example_gpio_intr/main.c +++ b/sw/applications/example_gpio_intr/main.c @@ -36,7 +36,7 @@ #endif -#ifndef RV_PLIC_IS_INCLUDED +#ifndef RV_PLIC_0_IS_INCLUDED #error ( "This app does NOT work as the RV_PLIC peripheral is not included" ) #endif @@ -44,14 +44,14 @@ #ifdef TARGET_PYNQ_Z2 #define GPIO_TB_OUT 8 #define GPIO_TB_IN 9 - #define GPIO_INTR GPIO_INTR_9 + #define GPIO_INTR GPIO_9_INTR #pragma message ( "Connect a cable between GPIOs IN and OUT" ) #else #define GPIO_TB_OUT 30 #define GPIO_TB_IN 31 - #define GPIO_INTR GPIO_INTR_31 + #define GPIO_INTR GPIO_31_INTR #endif @@ -59,13 +59,13 @@ plic_result_t plic_res; uint8_t gpio_intr_flag = 0; -void handler_1() +void handler_1(uint32_t id) { PRINTF("handler 1\n"); gpio_intr_flag = 1; } -void handler_2() +void handler_2(uint32_t id) { PRINTF("handler 2\n"); gpio_intr_flag = 1; @@ -77,7 +77,7 @@ int main(int argc, char *argv[]) pad_control_t pad_control; pad_control.base_addr = mmio_region_from_addr((uintptr_t)PAD_CONTROL_START_ADDRESS); // rv_plic_params.base_addr = mmio_region_from_addr((uintptr_t)RV_PLIC_START_ADDRESS); - plic_res = plic_Init(); + plic_res = plic_Init(&rv_plic_0_inf); if (plic_res != kPlicOk) { PRINTF("Init PLIC failed\n\r;"); return -1; @@ -85,20 +85,20 @@ int main(int argc, char *argv[]) // In case GPIOs 30 and 31 are used: #if GPIO_TB_OUT == 31 || GPIO_TB_IN == 31 - pad_control_set_mux(&pad_control, (ptrdiff_t)(PAD_CONTROL_PAD_MUX_I2C_SCL_REG_OFFSET), 1); + pad_control_set_mux(&pad_control, (ptrdiff_t)(PAD_CONTROL_PAD_MUX_PAD_I2C0_SCL_0_REG_OFFSET), 1); #endif #if GPIO_TB_OUT == 30|| GPIO_TB_IN == 30 - pad_control_set_mux(&pad_control, (ptrdiff_t)(PAD_CONTROL_PAD_MUX_I2C_SDA_REG_OFFSET), 1); + pad_control_set_mux(&pad_control, (ptrdiff_t)(PAD_CONTROL_PAD_MUX_PAD_I2C0_SDA_0_REG_OFFSET), 1); #endif - plic_res = plic_irq_set_priority(GPIO_INTR, 1); + plic_res = plic_irq_set_priority(&rv_plic_0_inf, GPIO_INTR, 1); if (plic_res != kPlicOk) { PRINTF("Failed\n\r;"); return -1; } - plic_res = plic_irq_set_enabled(GPIO_INTR, kPlicToggleEnabled); + plic_res = plic_irq_set_enabled(&rv_plic_0_inf, GPIO_INTR, kPlicToggleEnabled); if (plic_res != kPlicOk) { PRINTF("Failed\n\r;"); return -1; @@ -118,12 +118,12 @@ int main(int argc, char *argv[]) .pin = GPIO_TB_OUT, .mode = GpioModeOutPushPull }; - gpio_res = gpio_config(cfg_out); + gpio_res = gpio_config(gpio_1_peri, cfg_out); if (gpio_res != GpioOk) { PRINTF("Failed\n;"); return -1; } - gpio_res = gpio_write(GPIO_TB_OUT, false); + gpio_res = gpio_write(gpio_1_peri, GPIO_TB_OUT, false); gpio_cfg_t cfg_in = { .pin = GPIO_TB_IN, @@ -132,13 +132,13 @@ int main(int argc, char *argv[]) .en_intr = true, .intr_type = GpioIntrEdgeRising }; - gpio_res = gpio_config(cfg_in); + gpio_res = gpio_config(gpio_1_peri, cfg_in); if (gpio_res != GpioOk) { PRINTF("Failed\n;"); return -1; } - gpio_assign_irq_handler( GPIO_INTR, &handler_1 ); + plic_assign_irq_handler(&rv_plic_0_inf, GPIO_INTR, &handler_1); gpio_intr_flag = 0; PRINTF("Write 1 to GPIO 30 and wait for interrupt...\n\r"); @@ -146,12 +146,13 @@ int main(int argc, char *argv[]) // disable_interrupts // this does not prevent waking up the core as this is controlled by the MIP register CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); - gpio_write(GPIO_TB_OUT, true); + gpio_write(gpio_1_peri, GPIO_TB_OUT, true); // wait_for_interrupt(); CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); } + gpio_res = gpio_write(gpio_1_peri, GPIO_TB_OUT, false); - gpio_assign_irq_handler( GPIO_INTR, &handler_2 ); + plic_assign_irq_handler(&rv_plic_0_inf, GPIO_INTR, &handler_2); gpio_intr_flag = 0; PRINTF("Write 1 to GPIO 30 and wait for interrupt...\n\r"); @@ -159,7 +160,7 @@ int main(int argc, char *argv[]) // disable_interrupts // this does not prevent waking up the core as this is controlled by the MIP register CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); - gpio_write(GPIO_TB_OUT, true); + gpio_write(gpio_1_peri, GPIO_TB_OUT, true); //wait_for_interrupt(); CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); } diff --git a/sw/applications/example_gpio_toggle/main.c b/sw/applications/example_gpio_toggle/main.c index 9f920281c..67e334572 100644 --- a/sw/applications/example_gpio_toggle/main.c +++ b/sw/applications/example_gpio_toggle/main.c @@ -30,15 +30,15 @@ int main(int argc, char *argv[]) .pin = GPIO_TOGGLE, .mode = GpioModeOutPushPull }; - gpio_res = gpio_config (pin_cfg); + gpio_res = gpio_config(gpio_0_peri, pin_cfg); if (gpio_res != GpioOk) PRINTF("Gpio initialization failed!\n"); for(int i=0;i<100;i++) { - gpio_write(GPIO_TOGGLE, true); + gpio_write(gpio_0_peri, GPIO_TOGGLE, true); for(int i=0;i<10;i++) asm volatile("nop"); - gpio_write(GPIO_TOGGLE, false); + gpio_write(gpio_0_peri, GPIO_TOGGLE, false); for(int i=0;i<10;i++) asm volatile("nop"); } diff --git a/sw/applications/example_i2s/main.c b/sw/applications/example_i2s/main.c index d56b2f33b..88fc1c80f 100644 --- a/sw/applications/example_i2s/main.c +++ b/sw/applications/example_i2s/main.c @@ -127,9 +127,9 @@ void setup() // -- DMA CONFIGURATION -- - tgt_src.ptr = I2S_RX_DATA_ADDRESS; + tgt_src.ptr = I2S_RX_DATA_ADDRESS(I2S_0_START_ADDRESS); tgt_src.inc_du = 0; - tgt_src.trig = DMA_TRIG_SLOT_I2S; + tgt_src.trig = DMA_TRIG_SLOT_I2S_0_RX; tgt_src.type = DMA_DATA_TYPE_WORD; tgt_src.size_du = AUDIO_DATA_NUM; @@ -151,18 +151,18 @@ void setup() // PLIC - plic_Init(); - plic_res = plic_irq_set_priority(I2S_INTR_EVENT, 1); - plic_res = plic_irq_set_enabled(I2S_INTR_EVENT, kPlicToggleEnabled); + plic_Init(&rv_plic_0_inf); + plic_res = plic_irq_set_priority(&rv_plic_0_inf, I2S_0_I2S_EVENT_INTR, 1); + plic_res = plic_irq_set_enabled(&rv_plic_0_inf, I2S_0_I2S_EVENT_INTR, kPlicToggleEnabled); // enable I2s interrupt i2s_interrupt_flag = 0; - i2s_res = i2s_init(I2S_CLK_DIV, I2S_32_BITS); + i2s_res = i2s_init(i2s_0_peri, I2S_CLK_DIV, I2S_32_BITS); if (i2s_res != kI2sOk) { PRINTF("I2S init failed with %d\n\r", i2s_res); } - i2s_rx_enable_watermark(AUDIO_DATA_NUM, I2S_USE_INTERRUPT); + i2s_rx_enable_watermark(i2s_0_peri, AUDIO_DATA_NUM, I2S_USE_INTERRUPT); } @@ -199,7 +199,7 @@ int main(int argc, char *argv[]) { dma_launch( &trans ); #endif // USE_DMA - i2s_res = i2s_rx_start(I2S_LEFT_CH); + i2s_res = i2s_rx_start(i2s_0_peri, I2S_LEFT_CH); if (i2s_res != kI2sOk) { PRINTF("I2S rx start failed with %d\n\r", i2s_res); } @@ -213,17 +213,17 @@ int main(int argc, char *argv[]) { #else // READING DATA MANUALLY OVER BUS for (int i = 0; i < AUDIO_DATA_NUM; i+=1) { - if (i != i2s_rx_read_waterlevel()) PRINTF("Waterlevel wrong\r\n\r"); - while (! i2s_rx_data_available()) { } + if (i != i2s_rx_read_waterlevel(i2s_0_peri)) PRINTF("Waterlevel wrong\r\n\r"); + while (! i2s_rx_data_available(i2s_0_peri)) { } audio_data_0[i] = i2s_rx_read_data(); } #endif - if (i2s_rx_overflow()) { + if (i2s_rx_overflow(i2s_0_peri)) { PRINTF("I2S rx FIFO overflowed\n\r"); } - i2s_res = i2s_rx_stop(); + i2s_res = i2s_rx_stop(i2s_0_peri); if (i2s_res != kI2sOk) { if (i2s_res == kI2sOverflow) { PRINTF("I2S rx overflow occured and cleared\n\r"); @@ -259,7 +259,7 @@ int main(int argc, char *argv[]) { #ifdef USE_DMA dma_launch( &trans ); #endif // USE_DMA - i2s_res = i2s_rx_start(I2S_BOTH_CH); + i2s_res = i2s_rx_start(i2s_0_peri, I2S_BOTH_CH); if (i2s_res != kI2sOk) { PRINTF("I2S rx start failed with %d\n\r", i2s_res); } @@ -273,16 +273,16 @@ int main(int argc, char *argv[]) { #else // READING DATA MANUALLY OVER BUS for (int i = 0; i < AUDIO_DATA_NUM; i+=1) { - if (i != i2s_rx_read_waterlevel()) PRINTF("Waterlevel wrong\r\n\r"); - while (!i2s_rx_data_available()) { } + if (i != i2s_rx_read_waterlevel(i2s_0_peri)) PRINTF("Waterlevel wrong\r\n\r"); + while (!i2s_rx_data_available(i2s_0_peri)) { } audio_data_0[i] = i2s_rx_read_data(); } #endif - if (i2s_rx_overflow()) { + if (i2s_rx_overflow(i2s_0_peri)) { PRINTF("I2S rx FIFO overflowed\n\r"); } - i2s_res = i2s_rx_stop(); + i2s_res = i2s_rx_stop(i2s_0_peri); if (i2s_res != kI2sOk) { if (i2s_res == kI2sOverflow) { PRINTF("I2S rx overflow occured and cleared\n\r"); @@ -350,7 +350,7 @@ int main(int argc, char *argv[]) { } #endif - i2s_terminate(); + i2s_terminate(i2s_0_peri); if( success ){ PRINTF("Success. \n\r"); diff --git a/sw/applications/example_iffifo/main.c b/sw/applications/example_iffifo/main.c index b62fab6aa..b3ad9e3bc 100644 --- a/sw/applications/example_iffifo/main.c +++ b/sw/applications/example_iffifo/main.c @@ -115,11 +115,11 @@ int main(int argc, char *argv[]) { const uint32_t mask = 1 << 11; CSR_SET_BITS(CSR_REG_MIE, mask); - if(plic_Init()) {return EXIT_FAILURE;}; - if(plic_irq_set_priority(EXT_INTR_1, 1)) {return EXIT_FAILURE;}; - if(plic_irq_set_enabled(EXT_INTR_1, kPlicToggleEnabled)) {return EXIT_FAILURE;}; + if(plic_Init(&rv_plic_0_inf)) {return EXIT_FAILURE;}; + if(plic_irq_set_priority(&rv_plic_0_inf, EXT_INTR_1, 1)) {return EXIT_FAILURE;}; + if(plic_irq_set_enabled(&rv_plic_0_inf, EXT_INTR_1, kPlicToggleEnabled)) {return EXIT_FAILURE;}; - plic_assign_external_irq_handler(EXT_INTR_1, &handler_irq_iffifo); + plic_assign_irq_handler(&rv_plic_0_inf, EXT_INTR_1, &handler_irq_iffifo); mmio_region_write32(iffifo_base_addr, IFFIFO_WATERMARK_REG_OFFSET, 2); mmio_region_write32(iffifo_base_addr, IFFIFO_INTERRUPTS_REG_OFFSET, 0b1); @@ -137,7 +137,7 @@ int main(int argc, char *argv[]) { tgt_dst.ptr = IFFIFO_START_ADDRESS + IFFIFO_FIFO_IN_REG_OFFSET; tgt_dst.inc_du = 0; - tgt_dst.trig = DMA_TRIG_SLOT_EXT_TX; + tgt_dst.trig = DMA_TRIG_SLOT_DMA_EXT_TX; tgt_dst.type = DMA_DATA_TYPE_WORD; trans.src = &tgt_src; @@ -172,7 +172,7 @@ int main(int argc, char *argv[]) { dma_init(NULL); tgt_src.ptr = IFFIFO_START_ADDRESS + IFFIFO_FIFO_OUT_REG_OFFSET; tgt_src.inc_du = 0; - tgt_src.trig = DMA_TRIG_SLOT_EXT_RX; + tgt_src.trig = DMA_TRIG_SLOT_DMA_EXT_RX; tgt_src.type = DMA_DATA_TYPE_WORD; tgt_src.size_du = 4; diff --git a/sw/applications/example_pdm2pcm/main.c b/sw/applications/example_pdm2pcm/main.c index b4f9c3b37..0a1c5d584 100644 --- a/sw/applications/example_pdm2pcm/main.c +++ b/sw/applications/example_pdm2pcm/main.c @@ -25,7 +25,7 @@ #include "mmio.h" #include "groundtruth.h" -#ifndef PDM2PCM_IS_INCLUDED +#ifndef PDM2PCM_0_IS_INCLUDED #error ( "This app does NOT work as the PDM2PCM peripheral is not included" ) #endif @@ -48,7 +48,7 @@ int main(int argc, char *argv[]) PRINTF("PDM2PCM DEMO\n\r"); PRINTF(" > Start\n\r"); - mmio_region_t pdm2pcm_base_addr = mmio_region_from_addr((uintptr_t)PDM2PCM_START_ADDRESS); + mmio_region_t pdm2pcm_base_addr = mmio_region_from_addr((uintptr_t)PDM2PCM_0_START_ADDRESS); mmio_region_write32(pdm2pcm_base_addr, PDM2PCM_CLKDIVIDX_REG_OFFSET ,15); mmio_region_write32(pdm2pcm_base_addr, PDM2PCM_REACHCOUNT_REG_OFFSET, 1); diff --git a/sw/applications/example_power_gating_core/main.c b/sw/applications/example_power_gating_core/main.c index da7d84486..3ae7b5c13 100644 --- a/sw/applications/example_power_gating_core/main.c +++ b/sw/applications/example_power_gating_core/main.c @@ -19,7 +19,7 @@ #include "x-heep.h" -#ifndef RV_PLIC_IS_INCLUDED +#ifndef RV_PLIC_0_IS_INCLUDED #error ( "This app does NOT work as the RV_PLIC peripheral is not included" ) #endif @@ -61,12 +61,12 @@ int main(int argc, char *argv[]) #ifndef TARGET_PYNQ_Z2 pad_control_t pad_control; pad_control.base_addr = mmio_region_from_addr((uintptr_t)PAD_CONTROL_START_ADDRESS); - pad_control_set_mux(&pad_control, (ptrdiff_t)(PAD_CONTROL_PAD_MUX_I2C_SCL_REG_OFFSET), 1); - pad_control_set_mux(&pad_control, (ptrdiff_t)(PAD_CONTROL_PAD_MUX_I2C_SDA_REG_OFFSET), 1); + pad_control_set_mux(&pad_control, (ptrdiff_t)(PAD_CONTROL_PAD_MUX_PAD_I2C0_SCL_0_REG_OFFSET), 1); + pad_control_set_mux(&pad_control, (ptrdiff_t)(PAD_CONTROL_PAD_MUX_PAD_I2C0_SDA_0_REG_OFFSET), 1); #endif // Setup plic - plic_Init(); + plic_Init(&rv_plic_0_inf); // Get current Frequency soc_ctrl_t soc_ctrl; @@ -80,7 +80,7 @@ int main(int argc, char *argv[]) rv_timer_approximate_tick_params(freq_hz, kTickFreqHz, &tick_params); // Setup rv_timer_2_3 - mmio_region_t timer_2_3_reg = mmio_region_from_addr(RV_TIMER_START_ADDRESS); + mmio_region_t timer_2_3_reg = mmio_region_from_addr(RV_TIMER_2_3_START_ADDRESS); rv_timer_init(timer_2_3_reg, (rv_timer_config_t){.hart_count = 2, .comparator_count = 1}, &timer_2_3); // Init cpu_subsystem's counters @@ -107,7 +107,7 @@ int main(int argc, char *argv[]) rv_timer_counter_set_enabled(&timer_0_1, 0, kRvTimerEnabled); CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); - if (power_gate_core(&power_manager, kTimer_0_pm_e, &power_manager_cpu_counters) != kPowerManagerOk_e) + if (power_gate_core(&power_manager, kRv_Timer_0_pm_e, &power_manager_cpu_counters) != kPowerManagerOk_e) { PRINTF("Error: power manager fail.\n\r"); return EXIT_FAILURE; @@ -121,7 +121,7 @@ int main(int argc, char *argv[]) rv_timer_counter_set_enabled(&timer_0_1, 1, kRvTimerEnabled); CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); - if (power_gate_core(&power_manager, kTimer_1_pm_e, &power_manager_cpu_counters) != kPowerManagerOk_e) + if (power_gate_core(&power_manager, kRv_Timer_1_pm_e, &power_manager_cpu_counters) != kPowerManagerOk_e) { PRINTF("Error: power manager fail.\n\r"); return EXIT_FAILURE; @@ -135,7 +135,7 @@ int main(int argc, char *argv[]) rv_timer_counter_set_enabled(&timer_2_3, 0, kRvTimerEnabled); CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); - if (power_gate_core(&power_manager, kTimer_2_pm_e, &power_manager_cpu_counters) != kPowerManagerOk_e) + if (power_gate_core(&power_manager, kRv_Timer_2_pm_e, &power_manager_cpu_counters) != kPowerManagerOk_e) { PRINTF("Error: power manager fail.\n\r"); return EXIT_FAILURE; @@ -149,7 +149,7 @@ int main(int argc, char *argv[]) rv_timer_counter_set_enabled(&timer_2_3, 1, kRvTimerEnabled); CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); - if (power_gate_core(&power_manager, kTimer_3_pm_e, &power_manager_cpu_counters) != kPowerManagerOk_e) + if (power_gate_core(&power_manager, kRv_Timer_3_pm_e, &power_manager_cpu_counters) != kPowerManagerOk_e) { PRINTF("Error: power manager fail.\n\r"); return EXIT_FAILURE; @@ -159,16 +159,16 @@ int main(int argc, char *argv[]) #ifndef TARGET_PYNQ_Z2 // Power-gate and wake-up due to plic bool state = false; - plic_irq_set_priority(GPIO_INTR_31, 1); - plic_irq_set_enabled(GPIO_INTR_31, kPlicToggleEnabled); + plic_irq_set_priority(&rv_plic_0_inf, GPIO_31_INTR, 1); + plic_irq_set_enabled(&rv_plic_0_inf, GPIO_31_INTR, kPlicToggleEnabled); gpio_cfg_t pin2_cfg = {.pin = GPIO_TB_IN, .mode = GpioModeIn,.en_input_sampling = true, .en_intr = true, .intr_type = GpioIntrEdgeRising}; - gpio_config (pin2_cfg); + gpio_config(gpio_1_peri, pin2_cfg); gpio_cfg_t pin1_cfg = {.pin = GPIO_TB_OUT, .mode = GpioModeOutPushPull}; - gpio_config (pin1_cfg); - gpio_write(GPIO_TB_OUT, true); + gpio_config(gpio_1_peri, pin1_cfg); + gpio_write(gpio_1_peri, GPIO_TB_OUT, true); CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); if (power_gate_core(&power_manager, kPlic_pm_e, &power_manager_cpu_counters) != kPowerManagerOk_e) @@ -179,7 +179,7 @@ int main(int argc, char *argv[]) CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); uint32_t intr_num; - plic_irq_complete(&intr_num); + plic_irq_complete(&rv_plic_0_inf, &intr_num); #endif /* write something to stdout */ diff --git a/sw/applications/example_spi_host_dma_power_gate/main.c b/sw/applications/example_spi_host_dma_power_gate/main.c index 0f1a444a9..419b66516 100644 --- a/sw/applications/example_spi_host_dma_power_gate/main.c +++ b/sw/applications/example_spi_host_dma_power_gate/main.c @@ -99,7 +99,7 @@ int main(int argc, char *argv[]) } #ifndef USE_SPI_FLASH - spi_host.base_addr = mmio_region_from_addr((uintptr_t)SPI_HOST_START_ADDRESS); + spi_host.base_addr = mmio_region_from_addr((uintptr_t)SPI_HOST_0_START_ADDRESS); #else spi_host.base_addr = mmio_region_from_addr((uintptr_t)SPI_FLASH_START_ADDRESS); #endif @@ -122,7 +122,7 @@ int main(int argc, char *argv[]) CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); // Set mie.MEIE bit to one to enable machine-level fast dma interrupt - const uint32_t mask = 1 << 19; + const uint32_t mask = MIE_MASK_DMA; CSR_SET_BITS(CSR_REG_MIE, mask); #ifdef USE_SPI_FLASH @@ -145,9 +145,9 @@ int main(int argc, char *argv[]) dma_init(NULL); #ifndef USE_SPI_FLASH - uint8_t slot = DMA_TRIG_SLOT_SPI_RX ; // The DMA will wait for the SPI RX FIFO valid signal + uint8_t slot = DMA_TRIG_SLOT_SPI_HOST_0_RX ; // The DMA will wait for the SPI RX FIFO valid signal #else - uint8_t slot = DMA_TRIG_SLOT_SPI_FLASH_RX ; // The DMA will wait for the SPI FLASH RX FIFO valid signal + uint8_t slot = DMA_TRIG_SLOT_SPI_FLASH_DMA_RX ; // The DMA will wait for the SPI FLASH RX FIFO valid signal #endif static dma_target_t tgt_src = { diff --git a/sw/applications/example_spi_read/main.c b/sw/applications/example_spi_read/main.c index 2e9528160..6d373d75d 100644 --- a/sw/applications/example_spi_read/main.c +++ b/sw/applications/example_spi_read/main.c @@ -149,7 +149,7 @@ int main(int argc, char *argv[]) { // Pick the correct spi device based on simulation type spi_host_t spi; #ifndef USE_SPI_FLASH - spi.base_addr = mmio_region_from_addr((uintptr_t)SPI_HOST_START_ADDRESS); + spi.base_addr = mmio_region_from_addr((uintptr_t)SPI_HOST_0_START_ADDRESS); #else spi.base_addr = mmio_region_from_addr((uintptr_t)SPI_FLASH_START_ADDRESS); #endif diff --git a/sw/applications/example_spi_write/main.c b/sw/applications/example_spi_write/main.c index 2b1a362b8..c8e767a71 100644 --- a/sw/applications/example_spi_write/main.c +++ b/sw/applications/example_spi_write/main.c @@ -154,7 +154,7 @@ int main(int argc, char *argv[]) { // Pick the correct spi device spi_host_t spi; #ifndef USE_SPI_FLASH - spi.base_addr = mmio_region_from_addr((uintptr_t)SPI_HOST_START_ADDRESS); + spi.base_addr = mmio_region_from_addr((uintptr_t)SPI_HOST_0_START_ADDRESS); #else spi.base_addr = mmio_region_from_addr((uintptr_t)SPI_FLASH_START_ADDRESS); #endif diff --git a/sw/device/bsp/w25q/w25q.c b/sw/device/bsp/w25q/w25q.c index 5c7763f56..0bdc9c3e5 100644 --- a/sw/device/bsp/w25q/w25q.c +++ b/sw/device/bsp/w25q/w25q.c @@ -451,9 +451,9 @@ w25q_error_codes_t w25q128jw_read_standard_dma(uint32_t addr, void *data, uint32 // The DMA will wait for the SPI HOST/FLASH RX FIFO valid signal #ifndef USE_SPI_FLASH - uint8_t slot = DMA_TRIG_SLOT_SPI_RX; + uint8_t slot = DMA_TRIG_SLOT_SPI_HOST_0_RX; #else - uint8_t slot = DMA_TRIG_SLOT_SPI_FLASH_RX; + uint8_t slot = DMA_TRIG_SLOT_SPI_FLASH_DMA_RX; #endif // Set up DMA source target @@ -792,9 +792,9 @@ w25q_error_codes_t w25q128jw_read_quad_dma(uint32_t addr, void *data, uint32_t l // The DMA will wait for the SPI HOST/FLASH RX FIFO valid signal #ifndef USE_SPI_FLASH - uint8_t slot = DMA_TRIG_SLOT_SPI_RX; + uint8_t slot = DMA_TRIG_SLOT_SPI_HOST_0_RX; #else - uint8_t slot = DMA_TRIG_SLOT_SPI_FLASH_RX; + uint8_t slot = DMA_TRIG_SLOT_SPI_FLASH_DMA_RX; #endif // Set up DMA source target @@ -1358,9 +1358,9 @@ static w25q_error_codes_t dma_send_toflash(uint8_t *data, uint32_t length) { // The DMA will wait for the SPI HOST/FLASH TX FIFO valid signal #ifndef USE_SPI_FLASH - uint8_t slot = DMA_TRIG_SLOT_SPI_TX; + uint8_t slot = DMA_TRIG_SLOT_SPI_HOST_0_TX; #else - uint8_t slot = DMA_TRIG_SLOT_SPI_FLASH_TX; + uint8_t slot = DMA_TRIG_SLOT_SPI_FLASH_DMA_TX; #endif // Set up DMA source target diff --git a/sw/device/lib/crt/vectors.S b/sw/device/lib/crt/vectors.S index f6a805c65..7b00c2575 100644 --- a/sw/device/lib/crt/vectors.S +++ b/sw/device/lib/crt/vectors.S @@ -49,36 +49,36 @@ vector_table: j __no_irq_handler // 15 : unmapped j __no_irq_handler - // 16 : fast interrupt - timer_1 - j handler_irq_fast_timer_1 - // 17 : fast interrupt - timer_2 - j handler_irq_fast_timer_2 - // 18 : fast interrupt - timer_3 - j handler_irq_fast_timer_3 - // 19 : fast interrupt - dma - j handler_irq_fast_dma - // 20 : fast interrupt - spi - j handler_irq_fast_spi - // 21 : fast interrupt - spi_flash - j handler_irq_fast_spi_flash - // 22 : fast interrupt - gpio_0 - j handler_irq_fast_gpio_0 - // 23 : fast interrupt - gpio_1 - j handler_irq_fast_gpio_1 - // 24 : fast interrupt - gpio_2 - j handler_irq_fast_gpio_2 - // 25 : fast interrupt - gpio_3 - j handler_irq_fast_gpio_3 - // 26 : fast interrupt - gpio_4 - j handler_irq_fast_gpio_4 - // 27 : fast interrupt - gpio_5 - j handler_irq_fast_gpio_5 - // 28 : fast interrupt - gpio_6 - j handler_irq_fast_gpio_6 - // 29 : fast interrupt - gpio_7 - j handler_irq_fast_gpio_7 - // 30 : fast interrupt - unmapped - j __no_irq_handler + // 16 : fast interrupt - 0 + j handler_irq_fast_0 + // 17 : fast interrupt - 1 + j handler_irq_fast_1 + // 18 : fast interrupt - 2 + j handler_irq_fast_2 + // 19 : fast interrupt - 3 + j handler_irq_fast_3 + // 20 : fast interrupt - 4 + j handler_irq_fast_4 + // 21 : fast interrupt - 5 + j handler_irq_fast_5 + // 22 : fast interrupt - 6 + j handler_irq_fast_6 + // 23 : fast interrupt - 7 + j handler_irq_fast_7 + // 24 : fast interrupt - 8 + j handler_irq_fast_8 + // 25 : fast interrupt - 9 + j handler_irq_fast_9 + // 26 : fast interrupt - 10 + j handler_irq_fast_10 + // 27 : fast interrupt - 11 + j handler_irq_fast_11 + // 28 : fast interrupt - 12 + j handler_irq_fast_12 + // 29 : fast interrupt - 13 + j handler_irq_fast_13 + // 30 : fast interrupt - 14 + j handler_irq_fast_14 // vendor interrupts: on Ibex interrupt id 31 is for non-maskable interrupts j __no_irq_handler // 64-32 : not connected on Ibex diff --git a/sw/device/lib/drivers/dma/dma.c b/sw/device/lib/drivers/dma/dma.c index 8aff5ddde..c59c7e543 100644 --- a/sw/device/lib/drivers/dma/dma.c +++ b/sw/device/lib/drivers/dma/dma.c @@ -55,7 +55,7 @@ /** * Returns the mask to enable/disable DMA interrupts. */ -#define DMA_CSR_REG_MIE_MASK (( 1 << 19 ) | (1 << 11 ) ) // @ToDo Add definitions for this 19 and 11 +#define DMA_CSR_REG_MIE_MASK ( MIE_MASK_DMA | (1 << 11 ) ) // @ToDo Add definitions for this 11 /** * Size of a register of 32 bits. diff --git a/sw/device/lib/drivers/dma/dma.h b/sw/device/lib/drivers/dma/dma.h.tpl similarity index 95% rename from sw/device/lib/drivers/dma/dma.h rename to sw/device/lib/drivers/dma/dma.h.tpl index 85ee64751..ec47349c8 100644 --- a/sw/device/lib/drivers/dma/dma.h +++ b/sw/device/lib/drivers/dma/dma.h.tpl @@ -61,12 +61,15 @@ #define DMA_SPI_MODE_SPI_FLASH_RX 0x03 #define DMA_SPI_MODE_SPI_FLASH_TX 0x04 - -#define DMA_SPI_RX_SLOT 0x01 -#define DMA_SPI_TX_SLOT 0x02 -#define DMA_SPI_FLASH_RX_SLOT 0x04 -#define DMA_SPI_FLASH_TX_SLOT 0x08 -#define DMA_I2S_RX_SLOT 0x10 +<% + dma_sources = xheep.get_rh().use_target_as_sv_multi("dma_default_target", xheep.get_ao_node()) + dma_triggers = [] + for i, source in enumerate(dma_sources): + dma_triggers.append((2**i, source.split(".")[-1].upper())) +%> +% for i, trigger in dma_triggers: +#define DMA_${trigger}_SLOT ${f"0x{i:X}"} +% endfor #ifdef __cplusplus extern "C" { @@ -97,15 +100,10 @@ extern "C" { */ typedef enum { - DMA_TRIG_MEMORY = 0, /*!< Reads from memory or writes in - memory. */ - DMA_TRIG_SLOT_SPI_RX = 1, /*!< Slot 1 (MEM < SPI). */ - DMA_TRIG_SLOT_SPI_TX = 2, /*!< Slot 2 (MEM > SPI). */ - DMA_TRIG_SLOT_SPI_FLASH_RX = 4, /*!< Slot 3 (MEM < SPI FLASH). */ - DMA_TRIG_SLOT_SPI_FLASH_TX = 8, /*!< Slot 4 (MEM > SPI FLASH). */ - DMA_TRIG_SLOT_I2S = 16,/*!< Slot 5 (I2S). */ - DMA_TRIG_SLOT_EXT_TX = 32,/*!< Slot 6 (External peripherals TX). */ - DMA_TRIG_SLOT_EXT_RX = 64,/*!< Slot 7 (External peripherals RX). */ + DMA_TRIG_MEMORY = 0, /*!< Reads from memory or writes in memory. */ +% for i, trigger in dma_triggers: + DMA_TRIG_SLOT_${trigger} = ${f"0x{i:X}"}, +% endfor DMA_TRIG__size, /*!< Not used, only for sanity checks. */ DMA_TRIG__undef, /*!< DMA will not be used. */ } dma_trigger_slot_mask_t; @@ -332,11 +330,6 @@ typedef struct /** **/ /****************************************************************************/ -/** - * @brief Attends the plic interrupt. - */ -void handler_irq_dma( uint32_t id ); - /** * @brief This is a non-weak implementation of the function declared in * fast_intr_ctrl.c diff --git a/sw/device/lib/drivers/fast_intr_ctrl/fast_intr_ctrl.c b/sw/device/lib/drivers/fast_intr_ctrl/fast_intr_ctrl.c deleted file mode 100644 index 27c000a00..000000000 --- a/sw/device/lib/drivers/fast_intr_ctrl/fast_intr_ctrl.c +++ /dev/null @@ -1,426 +0,0 @@ -/* - ******************* -******************************* C SOURCE FILE ***************************** -** ******************* -** -** project : X-HEEP -** filename : fast_intr_ctrl.c -** version : 1 -** date : 27/03/23 -** -*************************************************************************** -** -** Copyright (c) EPFL contributors. -** All rights reserved. -** -*************************************************************************** -*/ - -/***************************************************************************/ -/***************************************************************************/ -/** -* @file fast_intr_ctrl.c -* @date 27/03/23 -* @brief The fast interrupt controller peripheral driver -*/ - -/****************************************************************************/ -/** **/ -/* MODULES USED */ -/** **/ -/****************************************************************************/ - -#include "fast_intr_ctrl.h" -#include "core_v_mini_mcu.h" -#include "fast_intr_ctrl_regs.h" // Generated. -#include "fast_intr_ctrl_structs.h" - -/****************************************************************************/ -/** **/ -/* DEFINITIONS AND MACROS */ -/** **/ -/****************************************************************************/ - -/** - * The RISC-V interrupt vector will not include the addresses of the handlers, - * instead, it includes (uncompressed) instructions. Thus the interrupt vector - * will include `j ` for each handler. - * - * The only requirement on the symbol in the jump is that it must be correctly - * aligned. If the processor supports the C extension, this can be 2-byte - * aligned, but 4-byte aligned is compatible with all RISC-V processors. - * - * If the processor is not using interrupt vectoring, then there will be a - * single address where interrupts jump to, which will either contain a function - * (which will need to be aligned), or will contain a jump to a function, again - * which will need to be aligned. - * - * You only need to use this ABI for handlers that are the first function called - * in an interrupt handler. Subsequent functions can just use the regular RISC-V - * calling convention. - */ -#define INTERRUPT_HANDLER_ABI __attribute__((aligned(4), interrupt)) - -/****************************************************************************/ -/** **/ -/* TYPEDEFS AND STRUCTURES */ -/** **/ -/****************************************************************************/ - -/****************************************************************************/ -/** **/ -/* PROTOTYPES OF LOCAL FUNCTIONS */ -/** **/ -/****************************************************************************/ - -/** - * @brief Fast timer 1 irq handler. The first entry point when timer 1 interrupt - * is recieved through fic. - * This function clear the responsible bit in FAST_INTR_PENDING then call a - * function that can be overriden inside peripherals. - */ -INTERRUPT_HANDLER_ABI void handler_irq_fast_timer_1(void); - -/** - * @brief Fast timer 2 irq handler. The first entry point when timer 2 interrupt - * is recieved through fic. - * This function clear the responsible bit in FAST_INTR_PENDING then call a - * function that can be overriden inside peripherals. - */ -INTERRUPT_HANDLER_ABI void handler_irq_fast_timer_2(void); - -/** - * @brief Fast timer 3 irq handler. The first entry point when timer 3 interrupt - * is recieved through fic. - * This function clear the responsible bit in FAST_INTR_PENDING then call a - * function that can be overriden inside peripherals. - */ -INTERRUPT_HANDLER_ABI void handler_irq_fast_timer_3(void); - -/** - * @brief Fast dma irq handler. The first entry point when dma interrupt - * is recieved through fic. - * This function clear the responsible bit in FAST_INTR_PENDING then call a - * function that can be overriden inside peripherals. - */ -INTERRUPT_HANDLER_ABI void handler_irq_fast_dma(void); - -/** - * @brief Fast spi irq handler. The first entry point when spi interrupt - * is recieved through fic. - * This function clear the responsible bit in FAST_INTR_PENDING then call a - * function that can be overriden inside peripherals. - */ -INTERRUPT_HANDLER_ABI void handler_irq_fast_spi(void); - -/** - * @brief Fast spi flash irq handler. The first entry point when spi flash - * interrupt is recieved through fic. - * This function clear the responsible bit in FAST_INTR_PENDING then call a - * function that can be overriden inside peripherals. - */ -INTERRUPT_HANDLER_ABI void handler_irq_fast_spi_flash(void); - -/** - * @brief Fast gpio 0 irq handler. The first entry point when gpio 0 interrupt - * is recieved through fic. - * This function clear the responsible bit in FAST_INTR_PENDING then call a - * function that can be overriden inside peripherals. - */ -INTERRUPT_HANDLER_ABI void handler_irq_fast_gpio_0(void); - -/** - * @brief Fast gpio 1 irq handler. The first entry point when gpio 1 interrupt - * is recieved through fic. - * This function clear the responsible bit in FAST_INTR_PENDING then call a - * function that can be overriden inside peripherals. - */ -INTERRUPT_HANDLER_ABI void handler_irq_fast_gpio_1(void); - -/** - * @brief Fast gpio 2 irq handler. The first entry point when gpio 2 interrupt - * is recieved through fic. - * This function clear the responsible bit in FAST_INTR_PENDING then call a - * function that can be overriden inside peripherals. - */ -INTERRUPT_HANDLER_ABI void handler_irq_fast_gpio_2(void); - -/** - * @brief Fast gpio 3 irq handler. The first entry point when gpio 3 interrupt - * is recieved through fic. - * This function clear the responsible bit in FAST_INTR_PENDING then call a - * function that can be overriden inside peripherals. - */ -INTERRUPT_HANDLER_ABI void handler_irq_fast_gpio_3(void); - -/** - * @brief Fast gpio 4 irq handler. The first entry point when gpio 4 interrupt - * is recieved through fic. - * This function clear the responsible bit in FAST_INTR_PENDING then call a - * function that can be overriden inside peripherals. - */ -INTERRUPT_HANDLER_ABI void handler_irq_fast_gpio_4(void); - -/** - * @brief Fast gpio 5 irq handler. The first entry point when gpio 5 interrupt - * is recieved through fic. - * This function clear the responsible bit in FAST_INTR_PENDING then call a - * function that can be overriden inside peripherals. - */ -INTERRUPT_HANDLER_ABI void handler_irq_fast_gpio_5(void); - -/** - * @brief Fast gpio 6 irq handler. The first entry point when gpio 6 interrupt - * is recieved through fic. - * This function clear the responsible bit in FAST_INTR_PENDING then call a - * function that can be overriden inside peripherals. - */ -INTERRUPT_HANDLER_ABI void handler_irq_fast_gpio_6(void); - -/** - * @brief Fast gpio 7 irq handler. The first entry point when gpio 7 interrupt - * is recieved through fic. - * This function clear the responsible bit in FAST_INTR_PENDING then call a - * function that can be overriden inside peripherals. - */ -INTERRUPT_HANDLER_ABI void handler_irq_fast_gpio_7(void); - -/****************************************************************************/ -/** **/ -/* EXPORTED VARIABLES */ -/** **/ -/****************************************************************************/ - -/****************************************************************************/ -/** **/ -/* GLOBAL VARIABLES */ -/** **/ -/****************************************************************************/ - -/****************************************************************************/ -/** **/ -/* EXPORTED FUNCTIONS */ -/** **/ -/****************************************************************************/ -fast_intr_ctrl_result_t enable_fast_interrupt(fast_intr_ctrl_fast_interrupt_t\ - fast_interrupt, bool enable) -{ - /* masking a 32b go write in reg*/ - uint32_t reg = fast_intr_ctrl_peri->FAST_INTR_ENABLE; - reg = bitfield_bit32_write(reg, fast_interrupt, enable); - /* write in reg through structure */ - fast_intr_ctrl_peri->FAST_INTR_ENABLE = reg; - return kFastIntrCtrlOk_e; -} - -fast_intr_ctrl_result_t enable_all_fast_interrupts(bool enable) -{ - fast_intr_ctrl_peri->FAST_INTR_ENABLE = enable ? 0x7fff : 0x0000; - return kFastIntrCtrlOk_e; -} - - -fast_intr_ctrl_result_t clear_fast_interrupt(fast_intr_ctrl_fast_interrupt_t\ - fast_interrupt) -{ - /* masking a 32b go write in reg*/ - uint32_t reg = 0; - reg = bitfield_bit32_write(reg, fast_interrupt, true); - /* write in reg through structure */ - fast_intr_ctrl_peri->FAST_INTR_CLEAR = reg; - return kFastIntrCtrlOk_e; -} - -__attribute__((weak, optimize("O0"))) void fic_irq_timer_1(void) -{ - /* Users should implement their non-weak version */ -} - -__attribute__((weak, optimize("O0"))) void fic_irq_timer_2(void) -{ - /* Users should implement their non-weak version */ -} - -__attribute__((weak, optimize("O0"))) void fic_irq_timer_3(void) -{ - /* Users should implement their non-weak version */ -} - -__attribute__((weak, optimize("O0"))) void fic_irq_dma(void) -{ - /* Users should implement their non-weak version */ -} - -__attribute__((weak, optimize("O0"))) void fic_irq_spi(void) -{ - /* Users should implement their non-weak version */ -} - -__attribute__((weak, optimize("O0"))) void fic_irq_spi_flash(void) -{ - /* Users should implement their non-weak version */ -} - -__attribute__((weak, optimize("O0"))) void fic_irq_gpio_0(void) -{ - /* Users should implement their non-weak version */ -} - -__attribute__((weak, optimize("O0"))) void fic_irq_gpio_1(void) -{ - /* Users should implement their non-weak version */ -} - -__attribute__((weak, optimize("O0"))) void fic_irq_gpio_2(void) -{ - /* Users should implement their non-weak version */ -} - -__attribute__((weak, optimize("O0"))) void fic_irq_gpio_3(void) -{ - /* Users should implement their non-weak version */ -} - -__attribute__((weak, optimize("O0"))) void fic_irq_gpio_4(void) -{ - /* Users should implement their non-weak version */ -} - -__attribute__((weak, optimize("O0"))) void fic_irq_gpio_5(void) -{ - /* Users should implement their non-weak version */ -} - -__attribute__((weak, optimize("O0"))) void fic_irq_gpio_6(void) -{ - /* Users should implement their non-weak version */ -} - -__attribute__((weak, optimize("O0"))) void fic_irq_gpio_7(void) -{ - /* Users should implement their non-weak version */ -} - -/****************************************************************************/ -/** **/ -/* LOCAL FUNCTIONS */ -/** **/ -/****************************************************************************/ - -void handler_irq_fast_timer_1(void) -{ - // The interrupt is cleared. - clear_fast_interrupt(kTimer_1_fic_e); - // call the weak fic handler - fic_irq_timer_1(); -} - -void handler_irq_fast_timer_2(void) -{ - // The interrupt is cleared. - clear_fast_interrupt(kTimer_2_fic_e); - // call the weak fic handler - fic_irq_timer_2(); -} - -void handler_irq_fast_timer_3(void) -{ - // The interrupt is cleared. - clear_fast_interrupt(kTimer_3_fic_e); - // call the weak fic handler - fic_irq_timer_3(); -} - -void handler_irq_fast_dma(void) -{ - // The interrupt is cleared. - clear_fast_interrupt(kDma_fic_e); - // call the weak fic handler - fic_irq_dma(); -} - -void handler_irq_fast_spi(void) -{ - // The interrupt is cleared. - clear_fast_interrupt(kSpi_fic_e); - // call the weak fic handler - fic_irq_spi(); -} - -void handler_irq_fast_spi_flash(void) -{ - // The interrupt is cleared. - clear_fast_interrupt(kSpiFlash_fic_e); - // call the weak fic handler - fic_irq_spi_flash(); -} - -void handler_irq_fast_gpio_0(void) -{ - // The interrupt is cleared. - clear_fast_interrupt(kGpio_0_fic_e); - // call the weak fic handler - fic_irq_gpio_0(); -} - -void handler_irq_fast_gpio_1(void) -{ - // The interrupt is cleared. - clear_fast_interrupt(kGpio_1_fic_e); - // call the weak fic handler - fic_irq_gpio_1(); -} - -void handler_irq_fast_gpio_2(void) -{ - // The interrupt is cleared. - clear_fast_interrupt(kGpio_2_fic_e); - // call the weak fic handler - fic_irq_gpio_2(); -} - -void handler_irq_fast_gpio_3(void) -{ - // The interrupt is cleared. - clear_fast_interrupt(kGpio_3_fic_e); - // call the weak fic handler - fic_irq_gpio_3(); -} - -void handler_irq_fast_gpio_4(void) -{ - // The interrupt is cleared. - clear_fast_interrupt(kGpio_4_fic_e); - // call the weak fic handler - fic_irq_gpio_4(); -} - -void handler_irq_fast_gpio_5(void) -{ - // The interrupt is cleared. - clear_fast_interrupt(kGpio_5_fic_e); - // call the weak fic handler - fic_irq_gpio_5(); -} - -void handler_irq_fast_gpio_6(void) -{ - // The interrupt is cleared. - clear_fast_interrupt(kGpio_6_fic_e); - // call the weak fic handler - fic_irq_gpio_6(); -} - -void handler_irq_fast_gpio_7(void) -{ - // The interrupt is cleared. - clear_fast_interrupt(kGpio_7_fic_e); - // call the weak fic handler - fic_irq_gpio_7(); -} - -/****************************************************************************/ -/** **/ -/* EOF */ -/** **/ -/****************************************************************************/ diff --git a/sw/device/lib/drivers/fast_intr_ctrl/fast_intr_ctrl.c.tpl b/sw/device/lib/drivers/fast_intr_ctrl/fast_intr_ctrl.c.tpl new file mode 100644 index 000000000..a1a6c9e9e --- /dev/null +++ b/sw/device/lib/drivers/fast_intr_ctrl/fast_intr_ctrl.c.tpl @@ -0,0 +1,169 @@ +/* + ******************* +******************************* C SOURCE FILE ***************************** +** ******************* +** +** project : X-HEEP +** filename : fast_intr_ctrl.c +** version : 1 +** date : 27/03/23 +** +*************************************************************************** +** +** Copyright (c) EPFL contributors. +** All rights reserved. +** +*************************************************************************** +*/ + +/***************************************************************************/ +/***************************************************************************/ +/** +* @file fast_intr_ctrl.c +* @date 27/03/23 +* @brief The fast interrupt controller peripheral driver +*/ + +/****************************************************************************/ +/** **/ +/* MODULES USED */ +/** **/ +/****************************************************************************/ + +#include "fast_intr_ctrl.h" +#include "core_v_mini_mcu.h" +#include "fast_intr_ctrl_regs.h" // Generated. +#include "fast_intr_ctrl_structs.h" + +/****************************************************************************/ +/** **/ +/* DEFINITIONS AND MACROS */ +/** **/ +/****************************************************************************/ + +/** + * The RISC-V interrupt vector will not include the addresses of the handlers, + * instead, it includes (uncompressed) instructions. Thus the interrupt vector + * will include `j ` for each handler. + * + * The only requirement on the symbol in the jump is that it must be correctly + * aligned. If the processor supports the C extension, this can be 2-byte + * aligned, but 4-byte aligned is compatible with all RISC-V processors. + * + * If the processor is not using interrupt vectoring, then there will be a + * single address where interrupts jump to, which will either contain a function + * (which will need to be aligned), or will contain a jump to a function, again + * which will need to be aligned. + * + * You only need to use this ABI for handlers that are the first function called + * in an interrupt handler. Subsequent functions can just use the regular RISC-V + * calling convention. + */ +#define INTERRUPT_HANDLER_ABI __attribute__((aligned(4), interrupt)) + +/****************************************************************************/ +/** **/ +/* TYPEDEFS AND STRUCTURES */ +/** **/ +/****************************************************************************/ + +/****************************************************************************/ +/** **/ +/* PROTOTYPES OF LOCAL FUNCTIONS */ +/** **/ +/****************************************************************************/ + +% for i in range(15): +/** + * @brief Fast irq ${i} handler. The first entry point when timer 1 interrupt + * is recieved through fic. + * This function clear the responsible bit in FAST_INTR_PENDING then call a + * function that can be overriden inside peripherals. + */ +INTERRUPT_HANDLER_ABI void handler_irq_fast_${i}(void); + +%endfor + + +/****************************************************************************/ +/** **/ +/* EXPORTED VARIABLES */ +/** **/ +/****************************************************************************/ + +/****************************************************************************/ +/** **/ +/* GLOBAL VARIABLES */ +/** **/ +/****************************************************************************/ + +/****************************************************************************/ +/** **/ +/* EXPORTED FUNCTIONS */ +/** **/ +/****************************************************************************/ +fast_intr_ctrl_result_t enable_fast_interrupt(fast_intr_ctrl_fast_interrupt_t\ + fast_interrupt, bool enable) +{ + /* masking a 32b go write in reg*/ + uint32_t reg = fast_intr_ctrl_peri->FAST_INTR_ENABLE; + reg = bitfield_bit32_write(reg, fast_interrupt, enable); + /* write in reg through structure */ + fast_intr_ctrl_peri->FAST_INTR_ENABLE = reg; + return kFastIntrCtrlOk_e; +} + +fast_intr_ctrl_result_t enable_all_fast_interrupts(bool enable) +{ + fast_intr_ctrl_peri->FAST_INTR_ENABLE = enable ? 0x7fff : 0x0000; + return kFastIntrCtrlOk_e; +} + + +fast_intr_ctrl_result_t clear_fast_interrupt(fast_intr_ctrl_fast_interrupt_t\ + fast_interrupt) +{ + /* masking a 32b go write in reg*/ + uint32_t reg = 0; + reg = bitfield_bit32_write(reg, fast_interrupt, true); + /* write in reg through structure */ + fast_intr_ctrl_peri->FAST_INTR_CLEAR = reg; + return kFastIntrCtrlOk_e; +} + + +<% + intr_sources = xheep.get_rh().use_target_as_sv_multi("fast_irq_target", xheep.get_mcu_node()) + intrs = [] + for i, intr_s in enumerate(intr_sources): + ep = xheep.get_rh().get_source_ep_copy(intr_s.split(".")[-1]) + intrs.append(ep.handler) + for _ in range(i+1, 15): + intrs.append("") +%> +% for i, intr in enumerate(intrs): +% if intr != "": + +__attribute__((weak, optimize("O0"))) void ${intr}(void) +{ + /* Users should implement their non-weak version */ +} +% endif + +void handler_irq_fast_${i}(void) +{ + // The interrupt is cleared. + clear_fast_interrupt(${i}); +% if intr != "": + // call the weak fic handler + ${intr}(); +% endif +} + +% endfor + +/****************************************************************************/ +/** **/ +/* EOF */ +/** **/ +/****************************************************************************/ diff --git a/sw/device/lib/drivers/fast_intr_ctrl/fast_intr_ctrl.h b/sw/device/lib/drivers/fast_intr_ctrl/fast_intr_ctrl.h.tpl similarity index 58% rename from sw/device/lib/drivers/fast_intr_ctrl/fast_intr_ctrl.h rename to sw/device/lib/drivers/fast_intr_ctrl/fast_intr_ctrl.h.tpl index 879975515..7f08b6562 100644 --- a/sw/device/lib/drivers/fast_intr_ctrl/fast_intr_ctrl.h +++ b/sw/device/lib/drivers/fast_intr_ctrl/fast_intr_ctrl.h.tpl @@ -42,7 +42,20 @@ /** DEFINITIONS AND MACROS **/ /** **/ /****************************************************************************/ - +<% + intr_sources = xheep.get_rh().use_target_as_sv_multi("fast_irq_target", xheep.get_mcu_node()) + intrs = [] + for i, intr_s in enumerate(intr_sources): + ep = xheep.get_rh().get_source_ep_copy(intr_s.split(".")[-1]) + intrs.append(ep.handler) +%> + +#define MIE_MASK_FIC_BASE_BIT 16 +% for i, intr in enumerate(intrs): +% if intr != "": +#define MIE_MASK_${intr[len("fic_irq_"):].upper()} ( (uint32_t) 1 << (${i} + MIE_MASK_FIC_BASE_BIT) ) +% endif +% endfor /****************************************************************************/ @@ -59,26 +72,18 @@ typedef enum fast_intr_ctrl_result { kFastIntrCtrlError_e = 1, /*!< an error occured. */ } fast_intr_ctrl_result_t; + /** * Specify the modules connected to FIC. * This enum is used as an input for clearing the specifc bit inside * pending register while recieving an interrupt through FIC. */ typedef enum fast_intr_ctrl_fast_interrupt { - kTimer_1_fic_e = 0, /*!< Timer 1. */ - kTimer_2_fic_e = 1, /*!< Timer 2. */ - kTimer_3_fic_e = 2, /*!< Timer 3. */ - kDma_fic_e = 3, /*!< DMA. */ - kSpi_fic_e = 4, /*!< SPI. */ - kSpiFlash_fic_e = 5, /*!< SPI Flash. */ - kGpio_0_fic_e = 6, /*!< GPIO 0. */ - kGpio_1_fic_e = 7, /*!< GPIO 1. */ - kGpio_2_fic_e = 8, /*!< GPIO 2. */ - kGpio_3_fic_e = 9, /*!< GPIO 3. */ - kGpio_4_fic_e = 10,/*!< GPIO 4. */ - kGpio_5_fic_e = 11,/*!< GPIO 5. */ - kGpio_6_fic_e = 12,/*!< GPIO 6. */ - kGpio_7_fic_e = 13,/*!< GPIO 7. */ +% for i, intr in enumerate(intrs): +% if intr != "": + k${intr[len("fic_irq_"):].title()}_fic_e = ${i}, +% endif +% endfor } fast_intr_ctrl_fast_interrupt_t; /****************************************************************************/ @@ -124,117 +129,18 @@ fast_intr_ctrl_result_t enable_all_fast_interrupts(bool enable); fast_intr_ctrl_result_t clear_fast_interrupt(fast_intr_ctrl_fast_interrupt_t\ fast_interrupt); +% for intr in intrs: +% if intr != "": /** - * @brief fast interrupt controller irq for timer 1 - * `fast_intr_ctrl.c` provides a weak definition of this symbol, which can - * be overridden at link-time by providing an additional non-weak definition - * inside peripherals connected through FIC - */ -void fic_irq_timer_1(void); - -/** - * @brief fast interrupt controller irq for timer 2 - * `fast_intr_ctrl.c` provides a weak definition of this symbol, which can - * be overridden at link-time by providing an additional non-weak definition - * inside peripherals connected through FIC - */ -void fic_irq_timer_2(void); - -/** - * @brief fast interrupt controller irq for timer 3 - * `fast_intr_ctrl.c` provides a weak definition of this symbol, which can - * be overridden at link-time by providing an additional non-weak definition - * inside peripherals connected through FIC - */ -void fic_irq_timer_3(void); - -/** - * @brief fast interrupt controller irq for dma + * @brief fast interrupt controller irq for ${intr} * `fast_intr_ctrl.c` provides a weak definition of this symbol, which can * be overridden at link-time by providing an additional non-weak definition * inside peripherals connected through FIC */ -void fic_irq_dma(void); +void ${intr}(void); -/** - * @brief fast interrupt controller irq for spi - * `fast_intr_ctrl.c` provides a weak definition of this symbol, which can - * be overridden at link-time by providing an additional non-weak definition - * inside peripherals connected through FIC - */ -void fic_irq_spi(void); - -/** - * @brief fast interrupt controller irq for spi flash - * `fast_intr_ctrl.c` provides a weak definition of this symbol, which can - * be overridden at link-time by providing an additional non-weak definition - * inside peripherals connected through FIC - */ -void fic_irq_spi_flash(void); - -/** - * @brief fast interrupt controller irq for gpio 0 - * `fast_intr_ctrl.c` provides a weak definition of this symbol, which can - * be overridden at link-time by providing an additional non-weak definition - * inside peripherals connected through FIC - */ -void fic_irq_gpio_0(void); - -/** - * @brief fast interrupt controller irq for gpio 1 - * `fast_intr_ctrl.c` provides a weak definition of this symbol, which can - * be overridden at link-time by providing an additional non-weak definition - * inside peripherals connected through FIC - */ -void fic_irq_gpio_1(void); - -/** - * @brief fast interrupt controller irq for gpio 2 - * `fast_intr_ctrl.c` provides a weak definition of this symbol, which can - * be overridden at link-time by providing an additional non-weak definition - * inside peripherals connected through FIC - */ -void fic_irq_gpio_2(void); - -/** - * @brief fast interrupt controller irq for gpio 3 - * `fast_intr_ctrl.c` provides a weak definition of this symbol, which can - * be overridden at link-time by providing an additional non-weak definition - * inside peripherals connected through FIC - */ -void fic_irq_gpio_3(void); - -/** - * @brief fast interrupt controller irq for gpio 4 - * `fast_intr_ctrl.c` provides a weak definition of this symbol, which can - * be overridden at link-time by providing an additional non-weak definition - * inside peripherals connected through FIC - */ -void fic_irq_gpio_4(void); - -/** - * @brief fast interrupt controller irq for gpio 5 - * `fast_intr_ctrl.c` provides a weak definition of this symbol, which can - * be overridden at link-time by providing an additional non-weak definition - * inside peripherals connected through FIC - */ -void fic_irq_gpio_5(void); - -/** - * @brief fast interrupt controller irq for gpio 6 - * `fast_intr_ctrl.c` provides a weak definition of this symbol, which can - * be overridden at link-time by providing an additional non-weak definition - * inside peripherals connected through FIC - */ -void fic_irq_gpio_6(void); - -/** - * @brief fast interrupt controller irq for gpio 7 - * `fast_intr_ctrl.c` provides a weak definition of this symbol, which can - * be overridden at link-time by providing an additional non-weak definition - * inside peripherals connected through FIC - */ -void fic_irq_gpio_7(void); +% endif +% endfor /****************************************************************************/ diff --git a/sw/device/lib/drivers/gpio/gpio.c b/sw/device/lib/drivers/gpio/gpio.c index f5cb004f2..cf728f94e 100644 --- a/sw/device/lib/drivers/gpio/gpio.c +++ b/sw/device/lib/drivers/gpio/gpio.c @@ -43,10 +43,6 @@ /** **/ /****************************************************************************/ -/** - * GPIO_AO pointer - */ -#define gpio_ao_peri ((volatile gpio *) GPIO_AO_START_ADDRESS) /** @@ -96,25 +92,10 @@ */ #define GPIO_MODE_NUM_PINS 16 -/** - * The first interrupt ID for the GPIOS - */ -#define GPIO_INTR_START GPIO_INTR_8 - -/** - * The last interrupt ID for the GPIOS - */ -#define GPIO_INTR_END GPIO_INTR_31 - -/** - * The number of GPIO interrupt IDs - */ -#define GPIO_INTR_QTY ( GPIO_INTR_END - GPIO_INTR_START + 1 ) - /** * Array of handlers for the different GPIO interrupts. */ -void (*gpio_handlers[ GPIO_INTR_QTY ])( void ); +//void (*gpio_handlers[ GPIO_INTR_QTY ])( void ); /****************************************************************************/ @@ -127,77 +108,39 @@ void (*gpio_handlers[ GPIO_INTR_QTY ])( void ); * A dummy function to prevent unassigned irq to access a null pointer. */ -volatile gpio * gpio_perif; - -__attribute__((optimize("O0"))) static void gpio_handler_irq_dummy( uint32_t dummy ); - - -__attribute__((always_inline)) void select_gpio_domain(gpio_pin_number_t pin) -{ - - gpio_perif = pin < GPIO_AO_DOMAIN_LIMIT ? gpio_ao_peri : gpio_peri; - return; -} - /****************************************************************************/ /** **/ /* EXPORTED FUNCTIONS */ /** **/ /****************************************************************************/ -gpio_result_t gpio_assign_irq_handler( uint32_t intr_id, - void *handler() ) -{ - if( intr_id >= GPIO_INTR_START && intr_id <= GPIO_INTR_END ) - { - gpio_handlers[ intr_id - GPIO_INTR_START ] = (void (*)(void))handler; - return GpioOk; - } - return GpioError; -} - -void gpio_reset_handlers_list( ) -{ - for( uint8_t i = 0; i < GPIO_INTR_QTY; i++ ) - { - gpio_handlers[ i ] = (void (*)(void))&gpio_handler_irq_dummy; - } -} - -void handler_irq_gpio( uint32_t id ) -{ - gpio_handlers[ id - GPIO_INTR_START ](); -} - -gpio_result_t gpio_config (gpio_cfg_t cfg) +gpio_result_t gpio_config (volatile gpio *gpio_perif, gpio_cfg_t cfg) { /* check that pin is in acceptable range. */ if (cfg.pin > (MAX_PIN-1) || cfg.pin < 0) return GpioPinNotAcceptable; /* reset pin coniguration first.*/ - gpio_reset (cfg.pin); + gpio_reset (gpio_perif, cfg.pin); /* check mode. */ if ((cfg.mode < GpioModeIn) || (cfg.mode > GpioModeoutOpenDrain1)) return GpioModeNotAcceptable; /* set mode. */ - gpio_set_mode (cfg.pin, cfg.mode); + gpio_set_mode (gpio_perif, cfg.pin, cfg.mode); /* if input sampling is enabled */ if (cfg.en_input_sampling == true) - gpio_en_input_sampling (cfg.pin); + gpio_en_input_sampling (gpio_perif, cfg.pin); /* if interrupt is enabled. Also after enabling check for error */ if (cfg.en_intr == true) - if (gpio_intr_en (cfg.pin, cfg.intr_type) != GpioOk) + if (gpio_intr_en (gpio_perif, cfg.pin, cfg.intr_type) != GpioOk) return GpioIntrTypeNotAcceptable; return GpioOk; } -gpio_result_t gpio_set_mode (gpio_pin_number_t pin, gpio_mode_t mode) +gpio_result_t gpio_set_mode (volatile gpio *gpio_perif, gpio_pin_number_t pin, gpio_mode_t mode) { if (pin < 0 && pin > (MAX_PIN-1)) return GpioModeNotAcceptable; - select_gpio_domain(pin); - if (pin >= 0 && pin < 1*GPIO_MODE_NUM_PINS) gpio_perif->GPIO_MODE0 = bitfield_write(gpio_perif->GPIO_MODE0, BIT_MASK_3, 2*pin, mode); @@ -207,62 +150,43 @@ gpio_result_t gpio_set_mode (gpio_pin_number_t pin, gpio_mode_t mode) return GpioOk; } -gpio_result_t gpio_en_input_sampling (gpio_pin_number_t pin) +gpio_result_t gpio_en_input_sampling (volatile gpio *gpio_perif, gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - select_gpio_domain(pin); gpio_perif->GPIO_EN0 = bitfield_write(gpio_perif->GPIO_EN0, BIT_MASK_1, pin, GPIO_EN__ENABLED); return GpioOk; } -gpio_result_t gpio_dis_input_sampling (gpio_pin_number_t pin) +gpio_result_t gpio_dis_input_sampling (volatile gpio *gpio_perif, gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - select_gpio_domain(pin); gpio_perif->GPIO_EN0 = bitfield_write(gpio_perif->GPIO_EN0, BIT_MASK_1, pin, GPIO_EN__DISABLED); return GpioOk; } -gpio_result_t gpio_reset (gpio_pin_number_t pin) +gpio_result_t gpio_reset (volatile gpio *gpio_perif, gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - gpio_intr_set_mode (pin, 0); - gpio_set_mode (pin, GpioModeIn); - gpio_dis_input_sampling (pin); - select_gpio_domain(pin); + gpio_intr_set_mode (gpio_perif, pin, 0); + gpio_set_mode (gpio_perif, pin, GpioModeIn); + gpio_dis_input_sampling (gpio_perif, pin); gpio_perif->GPIO_CLEAR0 = bitfield_write(gpio_perif->GPIO_CLEAR0, BIT_MASK_1, pin, GPIO_REMOVE_MASK); gpio_perif->GPIO_SET0 = bitfield_write(gpio_perif->GPIO_SET0, BIT_MASK_1, pin, GPIO_REMOVE_MASK); - gpio_intr_dis_all(pin); - gpio_intr_clear_stat(pin); + gpio_intr_dis_all(gpio_perif, pin); + gpio_intr_clear_stat(gpio_perif, pin); return GpioOk; } -gpio_result_t gpio_reset_all (void) +gpio_result_t gpio_reset_all (volatile gpio *gpio_perif) { - - /* first reset the GPIO in the AO domain by setting the GPIO pin to 0 */ - select_gpio_domain(0); - gpio_perif->GPIO_MODE0 = 0; - gpio_perif->GPIO_MODE1 = 0; - gpio_perif->GPIO_EN0 = 0; - gpio_perif->GPIO_CLEAR0 = 0; - gpio_perif->GPIO_SET0 = 0; - gpio_perif->GPIO_TOGGLE0 = 0; - gpio_perif->INTRPT_RISE_EN0 = 0; - gpio_perif->INTRPT_FALL_EN0 = 0; - gpio_perif->INTRPT_LVL_HIGH_EN0 = 0; - gpio_perif->INTRPT_LVL_LOW_EN0 = 0; - gpio_perif->INTRPT_STATUS0 = 0xFFFFFFFF; - /* then reset the GPIO in the peripheral domain by setting the GPIO pin to GPIO_AO_DOMAIN_LIMIT */ - select_gpio_domain(GPIO_AO_DOMAIN_LIMIT); gpio_perif->GPIO_MODE0 = 0; gpio_perif->GPIO_MODE1 = 0; gpio_perif->GPIO_EN0 = 0; @@ -278,120 +202,108 @@ gpio_result_t gpio_reset_all (void) gpio_reset_handlers_list( ); } -gpio_result_t gpio_read (gpio_pin_number_t pin, bool *val) +gpio_result_t gpio_read (volatile gpio *gpio_perif, gpio_pin_number_t pin, bool *val) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - select_gpio_domain(pin); *val = bitfield_read(gpio_perif->GPIO_IN0, BIT_MASK_1, pin); return GpioOk; } -gpio_result_t gpio_toggle (gpio_pin_number_t pin) +gpio_result_t gpio_toggle (volatile gpio *gpio_perif, gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - select_gpio_domain(pin); gpio_perif->GPIO_OUT0 = bitfield_write(gpio_perif->GPIO_OUT0, BIT_MASK_1, pin, !(bitfield_read(gpio_perif->GPIO_OUT0, BIT_MASK_1, pin))); return GpioOk; } -gpio_result_t gpio_write (gpio_pin_number_t pin, bool val) +gpio_result_t gpio_write (volatile gpio *gpio_perif, gpio_pin_number_t pin, bool val) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - select_gpio_domain(pin); gpio_perif->GPIO_OUT0 = bitfield_write(gpio_perif->GPIO_OUT0, BIT_MASK_1, pin, val); return GpioOk; } -gpio_result_t gpio_intr_en_rise (gpio_pin_number_t pin) +gpio_result_t gpio_intr_en_rise (volatile gpio *gpio_perif, gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - select_gpio_domain(pin); gpio_perif->INTRPT_RISE_EN0 = bitfield_write( gpio_perif->INTRPT_RISE_EN0, BIT_MASK_1, pin, GPIO_INTR_ENABLE); return GpioOk; } -gpio_result_t gpio_intr_en_fall (gpio_pin_number_t pin) +gpio_result_t gpio_intr_en_fall (volatile gpio *gpio_perif, gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - select_gpio_domain(pin); gpio_perif->INTRPT_FALL_EN0 = bitfield_write(gpio_perif->INTRPT_FALL_EN0, BIT_MASK_1, pin, GPIO_INTR_ENABLE); return GpioOk; } -gpio_result_t gpio_intr_en_lvl_high (gpio_pin_number_t pin) +gpio_result_t gpio_intr_en_lvl_high (volatile gpio *gpio_perif, gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - select_gpio_domain(pin); gpio_perif->INTRPT_LVL_HIGH_EN0 = bitfield_write( gpio_perif->INTRPT_LVL_HIGH_EN0, BIT_MASK_1, pin, GPIO_INTR_ENABLE); return GpioOk; } -gpio_result_t gpio_intr_en_lvl_low (gpio_pin_number_t pin) +gpio_result_t gpio_intr_en_lvl_low (volatile gpio *gpio_perif, gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - select_gpio_domain(pin); gpio_perif->INTRPT_LVL_LOW_EN0 = bitfield_write( gpio_perif->INTRPT_LVL_LOW_EN0, BIT_MASK_1, pin, GPIO_INTR_ENABLE); return GpioOk; } -gpio_result_t gpio_intr_dis_rise (gpio_pin_number_t pin) +gpio_result_t gpio_intr_dis_rise (volatile gpio *gpio_perif, gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - select_gpio_domain(pin); gpio_perif->INTRPT_RISE_EN0 = bitfield_write( gpio_perif->INTRPT_RISE_EN0, BIT_MASK_1, pin, GPIO_INTR_DISABLE); return GpioOk; } -gpio_result_t gpio_intr_dis_fall (gpio_pin_number_t pin) +gpio_result_t gpio_intr_dis_fall (volatile gpio *gpio_perif, gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - select_gpio_domain(pin); gpio_perif->INTRPT_FALL_EN0 = bitfield_write( gpio_perif->INTRPT_FALL_EN0, BIT_MASK_1, pin, GPIO_INTR_DISABLE); return GpioOk; } -gpio_result_t gpio_intr_dis_lvl_high (gpio_pin_number_t pin) +gpio_result_t gpio_intr_dis_lvl_high (volatile gpio *gpio_perif, gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - select_gpio_domain(pin); gpio_perif->INTRPT_LVL_HIGH_EN0 = bitfield_write( gpio_perif->INTRPT_LVL_HIGH_EN0, BIT_MASK_1, pin, GPIO_INTR_DISABLE); return GpioOk; } -gpio_result_t gpio_intr_dis_lvl_low (gpio_pin_number_t pin) +gpio_result_t gpio_intr_dis_lvl_low (volatile gpio *gpio_perif, gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - select_gpio_domain(pin); gpio_perif->INTRPT_LVL_LOW_EN0 = bitfield_write( gpio_perif->INTRPT_LVL_LOW_EN0, BIT_MASK_1, pin, GPIO_INTR_DISABLE); return GpioOk; } -gpio_result_t gpio_intr_dis_all (gpio_pin_number_t pin){ +gpio_result_t gpio_intr_dis_all (volatile gpio *gpio_perif, gpio_pin_number_t pin){ if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - select_gpio_domain(pin); gpio_perif->INTRPT_RISE_EN0 = bitfield_write( gpio_perif->INTRPT_RISE_EN0, BIT_MASK_1, pin, GPIO_INTR_DISABLE); gpio_perif->INTRPT_FALL_EN0 = bitfield_write( @@ -403,36 +315,36 @@ gpio_result_t gpio_intr_dis_all (gpio_pin_number_t pin){ return GpioOk; } -gpio_result_t gpio_intr_en (gpio_pin_number_t pin, gpio_intr_type_t type) +gpio_result_t gpio_intr_en (volatile gpio *gpio_perif, gpio_pin_number_t pin, gpio_intr_type_t type) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - gpio_intr_dis_all(pin); + gpio_intr_dis_all(gpio_perif, pin); switch(type) { case GpioIntrEdgeRising: - gpio_intr_en_rise(pin); + gpio_intr_en_rise(gpio_perif, pin); break; case GpioIntrEdgeFalling: - gpio_intr_en_fall(pin); + gpio_intr_en_fall(gpio_perif, pin); break; case GpioIntrLevelLow: - gpio_intr_en_lvl_low(pin); + gpio_intr_en_lvl_low(gpio_perif, pin); break; case GpioIntrLevelHigh: - gpio_intr_en_lvl_high(pin); + gpio_intr_en_lvl_high(gpio_perif, pin); break; case GpioIntrEdgeRisingFalling: - gpio_intr_en_rise(pin); - gpio_intr_en_fall(pin); + gpio_intr_en_rise(gpio_perif, pin); + gpio_intr_en_fall(gpio_perif, pin); break; case GpioIntrEdgeRisingLevelLow: - gpio_intr_en_rise(pin); - gpio_intr_en_lvl_low(pin); + gpio_intr_en_rise(gpio_perif, pin); + gpio_intr_en_lvl_low(gpio_perif, pin); break; case GpioIntrEdgeFallingLevelHigh: - gpio_intr_en_fall(pin); - gpio_intr_en_lvl_high(pin); + gpio_intr_en_fall(gpio_perif, pin); + gpio_intr_en_lvl_high(gpio_perif, pin); break; default: return GpioIntrTypeNotAcceptable; @@ -440,55 +352,51 @@ gpio_result_t gpio_intr_en (gpio_pin_number_t pin, gpio_intr_type_t type) return GpioOk; } -gpio_result_t gpio_intr_check_stat_rise (gpio_pin_number_t pin, bool *is_pending) +gpio_result_t gpio_intr_check_stat_rise (volatile gpio *gpio_perif, gpio_pin_number_t pin, bool *is_pending) { if (pin > (MAX_PIN-1) || pin < 0) { *is_pending = GPIO_INTR_IS_NOT_TRIGGERED; return GpioPinNotAcceptable; } - select_gpio_domain(pin); *is_pending = bitfield_read(gpio_perif->INTRPT_RISE_STATUS0, BIT_MASK_1, pin); return GpioOk; } -gpio_result_t gpio_intr_check_stat_fall (gpio_pin_number_t pin, bool *is_pending) +gpio_result_t gpio_intr_check_stat_fall (volatile gpio *gpio_perif, gpio_pin_number_t pin, bool *is_pending) { if (pin > (MAX_PIN-1) || pin < 0) { *is_pending = GPIO_INTR_IS_NOT_TRIGGERED; return GpioPinNotAcceptable; } - select_gpio_domain(pin); *is_pending = bitfield_read(gpio_perif->INTRPT_FALL_STATUS0, BIT_MASK_1, pin); return GpioOk; } -gpio_result_t gpio_intr_check_stat_lvl_low (gpio_pin_number_t pin, bool *is_pending) +gpio_result_t gpio_intr_check_stat_lvl_low (volatile gpio *gpio_perif, gpio_pin_number_t pin, bool *is_pending) { if (pin > (MAX_PIN-1) || pin < 0) { *is_pending = GPIO_INTR_IS_NOT_TRIGGERED; return GpioPinNotAcceptable; } - select_gpio_domain(pin); *is_pending = bitfield_read(gpio_perif->INTRPT_LVL_LOW_STATUS0, BIT_MASK_1, pin); return GpioOk; } -gpio_result_t gpio_intr_check_stat_lvl_high (gpio_pin_number_t pin, bool *is_pending) +gpio_result_t gpio_intr_check_stat_lvl_high (volatile gpio *gpio_perif, gpio_pin_number_t pin, bool *is_pending) { if (pin > (MAX_PIN-1) || pin < 0) { *is_pending = GPIO_INTR_IS_NOT_TRIGGERED; return GpioPinNotAcceptable; } - select_gpio_domain(pin); *is_pending = bitfield_read(gpio_perif->INTRPT_LVL_HIGH_STATUS0, BIT_MASK_1, pin); return GpioOk; } -gpio_result_t gpio_intr_check_stat (gpio_pin_number_t pin, bool *is_pending) +gpio_result_t gpio_intr_check_stat (volatile gpio *gpio_perif, gpio_pin_number_t pin, bool *is_pending) { if (pin > (MAX_PIN-1) || pin < 0) { @@ -499,60 +407,54 @@ gpio_result_t gpio_intr_check_stat (gpio_pin_number_t pin, bool *is_pending) return GpioOk; } -gpio_result_t gpio_intr_clear_stat_rise (gpio_pin_number_t pin) +gpio_result_t gpio_intr_clear_stat_rise (volatile gpio *gpio_perif, gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - select_gpio_domain(pin); gpio_perif->INTRPT_RISE_STATUS0 = bitfield_write( gpio_perif->INTRPT_RISE_STATUS0, BIT_MASK_1, pin, GPIO_INTR_CLEAR); return GpioOk; } -gpio_result_t gpio_intr_clear_stat_fall (gpio_pin_number_t pin) +gpio_result_t gpio_intr_clear_stat_fall (volatile gpio *gpio_perif, gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - select_gpio_domain(pin); gpio_perif->INTRPT_FALL_STATUS0 = bitfield_write( gpio_perif->INTRPT_FALL_STATUS0, BIT_MASK_1, pin, GPIO_INTR_CLEAR); return GpioOk; } -gpio_result_t gpio_intr_clear_stat_lvl_low (gpio_pin_number_t pin) +gpio_result_t gpio_intr_clear_stat_lvl_low (volatile gpio *gpio_perif, gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - select_gpio_domain(pin); gpio_perif->INTRPT_LVL_LOW_STATUS0 = bitfield_write( gpio_perif->INTRPT_LVL_LOW_STATUS0, BIT_MASK_1, pin, GPIO_INTR_CLEAR); return GpioOk; } -gpio_result_t gpio_intr_clear_stat_lvl_high (gpio_pin_number_t pin) +gpio_result_t gpio_intr_clear_stat_lvl_high (volatile gpio *gpio_perif, gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - select_gpio_domain(pin); gpio_perif->INTRPT_LVL_HIGH_STATUS0 = bitfield_write( gpio_perif->INTRPT_LVL_HIGH_STATUS0, BIT_MASK_1, pin, GPIO_INTR_CLEAR); return GpioOk; } -gpio_result_t gpio_intr_clear_stat (gpio_pin_number_t pin) +gpio_result_t gpio_intr_clear_stat (volatile gpio *gpio_perif, gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - select_gpio_domain(pin); gpio_perif->INTRPT_STATUS0 = bitfield_write( gpio_perif->INTRPT_STATUS0, BIT_MASK_1, pin, GPIO_INTR_CLEAR); return GpioOk; } -void gpio_intr_set_mode (gpio_pin_number_t pin, gpio_intr_general_mode_t mode) +void gpio_intr_set_mode (volatile gpio *gpio_perif, gpio_pin_number_t pin, gpio_intr_general_mode_t mode) { - select_gpio_domain(pin); gpio_perif->CFG = bitfield_write( gpio_perif->CFG, BIT_MASK_1, GPIO_CFG_INTR_MODE_INDEX, mode); } diff --git a/sw/device/lib/drivers/gpio/gpio.h b/sw/device/lib/drivers/gpio/gpio.h index 069d3a781..3d54ecacb 100644 --- a/sw/device/lib/drivers/gpio/gpio.h +++ b/sw/device/lib/drivers/gpio/gpio.h @@ -36,6 +36,7 @@ #include #include #include +#include "gpio_structs.h" /****************************************************************************/ /** **/ @@ -131,43 +132,24 @@ typedef struct gpio_cfg /** **/ /****************************************************************************/ -/** - * @brief Adds a handler function for a gpio interrupt to the handlers list. - * @param intr_id The interrupt ID of a gpio interrupt (from core_v_mini_mcu.h) - * @param handler A pointer to a function that will be called upon interrupt. - * @return The result of the operation - */ -gpio_result_t gpio_assign_irq_handler( uint32_t intr_id, - void *handler() ); - -/** - * @brief Resets all handlers to the dummy handler. - */ -void gpio_reset_handlers_list( ); - -/** - * @brief Attends the plic interrupt. - */ -void handler_irq_gpio( uint32_t id ); - /** * @brief gpio configuration. It first reset the pin configuration. * @param gpio_struct_t contatining pin, mode, en_input_sampling, en_intr, * intr_type * @return GpioOk: no problem, GpioError: there is an error. */ -gpio_result_t gpio_config (gpio_cfg_t cfg); +gpio_result_t gpio_config (volatile gpio *gpio_perif, gpio_cfg_t cfg); /** * @brief reset completely all the configurations set for the pin * @param gpio_pin_number_t specify pin number */ -gpio_result_t gpio_reset (gpio_pin_number_t pin); +gpio_result_t gpio_reset (volatile gpio *gpio_perif, gpio_pin_number_t pin); /** * @brief reset completely all the configurations for all the pins */ -gpio_result_t gpio_reset_all (void); +gpio_result_t gpio_reset_all (volatile gpio *gpio_perif); /** * @brief setting the a pins mode by writing in GPIO_MODE0 and GPIO_MODE1. @@ -175,87 +157,87 @@ gpio_result_t gpio_reset_all (void); * @param gpio_mode_t specify pin mode: 0 as input, 1 push-pull as output, * 2 as open_drain0, and 3 as open_drain1. */ -gpio_result_t gpio_set_mode (gpio_pin_number_t pin, gpio_mode_t mode); +gpio_result_t gpio_set_mode (volatile gpio *gpio_perif, gpio_pin_number_t pin, gpio_mode_t mode); /** * @brief enable sampling as input by writing one in GPIO_EN. If disables * (0) the corresponding GPIO will not sample the inputs (saves power) and * will not generate any interrupts. */ -gpio_result_t gpio_en_input_sampling (gpio_pin_number_t pin); +gpio_result_t gpio_en_input_sampling (volatile gpio *gpio_perif, gpio_pin_number_t pin); /** * @brief disable sampling as input by writing zero in GPIO_EN. */ -gpio_result_t gpio_dis_input_sampling (gpio_pin_number_t pin); +gpio_result_t gpio_dis_input_sampling (volatile gpio *gpio_perif, gpio_pin_number_t pin); /** * @brief reading from a gpio pin, which is done by reading from GPIO_IN reg * @param gpio_pin_number_t specify pin number * @return gpio value as GpioLow (false) or GpioHigh (true) */ -gpio_result_t gpio_read (gpio_pin_number_t pin, bool *val); +gpio_result_t gpio_read (volatile gpio *gpio_perif, gpio_pin_number_t pin, bool *val); /** * @brief toggle a pin. Using masking through GPIO_TOGGLE, and then * writing to GPIO_OUT * @param gpio_pin_number_t specify pin number */ -gpio_result_t gpio_toggle (gpio_pin_number_t pin); +gpio_result_t gpio_toggle (volatile gpio *gpio_perif, gpio_pin_number_t pin); /** * @brief write to a pin. using gpio_set and gpio_clear functions. * @param gpio_pin_number_t specify pin number */ -gpio_result_t gpio_write (gpio_pin_number_t pin, bool val); +gpio_result_t gpio_write (volatile gpio *gpio_perif, gpio_pin_number_t pin, bool val); /** * @brief enable rising edge interrupt for the given pin. * @param gpio_pin_number_t specify pin number */ -gpio_result_t gpio_intr_en_rise (gpio_pin_number_t pin); +gpio_result_t gpio_intr_en_rise (volatile gpio *gpio_perif, gpio_pin_number_t pin); /** * @brief disable rising edge interrupt for the given pin. * @param gpio_pin_number_t specify pin number */ -gpio_result_t gpio_intr_dis_rise (gpio_pin_number_t pin); +gpio_result_t gpio_intr_dis_rise (volatile gpio *gpio_perif, gpio_pin_number_t pin); /** * @brief enable falling edge interrupt for the given pin. * @param gpio_pin_number_t specify pin number */ -gpio_result_t gpio_intr_en_fall (gpio_pin_number_t pin); +gpio_result_t gpio_intr_en_fall (volatile gpio *gpio_perif, gpio_pin_number_t pin); /** * @brief disable falling edge interrupt for the given pin. * @param gpio_pin_number_t specify pin number */ -gpio_result_t gpio_intr_dis_fall (gpio_pin_number_t pin); +gpio_result_t gpio_intr_dis_fall (volatile gpio *gpio_perif, gpio_pin_number_t pin); /** * @brief enable logic-high level-sensitive interrupt for the given pin. * @param gpio_pin_number_t specify pin number */ -gpio_result_t gpio_intr_en_lvl_high (gpio_pin_number_t pin); +gpio_result_t gpio_intr_en_lvl_high (volatile gpio *gpio_perif, gpio_pin_number_t pin); /** * @brief disable logic-high level-sensitive interrupt for the given pin. * @param gpio_pin_number_t specify pin number */ -gpio_result_t gpio_intr_dis_lvl_high (gpio_pin_number_t pin); +gpio_result_t gpio_intr_dis_lvl_high (volatile gpio *gpio_perif, gpio_pin_number_t pin); /** * @brief enable logic-low level-sensitive interrupt for the given pin. * @param gpio_pin_number_t specify pin number */ -gpio_result_t gpio_intr_en_lvl_low (gpio_pin_number_t pin); +gpio_result_t gpio_intr_en_lvl_low (volatile gpio *gpio_perif, gpio_pin_number_t pin); /** * @brief disable logic-low level-sensitive interrupt for the given pin. * @param gpio_pin_number_t specify pin number */ -gpio_result_t gpio_intr_dis_lvl_low (gpio_pin_number_t pin); +gpio_result_t gpio_intr_dis_lvl_low (volatile gpio *gpio_perif, gpio_pin_number_t pin); /** * @brief enable the interrupt for the given pin. Type of interrupt @@ -263,83 +245,83 @@ gpio_result_t gpio_intr_dis_lvl_low (gpio_pin_number_t pin); * @param gpio_pin_number_t specify pin number * @param gpio_intr_type_t specify the type of the interrupt */ -gpio_result_t gpio_intr_en (gpio_pin_number_t pin, gpio_intr_type_t type); +gpio_result_t gpio_intr_en (volatile gpio *gpio_perif, gpio_pin_number_t pin, gpio_intr_type_t type); /** * @brief disable all the types of interrupt on the given pin. * @param gpio_pin_number_t specify pin number */ -gpio_result_t gpio_intr_dis_all (gpio_pin_number_t pin); +gpio_result_t gpio_intr_dis_all (volatile gpio *gpio_perif, gpio_pin_number_t pin); /** * @brief Each bit indicates if there is a pending rising-edge interrupt * on the corresponding GPIO. * @param gpio_pin_number_t specify pin number */ -gpio_result_t gpio_intr_check_stat_rise (gpio_pin_number_t pin, bool *is_pending); +gpio_result_t gpio_intr_check_stat_rise (volatile gpio *gpio_perif, gpio_pin_number_t pin, bool *is_pending); /** * @brief Each bit indicates if there is a pending falling-edge interrupt * on the corresponding GPIO. * @param gpio_pin_number_t specify pin number */ -gpio_result_t gpio_intr_check_stat_fall (gpio_pin_number_t pin, bool *is_pending); +gpio_result_t gpio_intr_check_stat_fall (volatile gpio *gpio_perif, gpio_pin_number_t pin, bool *is_pending); /** * @brief Each bit indicates if there is a pending low level-sensitive * interrupt on the corresponding GPIO. * @param gpio_pin_number_t specify pin number */ -gpio_result_t gpio_intr_check_stat_lvl_low (gpio_pin_number_t pin, bool *is_pending); +gpio_result_t gpio_intr_check_stat_lvl_low (volatile gpio *gpio_perif, gpio_pin_number_t pin, bool *is_pending); /** * @brief Each bit indicates if there is a pending high level-sensitive * interrupt on the corresponding GPIO. * @param gpio_pin_number_t specify pin number */ -gpio_result_t gpio_intr_check_stat_lvl_high (gpio_pin_number_t pin, bool *is_pending); +gpio_result_t gpio_intr_check_stat_lvl_high (volatile gpio *gpio_perif, gpio_pin_number_t pin, bool *is_pending); /** * @brief Each bit indicates if there is a pending interrupt on the * corresponding GPIO in any form (rise, fall, low level, and high level) * @param gpio_pin_number_t specify pin number */ -gpio_result_t gpio_intr_check_stat (gpio_pin_number_t pin, bool *is_pending); +gpio_result_t gpio_intr_check_stat (volatile gpio *gpio_perif, gpio_pin_number_t pin, bool *is_pending); /** * @brief Clearing interrupt rise status. Writing a 1 to a specific bit * clears the interrupt for the corresponding GPIO. * @param gpio_pin_number_t specify pin number */ -gpio_result_t gpio_intr_clear_stat_rise (gpio_pin_number_t pin); +gpio_result_t gpio_intr_clear_stat_rise (volatile gpio *gpio_perif, gpio_pin_number_t pin); /** * @brief Clearing interrupt fall status. Writing a 1 to a specific bit * clears the interrupt for the corresponding GPIO. * @param gpio_pin_number_t specify pin number */ -gpio_result_t gpio_intr_clear_stat_fall (gpio_pin_number_t pin); +gpio_result_t gpio_intr_clear_stat_fall (volatile gpio *gpio_perif, gpio_pin_number_t pin); /** * @brief Clearing interrupt low level-sensitive status. Writing a 1 to a * specific bit clears the interrupt for the corresponding GPIO. * @param gpio_pin_number_t specify pin number */ -gpio_result_t gpio_intr_clear_stat_lvl_low (gpio_pin_number_t pin); +gpio_result_t gpio_intr_clear_stat_lvl_low (volatile gpio *gpio_perif, gpio_pin_number_t pin); /** * @brief Clearing interrupt high level-sensitive status. Writing a 1 to a * specific bit clears the interrupt for the corresponding GPIO. * @param gpio_pin_number_t specify pin number */ -gpio_result_t gpio_intr_clear_stat_lvl_high (gpio_pin_number_t pin); +gpio_result_t gpio_intr_clear_stat_lvl_high (volatile gpio *gpio_perif, gpio_pin_number_t pin); /** * @brief Clearing interrupt status regardless of its type. Writing a 1 to * a specific bit clears the interrupt for the corresponding GPIO. * @param gpio_pin_number_t specify pin number */ -gpio_result_t gpio_intr_clear_stat (gpio_pin_number_t pin); +gpio_result_t gpio_intr_clear_stat (volatile gpio *gpio_perif, gpio_pin_number_t pin); /** * @brief Controls the interrupt mode of the gpios. @@ -347,7 +329,7 @@ gpio_result_t gpio_intr_clear_stat (gpio_pin_number_t pin); * interrupts for all GPIOs are cleared. If false, generate one cycle wide * pulses for every new interrupt. */ -void gpio_intr_set_mode (gpio_pin_number_t pin, gpio_intr_general_mode_t mode); +void gpio_intr_set_mode (volatile gpio *gpio_perif, gpio_pin_number_t pin, gpio_intr_general_mode_t mode); #endif // _GPIO_H_ /****************************************************************************/ diff --git a/sw/device/lib/drivers/i2c/i2c.c b/sw/device/lib/drivers/i2c/i2c.c index ef41d320a..7a760764a 100644 --- a/sw/device/lib/drivers/i2c/i2c.c +++ b/sw/device/lib/drivers/i2c/i2c.c @@ -625,8 +625,3 @@ i2c_result_t i2c_write_byte(const i2c_t *i2c, uint8_t byte, return i2c_write_byte_raw(i2c, byte, flags); } - -__attribute__((weak, optimize("O0"))) void handler_irq_i2c(uint32_t id) -{ - // Replace this function with a non-weak implementation -} \ No newline at end of file diff --git a/sw/device/lib/drivers/i2c/i2c.h b/sw/device/lib/drivers/i2c/i2c.h index 6c1706d9f..446ded987 100644 --- a/sw/device/lib/drivers/i2c/i2c.h +++ b/sw/device/lib/drivers/i2c/i2c.h @@ -604,11 +604,6 @@ i2c_result_t i2c_write_byte(const i2c_t *i2c, uint8_t byte, i2c_fmt_t code, bool suppress_nak_irq); -/** - * @brief Attends the plic interrupt. - */ -__attribute__((weak, optimize("O0"))) void handler_irq_i2c(uint32_t id); - #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/sw/device/lib/drivers/i2s/i2s.c b/sw/device/lib/drivers/i2s/i2s.c index 2c9975ef3..64cdaa48f 100644 --- a/sw/device/lib/drivers/i2s/i2s.c +++ b/sw/device/lib/drivers/i2s/i2s.c @@ -36,7 +36,6 @@ #include "i2s.h" -#include "i2s_structs.h" /****************************************************************************/ @@ -45,16 +44,11 @@ /** **/ /****************************************************************************/ -__attribute__((weak, optimize("O0"))) void handler_irq_i2s(uint32_t id) -{ - // Replace this function with a non-weak implementation -} - // i2s base functions -i2s_result_t i2s_init(uint16_t div_value, i2s_word_length_t word_length) +i2s_result_t i2s_init(volatile i2s * i2s_peri, uint16_t div_value, i2s_word_length_t word_length) { // already on ? - if (i2s_is_running()) { + if (i2s_is_running(i2s_peri)) { //printf("ERROR: [I2S HAL] I2S peripheral already running"); return kI2sError; } @@ -74,7 +68,7 @@ i2s_result_t i2s_init(uint16_t div_value, i2s_word_length_t word_length) i2s_peri->CONTROL = control; // wait for I2S clock domain to acknowledge startup - while (! i2s_is_running()) ; + while (! i2s_is_running(i2s_peri)) ; control |= (1 << I2S_CONTROL_EN_WS_BIT); // enable WS gen i2s_peri->CONTROL = control; @@ -82,7 +76,7 @@ i2s_result_t i2s_init(uint16_t div_value, i2s_word_length_t word_length) return kI2sOk; } -void i2s_terminate(void) +void i2s_terminate(volatile i2s * i2s_peri) { i2s_peri->CONTROL &= ~( (1 << I2S_CONTROL_EN_WS_BIT) // disable WS gen @@ -91,7 +85,7 @@ void i2s_terminate(void) ); } -bool i2s_is_running(void) +bool i2s_is_running(volatile i2s * i2s_peri) { // check "running" bit in the STATUS register return (i2s_peri->STATUS & (1 << I2S_STATUS_RUNNING_BIT)); @@ -101,19 +95,19 @@ bool i2s_is_running(void) // RX Channel // -i2s_result_t i2s_rx_start(i2s_channel_sel_t channels) +i2s_result_t i2s_rx_start(volatile i2s * i2s_peri, i2s_channel_sel_t channels) { - if (! i2s_is_running()) { + if (! i2s_is_running(i2s_peri)) { //printf("ERROR: [I2S HAL] I2S peripheral not running"); return kI2sErrUninit; } if (channels == I2S_DISABLE) { // no channels selected -> disable - return i2s_rx_stop(); + return i2s_rx_stop(i2s_peri); } - if (i2s_rx_overflow()) { + if (i2s_rx_overflow(i2s_peri)) { return kI2sOverflow; } @@ -131,14 +125,14 @@ i2s_result_t i2s_rx_start(i2s_channel_sel_t channels) return kI2sOk; } -i2s_result_t i2s_rx_stop(void) +i2s_result_t i2s_rx_stop(volatile i2s * i2s_peri) { - if (! i2s_is_running()) { + if (! i2s_is_running(i2s_peri)) { //printf("ERROR: [I2S HAL] I2S peripheral not running"); return kI2sErrUninit; } - bool overflow = i2s_rx_overflow(); + bool overflow = i2s_rx_overflow(i2s_peri); // disable rx channel uint32_t control = i2s_peri->CONTROL; @@ -150,7 +144,7 @@ i2s_result_t i2s_rx_stop(void) i2s_peri->CONTROL = control | (1 << I2S_CONTROL_RESET_RX_OVERFLOW_BIT); // overflow bit is going to be reset by rx channel if the sck is running - while (i2s_rx_overflow()) ; // wait for one SCK rise - this might take some time as the SCK can be much slower + while (i2s_rx_overflow(i2s_peri)) ; // wait for one SCK rise - this might take some time as the SCK can be much slower // disable WATERMARK counter i2s_peri->CONTROL = control & ~(1 << I2S_CONTROL_EN_WATERMARK_BIT); @@ -159,7 +153,7 @@ i2s_result_t i2s_rx_stop(void) // note: this uses much less resources for (int i = 0; i < 6; i++) { // 4 FIFO + 2 spill registers - i2s_rx_read_data(); // read to empty FIFO + i2s_rx_read_data(i2s_peri); // read to empty FIFO } i2s_peri->CONTROL = control; // reset control register @@ -169,19 +163,19 @@ i2s_result_t i2s_rx_stop(void) } -bool i2s_rx_data_available(void) +bool i2s_rx_data_available(volatile i2s * i2s_peri) { // read data ready bit from STATUS register return (i2s_peri->STATUS & (1 << I2S_STATUS_RX_DATA_READY_BIT)); } -uint32_t i2s_rx_read_data(void) +uint32_t i2s_rx_read_data(volatile i2s * i2s_peri) { // read RXDATA register return i2s_peri->RXDATA; } -bool i2s_rx_overflow(void) +bool i2s_rx_overflow(volatile i2s * i2s_peri) { // read overflow bit from STATUS register return (i2s_peri->STATUS & (1 << I2S_STATUS_RX_OVERFLOW_BIT)); @@ -191,7 +185,7 @@ bool i2s_rx_overflow(void) // // RX Watermark // -void i2s_rx_enable_watermark(uint16_t watermark, bool interrupt_en) +void i2s_rx_enable_watermark(volatile i2s * i2s_peri, uint16_t watermark, bool interrupt_en) { // set watermark (= max of counter) triggers an interrupt if enabled i2s_peri->WATERMARK = watermark; @@ -204,7 +198,7 @@ void i2s_rx_enable_watermark(uint16_t watermark, bool interrupt_en) i2s_peri->CONTROL = control; } -void i2s_rx_disable_watermark(void) +void i2s_rx_disable_watermark(volatile i2s * i2s_peri) { // disable interrupt and disable watermark counter i2s_peri->CONTROL &= ~( @@ -213,13 +207,13 @@ void i2s_rx_disable_watermark(void) ); } -uint16_t i2s_rx_read_waterlevel(void) +uint16_t i2s_rx_read_waterlevel(volatile i2s * i2s_peri) { // read WATERLEVEL register return (uint16_t) i2s_peri->WATERLEVEL; } -void i2s_rx_reset_waterlevel(void) +void i2s_rx_reset_waterlevel(volatile i2s * i2s_peri) { // set "reset watermark" bit in CONTROL register i2s_peri->CONTROL |= (1 << I2S_CONTROL_RESET_WATERMARK_BIT); diff --git a/sw/device/lib/drivers/i2s/i2s.h b/sw/device/lib/drivers/i2s/i2s.h index 4dcfbf0e6..bdcd68b7f 100644 --- a/sw/device/lib/drivers/i2s/i2s.h +++ b/sw/device/lib/drivers/i2s/i2s.h @@ -33,7 +33,7 @@ /** * Address of the I2S data of the read channel to be passed as address to the DMA */ -#define I2S_RX_DATA_ADDRESS (uint32_t)(I2S_RXDATA_REG_OFFSET+I2S_START_ADDRESS) +#define I2S_RX_DATA_ADDRESS(base) (uint32_t)(I2S_RXDATA_REG_OFFSET+(base)) /****************************************************************************/ @@ -48,6 +48,7 @@ #include "bitfield.h" #include "i2s_regs.h" +#include "i2s_structs.h" #ifdef __cplusplus @@ -107,10 +108,6 @@ typedef enum i2s_channel_sel { /** **/ /****************************************************************************/ -/** - * @brief Attends the plic interrupt. - */ -__attribute__((weak, optimize("O0"))) void handler_irq_i2s(uint32_t id); /** * Initialize I2S peripheral @@ -128,7 +125,7 @@ __attribute__((weak, optimize("O0"))) void handler_irq_i2s(uint32_t id); * @return kI2sOk initialized successful * @return kI2sError if peripheral was already running */ -i2s_result_t i2s_init(uint16_t div_value, i2s_word_length_t word_length); +i2s_result_t i2s_init(volatile i2s * i2s_peri, uint16_t div_value, i2s_word_length_t word_length); /** * Terminate I2S peripheral @@ -136,7 +133,7 @@ i2s_result_t i2s_init(uint16_t div_value, i2s_word_length_t word_length); * * Stops SCK and WS */ -void i2s_terminate(void); +void i2s_terminate(volatile i2s * i2s_peri); /** @@ -144,7 +141,7 @@ void i2s_terminate(void); * * @return true if i2s peripheral enable */ -bool i2s_is_running(void); +bool i2s_is_running(volatile i2s * i2s_peri); // @@ -163,7 +160,7 @@ bool i2s_is_running(void); * @return kI2sErrUninit error peripheral was not initialized * @return kI2sOverflow indicates overflow. (to clear call i2s_rx_stop()) */ -i2s_result_t i2s_rx_start(i2s_channel_sel_t channels); +i2s_result_t i2s_rx_start(volatile i2s * i2s_peri, i2s_channel_sel_t channels); /** * I2S stop rx channels and cleans overflow @@ -174,7 +171,7 @@ i2s_result_t i2s_rx_start(i2s_channel_sel_t channels); * @return kI2sErrUninit error peripheral was not initialized * @return kI2sOverflow the RX-FIFO overflowed since the RX has been started. */ -i2s_result_t i2s_rx_stop(void); +i2s_result_t i2s_rx_stop(volatile i2s * i2s_peri); /** @@ -182,7 +179,7 @@ i2s_result_t i2s_rx_stop(void); * * @return true if RX data is available */ -bool i2s_rx_data_available(void); +bool i2s_rx_data_available(volatile i2s * i2s_peri); /** * I2S read RX word @@ -191,7 +188,7 @@ bool i2s_rx_data_available(void); * * @return uint32_t RX word */ -uint32_t i2s_rx_read_data(void); +uint32_t i2s_rx_read_data(volatile i2s * i2s_peri); /** * I2S check RX FIFO overflow @@ -205,7 +202,7 @@ uint32_t i2s_rx_read_data(void); * @return true if RX FIFO overflowed * @return false */ -bool i2s_rx_overflow(void); +bool i2s_rx_overflow(volatile i2s * i2s_peri); @@ -217,12 +214,12 @@ bool i2s_rx_overflow(void); * @param watermark number to trigger interrupt * @param interrupt_en enable/disable interrupt */ -void i2s_rx_enable_watermark(uint16_t watermark, bool interrupt_en); +void i2s_rx_enable_watermark(volatile i2s * i2s_peri, uint16_t watermark, bool interrupt_en); /** * I2S disable watermark counter */ -void i2s_rx_disable_watermark(void); +void i2s_rx_disable_watermark(volatile i2s * i2s_peri); /** @@ -230,14 +227,14 @@ void i2s_rx_disable_watermark(void); * * @return uint16_t current counter value */ -uint16_t i2s_rx_read_waterlevel(void); +uint16_t i2s_rx_read_waterlevel(volatile i2s * i2s_peri); /** * I2S reset RX Watermark counter to 0 * */ -void i2s_rx_reset_waterlevel(void); +void i2s_rx_reset_waterlevel(volatile i2s * i2s_peri); #ifdef __cplusplus diff --git a/sw/device/lib/drivers/power_manager/data/power_manager.h.tpl b/sw/device/lib/drivers/power_manager/data/power_manager.h.tpl index 52215d273..d194d8c87 100644 --- a/sw/device/lib/drivers/power_manager/data/power_manager.h.tpl +++ b/sw/device/lib/drivers/power_manager/data/power_manager.h.tpl @@ -34,31 +34,27 @@ typedef enum power_manager_sel_state { kRetOn_e = 2, kRetOff_e = 3, } power_manager_sel_state_t; - +<% + intr_sources = xheep.get_rh().use_target_as_sv_multi("fast_irq_target", xheep.get_mcu_node()) + intrs = [] + for i, intr_s in enumerate(intr_sources): + ep = xheep.get_rh().get_source_ep_copy(intr_s.split(".")[-1]) + intrs.append(ep.handler) +%> /** * Interrupt source. */ typedef enum power_manager_sel_intr { - kTimer_0_pm_e = 0, - kPlic_pm_e = 1, - kTimer_1_pm_e = 2, - kTimer_2_pm_e = 3, - kTimer_3_pm_e = 4, - kDma_pm_e = 5, - kSpi_pm_e = 6, - kSpiFlash_pm_e = 7, - kGpio_0_pm_e = 8, - kGpio_1_pm_e = 9, - kGpio_2_pm_e = 10, - kGpio_3_pm_e = 11, - kGpio_4_pm_e = 12, - kGpio_5_pm_e = 13, - kGpio_6_pm_e = 14, - kGpio_7_pm_e = 15, - kExt_0_pm_e = 16, - kExt_1_pm_e = 17, - kExt_2_pm_e = 18, - kExt_3_pm_e = 19, + kRv_Timer_0_pm_e = 0, + kPlic_pm_e = 1, +% for i, intr in enumerate(intrs): +% if intr != "": + k${intr[len("fic_irq_"):].title()}_pm_e = ${i+2}, +% endif +% endfor +% for i in range(min(15, xheep.get_ext_intr())): + kExt_${i}_pm_e = ${17+i}, +% endfor } power_manager_sel_intr_t; /** diff --git a/sw/device/lib/drivers/rv_plic/rv_plic.c b/sw/device/lib/drivers/rv_plic/rv_plic.c index ffbb822df..c47c7a37c 100644 --- a/sw/device/lib/drivers/rv_plic/rv_plic.c +++ b/sw/device/lib/drivers/rv_plic/rv_plic.c @@ -36,7 +36,6 @@ /****************************************************************************/ #include "rv_plic.h" -#include "rv_plic_structs.h" #include #include "bitfield.h" #include "rv_plic_regs.h" // Generated. @@ -62,16 +61,6 @@ const uint32_t plicMinPriority = 0; const uint32_t plicMaxPriority = RV_PLIC_PRIO0_PRIO0_MASK; -/****************************************************************************/ -/** **/ -/* TYPEDEFS AND STRUCTURES */ -/** **/ -/****************************************************************************/ - -/** - * Pointer used to dynamically access the different interrupt handlers. -*/ -typedef void (*handler_funct_t)(uint32_t); /****************************************************************************/ /** **/ @@ -103,11 +92,6 @@ static ptrdiff_t plic_offset_from_reg0( uint32_t irq); */ static uint8_t plic_irq_bit_index( uint32_t irq); -/** - * @brief A dummy function to prevent unassigned irq to access a null pointer. - */ -__attribute__((optimize("O0"))) static void handler_irq_dummy( uint32_t dummy ); - /****************************************************************************/ /** **/ @@ -121,13 +105,7 @@ __attribute__((optimize("O0"))) static void handler_irq_dummy( uint32_t dummy ); /** **/ /****************************************************************************/ -/** - * Array for the ISRs. Length automatically generated when compiling and - * assigned to QTY_INTR. - * Each element will be initialized to be the address of the handler function - * relative to its index. So each element will be a callable function. -*/ -handler_funct_t handlers[QTY_INTR]; + /****************************************************************************/ /** **/ @@ -137,12 +115,14 @@ handler_funct_t handlers[QTY_INTR]; void handler_irq_external(void) { +#ifdef RV_PLIC_0_IS_INCLUDED uint32_t int_id = NULL_INTR; - plic_result_t res = plic_irq_claim(&int_id); + plic_result_t res = plic_irq_claim(&rv_plic_0_inf ,&int_id); - // Calls the proper handler - handlers[int_id](int_id); - plic_irq_complete(&int_id); + // Calls the proper handler + rv_plic_0_inf.handlers[int_id](int_id); + plic_irq_complete(&rv_plic_0_inf, &int_id); +#endif } /*! @@ -151,50 +131,50 @@ void handler_irq_external(void) It writes the default value 0 in them and read back the value into the proper register struct */ -plic_result_t plic_Init(void) +plic_result_t plic_Init(rv_plic_inf_t *inf) { /* Clears all the Level/Edge registers */ for(uint8_t i=0; iLE0)[i] = 0; + (&inf->rv_plic_peri->LE0)[i] = 0; } /* Clears all the priority registers */ for(uint8_t i=0; iPRIO0)[i] = 0; + (&inf->rv_plic_peri->PRIO0)[i] = 0; } /* Clears the Interrupt Enable registers */ for(uint8_t i=0; iIE00)[i] = 0; + (&inf->rv_plic_peri->IE00)[i] = 0; } /* Clears all the threshold registers */ - rv_plic_peri->THRESHOLD0 = 0; - if(rv_plic_peri->THRESHOLD0 != 0) + inf->rv_plic_peri->THRESHOLD0 = 0; + if(inf->rv_plic_peri->THRESHOLD0 != 0) { return kPlicError; } /* clears software interrupts registers */ - rv_plic_peri->MSIP0 = 0; - if(rv_plic_peri->MSIP0 != 0) + inf->rv_plic_peri->MSIP0 = 0; + if(inf->rv_plic_peri->MSIP0 != 0) { return kPlicError; } /* Fill the handlers array with the fixed peripherals. */ - plic_reset_handlers_list(); + plic_reset_handlers_list(inf); return kPlicOk; } -plic_result_t plic_irq_set_enabled( uint32_t irq, +plic_result_t plic_irq_set_enabled(rv_plic_inf_t *inf, uint32_t irq, plic_toggle_t state) { if(irq >= RV_PLIC_PARAM_NUM_SRC) @@ -216,7 +196,7 @@ plic_result_t plic_irq_set_enabled( uint32_t irq, // Writes `state` in the amount of bits defined by the mask // at position `bit_index` inside the proper Interrupt Enable register - (&rv_plic_peri->IE00)[offset] = bitfield_write((&rv_plic_peri->IE00)[offset], + (&inf->rv_plic_peri->IE00)[offset] = bitfield_write((&inf->rv_plic_peri->IE00)[offset], BIT_MASK_1, bit_index, state); @@ -225,7 +205,7 @@ plic_result_t plic_irq_set_enabled( uint32_t irq, } -plic_result_t plic_irq_get_enabled( uint32_t irq, +plic_result_t plic_irq_get_enabled(rv_plic_inf_t *inf, uint32_t irq, plic_toggle_t *state) { if(irq >= RV_PLIC_PARAM_NUM_SRC) @@ -240,14 +220,14 @@ plic_result_t plic_irq_get_enabled( uint32_t irq, uint16_t bit_index = plic_irq_bit_index(irq); // Reads the enabled/disabled bit - *state = bitfield_read((&rv_plic_peri->IE00)[offset], BIT_MASK_1, bit_index); + *state = bitfield_read((&inf->rv_plic_peri->IE00)[offset], BIT_MASK_1, bit_index); return kPlicOk; } -plic_result_t plic_irq_set_trigger( uint32_t irq, +plic_result_t plic_irq_set_trigger(rv_plic_inf_t *inf, uint32_t irq, plic_irq_trigger_t trigger) { if(irq >= RV_PLIC_PARAM_NUM_SRC) @@ -262,7 +242,7 @@ plic_result_t plic_irq_set_trigger( uint32_t irq, uint16_t bit_index = plic_irq_bit_index(irq); // Updated the register with the new bit - (&rv_plic_peri->LE0)[offset] = bitfield_write((&rv_plic_peri->LE0)[offset], + (&inf->rv_plic_peri->LE0)[offset] = bitfield_write((&inf->rv_plic_peri->LE0)[offset], BIT_MASK_1, bit_index, trigger); @@ -272,7 +252,7 @@ plic_result_t plic_irq_set_trigger( uint32_t irq, } -plic_result_t plic_irq_set_priority( uint32_t irq, uint32_t priority) +plic_result_t plic_irq_set_priority(rv_plic_inf_t *inf, uint32_t irq, uint32_t priority) { if(irq >= RV_PLIC_PARAM_NUM_SRC || priority > plicMaxPriority) { @@ -280,27 +260,27 @@ plic_result_t plic_irq_set_priority( uint32_t irq, uint32_t priority) } // Writes the new priority into the proper register - (&rv_plic_peri->PRIO0)[irq] = priority; + (&inf->rv_plic_peri->PRIO0)[irq] = priority; return kPlicOk; } -plic_result_t plic_target_set_threshold(uint32_t threshold) +plic_result_t plic_target_set_threshold(rv_plic_inf_t *inf, uint32_t threshold) { if(threshold > plicMaxPriority) { return kPlicBadArg; } - rv_plic_peri->THRESHOLD0 = threshold; + inf->rv_plic_peri->THRESHOLD0 = threshold; return kPlicOk; } -plic_result_t plic_irq_is_pending( uint32_t irq, +plic_result_t plic_irq_is_pending(rv_plic_inf_t *inf, uint32_t irq, bool *is_pending) { if(irq >= RV_PLIC_PARAM_NUM_SRC || is_pending == NULL) @@ -314,26 +294,26 @@ plic_result_t plic_irq_is_pending( uint32_t irq, // Get the destination bit in which to write uint16_t bit_index = plic_irq_bit_index(irq); - *is_pending = bitfield_read((&rv_plic_peri->IP0)[offset], BIT_MASK_1, bit_index); + *is_pending = bitfield_read((&inf->rv_plic_peri->IP0)[offset], BIT_MASK_1, bit_index); return kPlicOk; } -plic_result_t plic_irq_claim( uint32_t *claim_data) +plic_result_t plic_irq_claim(rv_plic_inf_t *inf, uint32_t *claim_data) { if (claim_data == NULL) { return kPlicBadArg; } - *claim_data = rv_plic_peri->CC0; + *claim_data = inf->rv_plic_peri->CC0; return kPlicOk; } -plic_result_t plic_irq_complete(const uint32_t *complete_data) +plic_result_t plic_irq_complete(rv_plic_inf_t *inf, const uint32_t *complete_data) { if (complete_data == NULL) { @@ -342,46 +322,45 @@ plic_result_t plic_irq_complete(const uint32_t *complete_data) // Write back the claimed IRQ ID to the target specific CC register, // to notify the PLIC of the IRQ completion. - rv_plic_peri->CC0 = *complete_data; + inf->rv_plic_peri->CC0 = *complete_data; return kPlicOk; } -void plic_software_irq_force(void) +void plic_software_irq_force(rv_plic_inf_t *inf) { - rv_plic_peri->MSIP0 = 1; + inf->rv_plic_peri->MSIP0 = 1; } -void plic_software_irq_acknowledge(void) +void plic_software_irq_acknowledge(rv_plic_inf_t *inf) { - rv_plic_peri->MSIP0 = 0; + inf->rv_plic_peri->MSIP0 = 0; } -plic_result_t plic_software_irq_is_pending(void) +plic_result_t plic_software_irq_is_pending(rv_plic_inf_t *inf) { - return rv_plic_peri->MSIP0; + return inf->rv_plic_peri->MSIP0; } -plic_result_t plic_assign_external_irq_handler( uint32_t id, - void *handler ) +plic_result_t plic_assign_irq_handler(rv_plic_inf_t *inf, uint32_t id, rv_plic_handler_funct_t handler ) { - if( id >= EXT_IRQ_START && id <= QTY_INTR ) + if( id < QTY_INTR_PLIC ) { - handlers[ id ] = (handler_funct_t) handler; + inf->handlers[ id ] = handler; return kPlicOk; } return kPlicBadArg; } -void plic_reset_handlers_list(void) +void plic_reset_handlers_list(rv_plic_inf_t *inf) { - handlers[NULL_INTR] = &handler_irq_dummy; - - for( uint8_t i = NULL_INTR +1; i < QTY_INTR; i++ ) + memcpy(inf->handlers, inf->default_handlers, sizeof(inf->handlers)); + /* + for( uint8_t i = NULL_INTR +1; i < QTY_INTR_PLIC; i++ ) { if ( i <= UART_ID_END) { @@ -411,7 +390,7 @@ void plic_reset_handlers_list(void) { handlers[i] = &handler_irq_dummy; } - } + }*/ } /****************************************************************************/ @@ -420,9 +399,6 @@ void plic_reset_handlers_list(void) /** **/ /****************************************************************************/ -__attribute__((optimize("O0"))) static void handler_irq_dummy( uint32_t dummy ) -{ -} static ptrdiff_t plic_offset_from_reg0( uint32_t irq) { diff --git a/sw/device/lib/drivers/rv_plic/rv_plic.h b/sw/device/lib/drivers/rv_plic/rv_plic.h index ed2753e12..523d10c35 100644 --- a/sw/device/lib/drivers/rv_plic/rv_plic.h +++ b/sw/device/lib/drivers/rv_plic/rv_plic.h @@ -43,48 +43,7 @@ #include "mmio.h" #include "macros.h" - - -/****************************************************************************/ -/** **/ -/* DEFINITIONS AND MACROS */ -/** **/ -/****************************************************************************/ - -/** - * Start and end ID of the UART interrupt request lines -*/ -#define UART_ID_END UART_INTR_RX_PARITY_ERR - -/** - * Start and end ID of the GPIO interrupt request lines -*/ -#define GPIO_ID_END GPIO_INTR_31 - -/** - * Start and end ID of the I2C interrupt request lines -*/ -#define I2C_ID_END INTR_HOST_TIMEOUT - -/** - * ID of the SPI interrupt request line -*/ -#define SPI_ID SPI2_INTR_EVENT - -/** - * ID of the I2S interrupt request lines - */ -#define I2S_ID I2S_INTR_EVENT - -/** - * ID of the DMA interrupt request line -*/ -#define DMA_ID DMA_WINDOW_INTR - -/** - * ID of the external interrupt request lines -*/ -#define EXT_IRQ_START EXT_INTR_0 +#include "rv_plic_structs.h" /****************************************************************************/ /** **/ @@ -159,6 +118,28 @@ typedef enum plic_irq_trigger { kPlicIrqTriggerEdge } plic_irq_trigger_t; +#define QTY_INTR_PLIC 64 +/** + * Pointer used to dynamically access the different interrupt handlers. +*/ +typedef void (*rv_plic_handler_funct_t)(uint32_t); + +/** + * Colletions of information about one plic and it's runtime components. + */ +typedef struct { + RV_PLIC* rv_plic_peri; + + /** + * Array for the ISRs. + * Each element will be initialized to be the address of the handler function + * relative to its index. So each element will be a callable function. + */ + rv_plic_handler_funct_t handlers[QTY_INTR_PLIC]; + rv_plic_handler_funct_t default_handlers[QTY_INTR_PLIC]; +} rv_plic_inf_t; + +#include "rv_plic_gen.h" /****************************************************************************/ /** **/ @@ -183,7 +164,7 @@ void handler_irq_external(void); * * @return The result of the operation. */ -plic_result_t plic_Init(void); +plic_result_t plic_Init(rv_plic_inf_t *inf); /** @@ -200,7 +181,7 @@ plic_result_t plic_Init(void); * @param state The new toggle state for the interrupt * @return The result of the operation */ -plic_result_t plic_irq_set_enabled( uint32_t irq, +plic_result_t plic_irq_set_enabled(rv_plic_inf_t *inf, uint32_t irq, plic_toggle_t state); @@ -218,7 +199,7 @@ plic_result_t plic_irq_set_enabled( uint32_t irq, * @param state The toggle state of the interrupt, as read from the IE registers * @return The result of the operation */ -plic_result_t plic_irq_get_enabled( uint32_t irq, +plic_result_t plic_irq_get_enabled(rv_plic_inf_t *inf, uint32_t irq, plic_toggle_t *state); /** @@ -234,7 +215,7 @@ plic_result_t plic_irq_get_enabled( uint32_t irq, * @result The result of the operation * */ -plic_result_t plic_irq_set_trigger( uint32_t irq, +plic_result_t plic_irq_set_trigger(rv_plic_inf_t *inf, uint32_t irq, plic_irq_trigger_t trigger); /** @@ -244,7 +225,7 @@ plic_result_t plic_irq_set_trigger( uint32_t irq, * @param priority A priority value to set * @return The result of the operation */ -plic_result_t plic_irq_set_priority( uint32_t irq, +plic_result_t plic_irq_set_priority(rv_plic_inf_t *inf, uint32_t irq, uint32_t priority); /** @@ -257,7 +238,7 @@ plic_result_t plic_irq_set_priority( uint32_t irq, * @param threshold The threshold value to be set * @return The result of the operation */ -plic_result_t plic_target_set_threshold(uint32_t threshold); +plic_result_t plic_target_set_threshold(rv_plic_inf_t *inf, uint32_t threshold); /** * Returns whether a particular interrupt is currently pending. @@ -265,7 +246,7 @@ plic_result_t plic_target_set_threshold(uint32_t threshold); * @param irq An interrupt source identification * @param[out] is_pending Boolean flagcorresponding to whether an interrupt is pending or not */ -plic_result_t plic_irq_is_pending( uint32_t irq, +plic_result_t plic_irq_is_pending(rv_plic_inf_t *inf, uint32_t irq, bool *is_pending); /** @@ -287,7 +268,7 @@ plic_result_t plic_irq_is_pending( uint32_t irq, * @param[out] claim_data Data that describes the origin of the IRQ. * @return The result of the operation. */ -plic_result_t plic_irq_claim( uint32_t *claim_data); +plic_result_t plic_irq_claim(rv_plic_inf_t *inf, uint32_t *claim_data); /** * Completes the claimed interrupt request. @@ -303,7 +284,7 @@ plic_result_t plic_irq_claim( uint32_t *claim_data); * PLIC of the IRQ servicing completion. * @return The result of the operation */ -plic_result_t plic_irq_complete(const uint32_t *complete_data ); +plic_result_t plic_irq_complete(rv_plic_inf_t *inf, const uint32_t *complete_data ); /** @@ -317,7 +298,7 @@ plic_result_t plic_irq_complete(const uint32_t *complete_data ); * * @return The result of the operation */ -void plic_software_irq_force(void); +void plic_software_irq_force(rv_plic_inf_t *inf); /** @@ -329,29 +310,28 @@ void plic_software_irq_force(void); * * @return The result of the operation */ -void plic_software_irq_acknowledge(void); +void plic_software_irq_acknowledge(rv_plic_inf_t *inf); /** * Returns software interrupt pending state * * @return The result of the operation */ -plic_result_t plic_software_irq_is_pending(void); +plic_result_t plic_software_irq_is_pending(rv_plic_inf_t *inf); /** - * Adds a handler function for an external interrupt to the handlers list. - * @param id The interrupt ID of an external interrupt (from core_v_mini_mcu.h) + * Adds a handler function for an interrupt to the handlers list. + * @param id The interrupt ID of an interrupt (from core_v_mini_mcu.h) * @param handler A pointer to a function that will be called upon interrupt. * @return The result of the operation */ -plic_result_t plic_assign_external_irq_handler( uint32_t id, - void *handler ); +plic_result_t plic_assign_irq_handler(rv_plic_inf_t *inf, uint32_t id, rv_plic_handler_funct_t handler ); /** * Resets all peripheral handlers to their pre-set ones. All external handlers * are re-set to the dummy handler. */ -void plic_reset_handlers_list(void); +void plic_reset_handlers_list(rv_plic_inf_t *inf); #endif /* _RV_PLIC_H_ */ diff --git a/sw/device/lib/drivers/rv_plic/rv_plic_gen.c.tpl b/sw/device/lib/drivers/rv_plic/rv_plic_gen.c.tpl new file mode 100644 index 000000000..139816cce --- /dev/null +++ b/sw/device/lib/drivers/rv_plic/rv_plic_gen.c.tpl @@ -0,0 +1,28 @@ +#include "rv_plic.h" + +<% + from x_heep_gen.peripherals.rv_plic import RvPlicPeripheral + handlers = set() + for domain in xheep.iter_peripheral_domains(): + for periph in domain.iter_peripherals(): + if isinstance(periph, RvPlicPeripheral): + handlers = handlers.union(periph.make_handler_set(xheep.get_rh())) +%> + + +% for domain in xheep.iter_peripheral_domains(): +% for periph in domain.iter_peripherals(): +% if isinstance(periph, RvPlicPeripheral): +extern rv_plic_inf_t ${periph.full_name}_inf = { + .rv_plic_peri = ${periph.full_name}_peri, + .default_handlers = {${periph.make_handler_array(xheep.get_rh())}} +}; + +% endif +% endfor +% endfor + + +% for handler in handlers: +__attribute__((weak, optimize("O0"))) void ${handler}(uint32_t id) {} +% endfor diff --git a/sw/device/lib/drivers/rv_plic/rv_plic_gen.h.tpl b/sw/device/lib/drivers/rv_plic/rv_plic_gen.h.tpl new file mode 100644 index 000000000..94b1f939f --- /dev/null +++ b/sw/device/lib/drivers/rv_plic/rv_plic_gen.h.tpl @@ -0,0 +1,26 @@ +#ifndef _RV_PLIC_GEN_H_ +#define _RV_PLIC_GEN_H_ + +#include "rv_plic.h" +<% + from x_heep_gen.peripherals.rv_plic import RvPlicPeripheral + handlers = set() + for domain in xheep.iter_peripheral_domains(): + for periph in domain.iter_peripherals(): + if isinstance(periph, RvPlicPeripheral): + handlers = handlers.union(periph.make_handler_set(xheep.get_rh())) +%> + +% for handler in handlers: +void ${handler}(uint32_t id); +% endfor + +% for domain in xheep.iter_peripheral_domains(): +% for periph in domain.iter_peripherals(): +% if isinstance(periph, RvPlicPeripheral): +extern rv_plic_inf_t ${periph.full_name}_inf; +% endif +% endfor +% endfor + +#endif \ No newline at end of file diff --git a/sw/device/lib/drivers/spi_host/spi_host.c b/sw/device/lib/drivers/spi_host/spi_host.c index 3312b8cd2..c53adf681 100644 --- a/sw/device/lib/drivers/spi_host/spi_host.c +++ b/sw/device/lib/drivers/spi_host/spi_host.c @@ -120,8 +120,3 @@ void spi_output_enable(const spi_host_t *spi, bool enable){ output_enable_reg = bitfield_bit32_write(output_enable_reg, SPI_HOST_CONTROL_OUTPUT_EN_BIT, enable); mmio_region_write32(spi->base_addr, SPI_HOST_CONTROL_REG_OFFSET, output_enable_reg); } - -__attribute__((weak, optimize("O0"))) void handler_irq_spi(uint32_t id) -{ - // Replace this function with a non-weak implementation -} \ No newline at end of file diff --git a/sw/device/lib/drivers/spi_host/spi_host.h b/sw/device/lib/drivers/spi_host/spi_host.h index af81fe21b..ced77160d 100644 --- a/sw/device/lib/drivers/spi_host/spi_host.h +++ b/sw/device/lib/drivers/spi_host/spi_host.h @@ -351,11 +351,6 @@ static inline __attribute__((always_inline)) __attribute__((const)) uint32_t spi return cmd_reg; } -/** - * @brief Attends the plic interrupt. - */ -__attribute__((weak, optimize("O0"))) void handler_irq_spi(uint32_t id); - #ifdef __cplusplus } diff --git a/sw/device/lib/drivers/template.tpl b/sw/device/lib/drivers/template.tpl index 70f1bdb78..7162644d9 100644 --- a/sw/device/lib/drivers/template.tpl +++ b/sw/device/lib/drivers/template.tpl @@ -26,7 +26,7 @@ */ #ifndef _${peripheral_name_upper}_STRUCTS_H -#define ${peripheral_name_upper}_STRUCTS +#define _${peripheral_name_upper}_STRUCTS_H /****************************************************************************/ /** **/ @@ -43,8 +43,7 @@ /** **/ /****************************************************************************/ -#define ${start_address_define} - +${start_address_define} /****************************************************************************/ /** **/ /** TYPEDEFS AND STRUCTURES **/ diff --git a/sw/device/lib/drivers/uart/uart.c b/sw/device/lib/drivers/uart/uart.c index 08a32fa7f..d98b7dab7 100644 --- a/sw/device/lib/drivers/uart/uart.c +++ b/sw/device/lib/drivers/uart/uart.c @@ -143,8 +143,3 @@ size_t uart_read(const uart_t *uart, const uint8_t *data, size_t len) { size_t uart_sink(void *uart, const char *data, size_t len) { return uart_write((const uart_t *)uart, (const uint8_t *)data, len); } - -__attribute__((weak, optimize("O0"))) void handler_irq_uart(uint32_t id) -{ - // Replace this function with a non-weak implementation -} \ No newline at end of file diff --git a/sw/device/lib/drivers/uart/uart.h b/sw/device/lib/drivers/uart/uart.h index c780ca731..4545407b9 100644 --- a/sw/device/lib/drivers/uart/uart.h +++ b/sw/device/lib/drivers/uart/uart.h @@ -84,11 +84,6 @@ size_t uart_read(const uart_t *uart, const uint8_t *data, size_t len); size_t uart_sink(void *uart, const char *data, size_t len); -/** - * @brief Attends the plic interrupt. - */ -__attribute__((weak, optimize("O0"))) void handler_irq_uart(uint32_t id); - #ifdef __cplusplus } #endif diff --git a/sw/device/lib/runtime/core_v_mini_mcu.h.tpl b/sw/device/lib/runtime/core_v_mini_mcu.h.tpl index 3784711ca..3f9ac39af 100644 --- a/sw/device/lib/runtime/core_v_mini_mcu.h.tpl +++ b/sw/device/lib/runtime/core_v_mini_mcu.h.tpl @@ -20,33 +20,20 @@ extern "C" { #define DEBUG_SIZE 0x${debug_size_address} #define DEBUG_END_ADDRESS (DEBUG_START_ADDRESS + DEBUG_SIZE) -//always-on peripherals -#define AO_PERIPHERAL_START_ADDRESS 0x${ao_peripheral_start_address} -#define AO_PERIPHERAL_SIZE 0x${ao_peripheral_size_address} -#define AO_PERIPHERAL_END_ADDRESS (AO_PERIPHERAL_START_ADDRESS + AO_PERIPHERAL_SIZE) -% for name, peripheral in ao_peripherals.items(): -#define ${name.upper()}_START_ADDRESS (AO_PERIPHERAL_START_ADDRESS + 0x${peripheral['offset']}) -#define ${name.upper()}_SIZE 0x${peripheral['length']} -#define ${name.upper()}_END_ADDRESS (${name.upper()}_START_ADDRESS + ${name.upper()}_SIZE) +% for domain in xheep.iter_peripheral_domains(): +#define ${domain.get_name().upper()}_START_ADDRESS ${f"0x{domain.get_address():08X}"} +#define ${domain.get_name().upper()}_SIZE ${f"0x{domain.get_address_length():08X}"} +#define ${domain.get_name().upper()}_END_ADDRESS (${domain.get_name().upper()}_START_ADDRESS + ${domain.get_name().upper()}_SIZE) -%endfor - -//switch-on/off peripherals -#define PERIPHERAL_START_ADDRESS 0x${peripheral_start_address} -#define PERIPHERAL_SIZE 0x${peripheral_size_address} -#define PERIPHERAL_END_ADDRESS (PERIPHERAL_START_ADDRESS + PERIPHERAL_SIZE) - -% for name, peripheral in peripherals.items(): -#define ${name.upper()}_START_ADDRESS (PERIPHERAL_START_ADDRESS + 0x${peripheral['offset']}) -#define ${name.upper()}_SIZE 0x${peripheral['length']} -#define ${name.upper()}_END_ADDRESS (${name.upper()}_START_ADDRESS + ${name.upper()}_SIZE) -% if "yes" in peripheral['is_included']: -#define ${name.upper()}_IS_INCLUDED +% for periph in domain.iter_peripherals(): +#define ${periph.full_name.upper()}_START_ADDRESS (${domain.get_name().upper()}_START_ADDRESS + ${f"0x{periph.get_offset_checked():08X}"}) +#define ${periph.full_name.upper()}_SIZE ${f"0x{periph.get_address_length_checked():08X}"} +#define ${periph.full_name.upper()}_END_ADDRESS (${periph.full_name.upper()}_START_ADDRESS + ${periph.full_name.upper()}_SIZE) +#define ${periph.full_name.upper()}_IS_INCLUDED -%else: +%endfor -% endif %endfor #define EXT_SLAVE_START_ADDRESS 0x${ext_slave_start_address} @@ -57,19 +44,29 @@ extern "C" { #define FLASH_MEM_SIZE 0x${flash_mem_size_address} #define FLASH_MEM_END_ADDRESS (FLASH_MEM_START_ADDRESS + FLASH_MEM_SIZE) -#define QTY_INTR ${len(interrupts)} -% for key, value in interrupts.items(): -#define ${key.upper()} ${value} +##% for key, value in interrupts.items(): +###define ${key.upper()} ${value} +##% endfor +<% + from x_heep_gen.peripherals.rv_plic import RvPlicPeripheral +%> + +#define NULL_INTR 0 +% for domain in xheep.iter_peripheral_domains(): +% for periph in domain.iter_peripherals(): +% if isinstance(periph, RvPlicPeripheral): +${periph.make_intr_defs(xheep.get_rh())} +% endif +% endfor % endfor -% if pads_attributes != None: -% for pad in pad_list: -#define ${pad.localparam}_ATTRIBUTE ${pad.index} + +% if xheep.get_pad_manager().get_attr_bits() != 0: +% for i, pad in enumerate(xheep.get_pad_manager().iterate_pad_index()): +#define ${pad}_ATTRIBUTE ${i} % endfor % endif -#define GPIO_AO_DOMAIN_LIMIT 8 - #ifdef __cplusplus } // extern "C" diff --git a/sw/device/lib/runtime/syscalls.c b/sw/device/lib/runtime/syscalls.c index a9a7fcc20..224fb6ae7 100644 --- a/sw/device/lib/runtime/syscalls.c +++ b/sw/device/lib/runtime/syscalls.c @@ -250,8 +250,9 @@ ssize_t _write(int file, const void *ptr, size_t len) soc_ctrl_t soc_ctrl; soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); +#ifdef UART_0_IS_INCLUDED uart_t uart; - uart.base_addr = mmio_region_from_addr((uintptr_t)UART_START_ADDRESS); + uart.base_addr = mmio_region_from_addr((uintptr_t)UART_0_START_ADDRESS); uart.baudrate = UART_BAUDRATE; uart.clk_freq_hz = soc_ctrl_get_frequency(&soc_ctrl); @@ -261,7 +262,9 @@ ssize_t _write(int file, const void *ptr, size_t len) } return uart_write(&uart,(uint8_t *)ptr,len); - +#else + return len; +#endif } extern char __heap_start[]; diff --git a/tb/testharness.sv b/tb/testharness.sv index 2a4c70403..033b5b3c5 100644 --- a/tb/testharness.sv +++ b/tb/testharness.sv @@ -183,8 +183,8 @@ module testharness #( .boot_select_i, .execute_from_flash_i, .exit_valid_o, - .uart_rx_i(uart_rx), - .uart_tx_o(uart_tx), + .uart0_rx_0_i(uart_rx), + .uart0_tx_0_o(uart_tx), .gpio_0_io(gpio[0]), .gpio_1_io(gpio[1]), .gpio_2_io(gpio[2]), @@ -203,34 +203,34 @@ module testharness #( .gpio_15_io(gpio[15]), .gpio_16_io(gpio[16]), .gpio_17_io(gpio[17]), - .spi_flash_sck_io(spi_flash_sck), - .spi_flash_cs_0_io(spi_flash_csb[0]), - .spi_flash_cs_1_io(spi_flash_csb[1]), + .spi_flash_sck_0_io(spi_flash_sck), + .spi_flash_csb_0_io(spi_flash_csb[0]), + .spi_flash_csb_1_io(spi_flash_csb[1]), .spi_flash_sd_0_io(spi_flash_sd_io[0]), .spi_flash_sd_1_io(spi_flash_sd_io[1]), .spi_flash_sd_2_io(spi_flash_sd_io[2]), .spi_flash_sd_3_io(spi_flash_sd_io[3]), - .spi_sck_io(spi_sck), - .spi_cs_0_io(spi_csb[0]), - .spi_cs_1_io(spi_csb[1]), - .spi_sd_0_io(spi_sd_io[0]), - .spi_sd_1_io(spi_sd_io[1]), - .spi_sd_2_io(spi_sd_io[2]), - .spi_sd_3_io(spi_sd_io[3]), - .pdm2pcm_pdm_io(gpio[18]), - .pdm2pcm_clk_io(gpio[19]), - .i2s_sck_io(gpio[20]), - .i2s_ws_io(gpio[21]), - .i2s_sd_io(gpio[22]), - .spi2_cs_0_io(gpio[23]), - .spi2_cs_1_io(gpio[24]), - .spi2_sck_io(gpio[25]), - .spi2_sd_0_io(gpio[26]), - .spi2_sd_1_io(gpio[27]), - .spi2_sd_2_io(gpio[28]), - .spi2_sd_3_io(gpio[29]), - .i2c_scl_io(gpio[31]), - .i2c_sda_io(gpio[30]), + .spi_host0_sck_0_io(spi_sck), + .spi_host0_csb_0_io(spi_csb[0]), + .spi_host0_csb_1_io(spi_csb[1]), + .spi_host0_sd_0_io(spi_sd_io[0]), + .spi_host0_sd_1_io(spi_sd_io[1]), + .spi_host0_sd_2_io(spi_sd_io[2]), + .spi_host0_sd_3_io(spi_sd_io[3]), + .pdm2pcm0_pdm_0_io(gpio[18]), + .pdm2pcm0_pdm_clk_0_io(gpio[19]), + .i2s0_sck_0_io(gpio[20]), + .i2s0_ws_0_io(gpio[21]), + .i2s0_sd_0_io(gpio[22]), + .spi_host1_csb_0_io(gpio[23]), + .spi_host1_csb_1_io(gpio[24]), + .spi_host1_sck_0_io(gpio[25]), + .spi_host1_sd_0_io(gpio[26]), + .spi_host1_sd_1_io(gpio[27]), + .spi_host1_sd_2_io(gpio[28]), + .spi_host1_sd_3_io(gpio[29]), + .i2c0_scl_0_io(gpio[31]), + .i2c0_sda_0_io(gpio[30]), .exit_value_o, .intr_vector_ext_i(intr_vector_ext), .xif_compressed_if(ext_if), diff --git a/util/mcu_gen.py b/util/mcu_gen.py index c661d780d..c760ce99e 100755 --- a/util/mcu_gen.py +++ b/util/mcu_gen.py @@ -7,280 +7,14 @@ #Simplified version of occamygen.py https://github.com/pulp-platform/snitch/blob/master/util/occamygen.py import argparse -import hjson +import pickle import pathlib -import sys -import re import logging -from subprocess import run -import csv -from jsonref import JsonRef +import re from mako.template import Template -import collections -from math import log2 -import x_heep_gen.load_config -from x_heep_gen.system import BusType - -class Pad: - - def remove_comma_io_interface(self): - try: - self.x_heep_system_interface = self.x_heep_system_interface.rstrip(self.x_heep_system_interface[-1]) - except IndexError: - pass - ### bypass kind of PADs do not have any comma to be removed as they do not define an interface - - def create_pad_ring(self): - - # Mapping dictionary from string to integer - mapping_dict = { - 'top' : 'core_v_mini_mcu_pkg::TOP', - 'right' : 'core_v_mini_mcu_pkg::RIGHT', - 'bottom' : 'core_v_mini_mcu_pkg::BOTTOM', - 'left' : 'core_v_mini_mcu_pkg::LEFT' - } - - mapping = '' - if self.pad_mapping is not None: - mapping = ', .SIDE(' + mapping_dict[self.pad_mapping] + ')' - - self.interface = ' inout wire ' + self.name + '_io,\n' - - if self.pad_type == 'input': - self.pad_ring_io_interface = ' inout wire ' + self.io_interface + ',' - self.pad_ring_ctrl_interface += ' output logic ' + self.signal_name + 'o,' - self.pad_ring_instance = \ - 'pad_cell_input #(.PADATTR('+ str(self.attribute_bits) +')' + mapping + ') ' + self.cell_name + ' ( \n' + \ - ' .pad_in_i(1\'b0),\n' + \ - ' .pad_oe_i(1\'b0),\n' + \ - ' .pad_out_o(' + self.signal_name + 'o),\n' + \ - ' .pad_io(' + self.signal_name + 'io),\n' - if self.pad_type == 'output': - self.pad_ring_io_interface = ' inout wire ' + self.io_interface + ',' - self.pad_ring_ctrl_interface += ' input logic ' + self.signal_name + 'i,' - self.pad_ring_instance = \ - 'pad_cell_output #(.PADATTR('+ str(self.attribute_bits) +')' + mapping + ') ' + self.cell_name + ' ( \n' + \ - ' .pad_in_i(' + self.signal_name + 'i),\n' + \ - ' .pad_oe_i(1\'b1),\n' + \ - ' .pad_out_o(),\n' + \ - ' .pad_io(' + self.signal_name + 'io),\n' - if self.pad_type == 'inout': - self.pad_ring_io_interface = ' inout wire ' + self.io_interface + ',' - self.pad_ring_ctrl_interface += ' input logic ' + self.signal_name + 'i,\n' - self.pad_ring_ctrl_interface += ' output logic ' + self.signal_name + 'o,\n' - self.pad_ring_ctrl_interface += ' input logic ' + self.signal_name + 'oe_i,' - self.pad_ring_instance = \ - 'pad_cell_inout #(.PADATTR('+ str(self.attribute_bits) +')' + mapping + ') ' + self.cell_name + ' ( \n' + \ - ' .pad_in_i(' + self.signal_name + 'i),\n' + \ - ' .pad_oe_i(' + self.signal_name + 'oe_i),\n' + \ - ' .pad_out_o(' + self.signal_name + 'o),\n' + \ - ' .pad_io(' + self.signal_name + 'io),\n' - - if self.pad_type == 'input' or self.pad_type == 'output' or self.pad_type == 'inout': - if self.has_attribute: - self.pad_ring_instance += \ - ' .pad_attributes_i(pad_attributes_i[core_v_mini_mcu_pkg::' + self.localparam + '])\n' + \ - ');\n\n' - else: - self.pad_ring_instance += \ - ' .pad_attributes_i(\'0)' + \ - ');\n\n' - - - def create_core_v_mini_mcu_ctrl(self): - - cnt = len(self.pad_type_drive) - - for i in range(cnt): - if self.driven_manually[i] == False: - if self.pad_type_drive[i] == 'input' or self.pad_type_drive[i] == 'bypass_input': - self.core_v_mini_mcu_interface += ' input logic ' + self.signal_name_drive[i] + 'i,\n' - if self.pad_type_drive[i] == 'output' or self.pad_type_drive[i] == 'bypass_output': - self.core_v_mini_mcu_interface += ' output logic ' + self.signal_name_drive[i] + 'o,\n' - if self.pad_type_drive[i] == 'inout' or self.pad_type_drive[i] == 'bypass_inout': - self.core_v_mini_mcu_interface += ' output logic ' + self.signal_name_drive[i] + 'o,\n' - self.core_v_mini_mcu_interface += ' input logic ' + self.signal_name_drive[i] + 'i,\n' - self.core_v_mini_mcu_interface += ' output logic ' + self.signal_name_drive[i] + 'oe_o,\n' - - def create_internal_signals(self): - cnt = len(self.pad_type_drive) - - for i in range(cnt): - - self.in_internal_signals.append(self.signal_name_drive[i] + 'in_x') - self.out_internal_signals.append(self.signal_name_drive[i] + 'out_x') - self.oe_internal_signals.append(self.signal_name_drive[i] + 'oe_x') - - if (self.skip_declaration[i] == False): - self.internal_signals += ' logic ' + self.in_internal_signals[i] + ',' \ - + self.out_internal_signals[i] + ',' \ - + self.oe_internal_signals[i] + ';\n' - - def create_multiplexers(self): - cnt = len(self.pad_type_drive) - - if cnt > 1: - ###muxing - pad_in_internal_signals = self.signal_name + 'in_x_muxed' - pad_out_internal_signals = self.signal_name + 'out_x_muxed' - pad_oe_internal_signals = self.signal_name + 'oe_x_muxed' - - self.internal_signals += ' logic ' + pad_in_internal_signals + ',' \ - + pad_out_internal_signals + ',' \ - + pad_oe_internal_signals + ';\n' - - self.mux_process += ' always_comb\n' + \ - ' begin\n' - - for i in range(cnt): - self.mux_process += ' ' + self.in_internal_signals[i] + '=1\'b0;\n' - - - self.mux_process += ' unique case(pad_muxes[core_v_mini_mcu_pkg::' + self.localparam + '])\n' - - for i in range(cnt): - self.mux_process += ' ' + str(i) + ': begin\n' + \ - ' ' + pad_out_internal_signals + ' = ' + self.out_internal_signals[i] + ';\n' + \ - ' ' + pad_oe_internal_signals + ' = ' + self.oe_internal_signals[i] + ';\n' + \ - ' ' + self.in_internal_signals[i] + ' = ' + pad_in_internal_signals + ';\n' + \ - ' end\n' - - self.mux_process += ' default: begin\n' + \ - ' ' + pad_out_internal_signals + ' = ' + self.out_internal_signals[0] + ';\n' + \ - ' ' + pad_oe_internal_signals + ' = ' + self.oe_internal_signals[0] + ';\n' + \ - ' ' + self.in_internal_signals[0] + ' = ' + pad_in_internal_signals + ';\n' + \ - ' end\n' - - self.mux_process += ' endcase\n' + \ - ' end\n' - - def create_constant_driver_assign(self): - cnt = len(self.pad_type_drive) - - for i in range(cnt): - - if (self.skip_declaration[i] == False): - if self.pad_type_drive[i] == 'input' or self.pad_type_drive[i] == 'bypass_input': - self.constant_driver_assign += ' assign ' + self.out_internal_signals[i] + ' = 1\'b0;\n' - self.constant_driver_assign += ' assign ' + self.oe_internal_signals[i] + ' = 1\'b0;\n' - if self.pad_type_drive[i] == 'output' or self.pad_type_drive[i] == 'bypass_output': - self.constant_driver_assign += ' assign ' + self.oe_internal_signals[i] + ' = 1\'b1;\n' - - def create_core_v_mini_mcu_bonding(self): - - cnt = len(self.pad_type_drive) - - for i in range(cnt): - - if self.driven_manually[i] == False: - if self.pad_type_drive[i] == 'input' or self.pad_type_drive[i] == 'bypass_input': - self.core_v_mini_mcu_bonding += ' .' + self.signal_name_drive[i] + 'i(' + self.in_internal_signals[i] + '),\n' - if self.pad_type_drive[i] == 'output' or self.pad_type_drive[i] == 'bypass_output': - self.core_v_mini_mcu_bonding += ' .' + self.signal_name_drive[i] + 'o(' + self.out_internal_signals[i] + '),\n' - if self.pad_type_drive[i] == 'inout' or self.pad_type_drive[i] == 'bypass_inout': - self.core_v_mini_mcu_bonding += ' .' + self.signal_name_drive[i] + 'i(' + self.in_internal_signals[i] + '),\n' - self.core_v_mini_mcu_bonding += ' .' + self.signal_name_drive[i] + 'o(' + self.out_internal_signals[i] + '),\n' - self.core_v_mini_mcu_bonding += ' .' + self.signal_name_drive[i] + 'oe_o(' + self.oe_internal_signals[i] + '),\n' - - def create_pad_ring_bonding(self): - - if(self.is_muxed): - append_name = '_muxed' - else: - append_name = '' - - if self.pad_type == 'input': - in_internal_signals = self.signal_name + 'in_x' + append_name - self.pad_ring_bonding_bonding = ' .' + self.io_interface + '(' + self.signal_name + 'i),\n' - self.pad_ring_bonding_bonding += ' .' + self.signal_name + 'o(' + in_internal_signals + '),' - self.x_heep_system_interface += ' inout wire ' + self.signal_name + 'i,' - if self.pad_type == 'output': - out_internal_signals = self.signal_name + 'out_x' + append_name - self.pad_ring_bonding_bonding = ' .' + self.io_interface + '(' + self.signal_name + 'o),\n' - self.pad_ring_bonding_bonding += ' .' + self.signal_name + 'i(' + out_internal_signals + '),' - self.x_heep_system_interface += ' inout wire ' + self.signal_name + 'o,' - if self.pad_type == 'inout': - in_internal_signals = self.signal_name + 'in_x' + append_name - out_internal_signals = self.signal_name + 'out_x' + append_name - oe_internal_signals = self.signal_name + 'oe_x' + append_name - self.pad_ring_bonding_bonding = ' .' + self.io_interface + '(' + self.signal_name + 'io),\n' - self.pad_ring_bonding_bonding += ' .' + self.signal_name + 'o(' + in_internal_signals + '),\n' - self.pad_ring_bonding_bonding += ' .' + self.signal_name + 'i(' + out_internal_signals + '),\n' - self.pad_ring_bonding_bonding += ' .' + self.signal_name + 'oe_i(' + oe_internal_signals + '),' - self.x_heep_system_interface += ' inout wire ' + self.signal_name + 'io,' - - def __init__(self, name, cell_name, pad_type, pad_mapping, index, pad_active, pad_driven_manually, pad_skip_declaration, pad_mux_list, has_attribute, attribute_bits): - self.name = name - self.cell_name = cell_name - self.index = index - self.localparam = 'PAD_' + name.upper() - self.pad_type = pad_type - self.pad_mapping = pad_mapping - self.pad_mux_list = pad_mux_list - - if('low' in pad_active): - name_active = 'n' - else: - name_active = '' - - self.signal_name = self.name + '_' + name_active - - self.has_attribute = has_attribute - self.attribute_bits = int(attribute_bits.split(":")[0]) - int(attribute_bits.split(":")[1]) + 1 - - self.signal_name_drive = [] - self.pad_type_drive = [] - self.driven_manually = [] - self.skip_declaration = [] - self.keep_internal = [] - - self.is_muxed = False - - self.is_driven_manually = pad_driven_manually - self.do_skip_declaration = pad_skip_declaration - - if(len(pad_mux_list) == 0): - self.signal_name_drive.append(self.signal_name) - self.pad_type_drive.append(pad_type) - self.driven_manually.append(pad_driven_manually) - self.skip_declaration.append(pad_skip_declaration) - else: - for pad_mux in pad_mux_list: - self.signal_name_drive.append(pad_mux.signal_name) - self.pad_type_drive.append(pad_mux.pad_type) - self.driven_manually.append(pad_mux.is_driven_manually) - self.skip_declaration.append(pad_mux.do_skip_declaration) - - self.is_muxed = True - - self.in_internal_signals = [] - self.out_internal_signals = [] - self.oe_internal_signals = [] - - self.io_interface = self.signal_name + 'io' - - ### Pad Ring ### - self.pad_ring_io_interface = '' - self.pad_ring_ctrl_interface = '' - self.pad_ring_instance = '' - - ### core v mini mcu ### - self.core_v_mini_mcu_interface = '' - self.constant_driver_assign = '' - self.mux_process = '' - - ### heep systems ### - self.internal_signals = '' - self.core_v_mini_mcu_bonding = '' - self.pad_ring_bonding_bonding = '' - self.x_heep_system_interface = '' - -# Compile a regex to trim trailing whitespaces on lines. re_trailws = re.compile(r'[ \t\r]+$', re.MULTILINE) -def string2int(hex_json_string): - return (hex_json_string.split('x')[1]).split(',')[0] def write_template(tpl_path, outdir, outfile, **kwargs): if tpl_path: @@ -299,26 +33,7 @@ def write_template(tpl_path, outdir, outfile, **kwargs): raise FileNotFoundError def main(): - parser = argparse.ArgumentParser(prog="mcugen") - parser.add_argument("--cfg_peripherals", - "-c", - metavar="file", - type=argparse.FileType('r'), - required=True, - help="A configuration file") - - parser.add_argument("--config", - metavar="file", - type=str, - required=True, - help="X-Heep general configuration") - - parser.add_argument("--pads_cfg", - "-pc", - metavar="file", - type=argparse.FileType('r'), - required=True, - help="A pad configuration file") + parser = argparse.ArgumentParser(prog="mcu_gen") parser.add_argument("--outdir", "-of", @@ -331,38 +46,12 @@ def main(): type=pathlib.Path, required=False, help="Target filename, if omitted the template basename is taken.") - - # Parse arguments. - - parser.add_argument("--cpu", - metavar="cv32e20,cv32e40p,cv32e40x,cv32e40px", - nargs='?', - default="", - help="CPU type (default value from cfg file)") - - parser.add_argument("--bus", - metavar="onetoM,NtoM", - nargs='?', - default="", - help="Bus type (default value from cfg file)") - - parser.add_argument("--memorybanks", - metavar="from 2 to 16", - nargs='?', - default="", - help="Number of 32KB Banks (default value from cfg file)") - - parser.add_argument("--memorybanks_il", - metavar="0, 2, 4 or 8", - nargs='?', - default="", - help="Number of interleaved memory banks (default value from cfg file)") - - parser.add_argument("--external_domains", - metavar="from 0 to 32", - nargs='?', - default="1", - help="Number of external domains") + + parser.add_argument("--infile", + "-i", + type=pathlib.Path, + required=True, + help="config data object") parser.add_argument("--pkg-sv", metavar="PKG_SV", @@ -381,15 +70,6 @@ def main(): metavar="LINKER_SCRIPT", help="Name of the linker script (output)") - parser.add_argument("--external_pads", - metavar="file", - type=argparse.FileType('r'), - required=False, - nargs='?', - default=None, - const=None, - help="Name of the hjson file contaiting extra pads") - parser.add_argument("-v", "--verbose", help="increase output verbosity", @@ -400,452 +80,14 @@ def main(): if args.verbose: logging.basicConfig(level=logging.DEBUG) - # Read HJSON description of System. - with args.cfg_peripherals as file: - try: - srcfull = file.read() - obj = hjson.loads(srcfull, use_decimal=True) - obj = JsonRef.replace_refs(obj) - except ValueError: - raise SystemExit(sys.exc_info()[1]) - - with args.pads_cfg as file: - try: - srcfull = file.read() - obj_pad = hjson.loads(srcfull, use_decimal=True) - obj_pad = JsonRef.replace_refs(obj_pad) - except ValueError: - raise SystemExit(sys.exc_info()[1]) - - if not args.outdir.is_dir(): - exit("Out directory is not a valid path.") outdir = args.outdir outdir.mkdir(parents=True, exist_ok=True) outfile = args.outfile - config_override = x_heep_gen.system.Override(None, None, None) - - if args.cpu != None and args.cpu != '': - cpu_type = args.cpu - else: - cpu_type = obj['cpu_type'] - - if args.bus != None and args.bus != '': - config_override.bus_type = BusType(args.bus) - - if args.memorybanks != None and args.memorybanks != '': - config_override.numbanks = int(args.memorybanks) - - if args.memorybanks_il != None and args.memorybanks_il != '': - config_override.numbanks_il = int(args.memorybanks_il) - - if args.external_domains != None and args.external_domains != '': - external_domains = int(args.external_domains) - else: - external_domains = 0 - - if external_domains > 32: - exit("external_domains must be less than 32 instead of " + str(external_domains)) - - - - xheep = x_heep_gen.load_config.load_cfg_file(pathlib.PurePath(str(args.config)), config_override) - - - - debug_start_address = string2int(obj['debug']['address']) - if int(debug_start_address, 16) < int('10000', 16): - exit("debug start address must be greater than 0x10000") - - debug_size_address = string2int(obj['debug']['length']) - - ao_peripheral_start_address = string2int(obj['ao_peripherals']['address']) - if int(ao_peripheral_start_address, 16) < int('10000', 16): - exit("always on peripheral start address must be greater than 0x10000") - - ao_peripheral_size_address = string2int(obj['ao_peripherals']['length']) - - - def extract_peripherals(peripherals): - result = {} - for name, info in peripherals.items(): - if isinstance(info, dict): - new_info = {} - for k, v in info.items(): - if k not in ("is_included"): - new_info[k] = string2int(v) - else: - new_info[k] = v - result[name] = new_info - - return result - - - def discard_path(peripherals): - new = {} - for k,v in peripherals.items(): - if isinstance(v, dict): - new[k] = {key:val for key,val in v.items() if key not in ("path")} - else: - new[k] = v - return new - - def len_extracted_peripherals(peripherals): - len_ep = 0 - for name, info in peripherals.items(): - if isinstance(info, dict): - for k, v in info.items(): - if k in ("is_included"): - if v in ("yes"): - len_ep += 1 - return len_ep - - ao_peripherals = extract_peripherals(discard_path(obj['ao_peripherals'])) - ao_peripherals_count = len(ao_peripherals) - - - peripheral_start_address = string2int(obj['peripherals']['address']) - if int(peripheral_start_address, 16) < int('10000', 16): - exit("peripheral start address must be greater than 0x10000") - - peripheral_size_address = string2int(obj['peripherals']['length']) - peripherals = extract_peripherals(discard_path(obj['peripherals'])) - peripherals_count = len(peripherals) - - ext_slave_start_address = string2int(obj['ext_slaves']['address']) - ext_slave_size_address = string2int(obj['ext_slaves']['length']) - - flash_mem_start_address = string2int(obj['flash_mem']['address']) - flash_mem_size_address = string2int(obj['flash_mem']['length']) - - stack_size = string2int(obj['linker_script']['stack_size']) - heap_size = string2int(obj['linker_script']['heap_size']) - - - if ((int(stack_size,16) + int(heap_size,16)) > xheep.ram_size_address()): - exit("The stack and heap section must fit in the RAM size, instead they takes " + str(stack_size + heap_size)) - - - plic_used_n_interrupts = len(obj['interrupts']['list']) - plit_n_interrupts = obj['interrupts']['number'] - ext_int_list = { f"EXT_INTR_{k}": v for k, v in enumerate(range(plic_used_n_interrupts, plit_n_interrupts)) } - - interrupts = { - **obj['interrupts']['list'], - **ext_int_list - } - - - pads = obj_pad['pads'] - - try: - pads_attributes = obj_pad['attributes'] - pads_attributes_bits = pads_attributes['bits'] - except KeyError: - pads_attributes = None - pads_attributes_bits = "-1:0" - - # Read HJSON description of External Pads - if args.external_pads != None: - with args.external_pads as file_external_pads: - try: - srcfull = file_external_pads.read() - ext_pads_obj = hjson.loads(srcfull, use_decimal=True) - ext_pads_obj = JsonRef.replace_refs(ext_pads_obj) - except ValueError: - raise SystemExit(sys.exc_info()[1]) - - external_pads = ext_pads_obj['pads'] - else: - external_pads = None - - pad_list = [] - pad_index_counter = 0 - external_pad_list = [] - external_pad_index_counter = 0 - - pad_constant_driver_assign='' - pad_mux_process='' - - pad_muxed_list = [] - - for key in pads: - - pad_name = key - pad_num = pads[key]['num'] - pad_type = pads[key]['type'].strip(',') - - try: - pad_offset = int(pads[key]['num_offset']) - except KeyError: - pad_offset = 0 - - try: - pad_active = pads[key]['active'] - except KeyError: - pad_active = 'high' - - try: - pad_mapping = pads[key]['mapping'].strip(',') - except KeyError: - pad_mapping = None - - try: - pad_mux_list_hjson = pads[key]['mux'] - except KeyError: - pad_mux_list_hjson = [] - - try: - if ('True' in pads[key]['driven_manually']): - pad_driven_manually = True - else: - pad_driven_manually = False - except KeyError: - pad_driven_manually = False - - try: - if ('True' in pads[key]['skip_declaration']): - pad_skip_declaration = True - else: - pad_skip_declaration = False - except KeyError: - pad_skip_declaration = False - - try: - if ('True' in pads[key]['keep_internal']): - pad_keep_internal = True - else: - pad_keep_internal = False - except KeyError: - pad_keep_internal = False - - pad_mux_list = [] - - for pad_mux in pad_mux_list_hjson: - - try: - pad_active_mux = pads[key]['mux'][pad_mux]['active'] - except KeyError: - pad_active_mux = 'high' - - try: - if ('True' in pads[key]['mux'][pad_mux]['driven_manually']): - pad_driven_manually_mux = True - else: - pad_driven_manually_mux = False - except KeyError: - pad_driven_manually_mux = False - - try: - if ('True' in pads[key]['mux'][pad_mux]['skip_declaration']): - pad_skip_declaration_mux = True - else: - pad_skip_declaration_mux = False - except KeyError: - pad_skip_declaration_mux = False - - p = Pad(pad_mux, '', pads[key]['mux'][pad_mux]['type'], pad_mapping, 0, pad_active_mux, pad_driven_manually_mux, pad_skip_declaration_mux, [], pads_attributes!=None, pads_attributes_bits) - pad_mux_list.append(p) - - if pad_num > 1: - for p in range(pad_num): - pad_cell_name = "pad_" + key + "_" + str(p+pad_offset) + "_i" - pad_obj = Pad(pad_name + "_" + str(p+pad_offset), pad_cell_name, pad_type, pad_mapping, pad_index_counter, pad_active, pad_driven_manually, pad_skip_declaration, pad_mux_list, pads_attributes!=None, pads_attributes_bits) - if not pad_keep_internal: - pad_obj.create_pad_ring() - pad_obj.create_core_v_mini_mcu_ctrl() - if not pad_keep_internal: - pad_obj.create_pad_ring_bonding() - pad_obj.create_internal_signals() - pad_obj.create_constant_driver_assign() - pad_obj.create_multiplexers() - pad_obj.create_core_v_mini_mcu_bonding() - pad_index_counter = pad_index_counter + 1 - pad_list.append(pad_obj) - pad_constant_driver_assign+= pad_obj.constant_driver_assign - pad_mux_process+=pad_obj.mux_process - if (pad_obj.is_muxed): - pad_muxed_list.append(pad_obj) - - else: - pad_cell_name = "pad_" + key + "_i" - pad_obj = Pad(pad_name, pad_cell_name, pad_type, pad_mapping, pad_index_counter, pad_active, pad_driven_manually, pad_skip_declaration, pad_mux_list, pads_attributes!=None, pads_attributes_bits) - if not pad_keep_internal: - pad_obj.create_pad_ring() - pad_obj.create_core_v_mini_mcu_ctrl() - if not pad_keep_internal: - pad_obj.create_pad_ring_bonding() - pad_obj.create_internal_signals() - pad_obj.create_constant_driver_assign() - pad_obj.create_multiplexers() - pad_obj.create_core_v_mini_mcu_bonding() - pad_index_counter = pad_index_counter + 1 - pad_list.append(pad_obj) - pad_constant_driver_assign+= pad_obj.constant_driver_assign - pad_mux_process+=pad_obj.mux_process - if (pad_obj.is_muxed): - pad_muxed_list.append(pad_obj) - - if external_pads != None: - external_pad_index_counter = 0 - external_pad_index = pad_index_counter - for key in external_pads: - pad_name = key - pad_num = external_pads[key]['num'] - pad_type = external_pads[key]['type'] - - try: - pad_offset = int(external_pads[key]['num_offset']) - except KeyError: - pad_offset = 0 - - try: - pad_active = external_pads[key]['active'] - except KeyError: - pad_active = 'high' - - try: - pad_mapping = external_pads[key]['mapping'] - except KeyError: - pad_mapping = None - - try: - pad_mux_list_hjson = external_pads[key]['mux'] - except KeyError: - pad_mux_list_hjson = [] - - try: - if ('True' in external_pads[key]['driven_manually']): - pad_driven_manually = True - else: - pad_driven_manually = False - except KeyError: - pad_driven_manually = False - - try: - if ('True' in external_pads[key]['skip_declaration']): - pad_skip_declaration = True - else: - pad_skip_declaration = False - except KeyError: - pad_skip_declaration = False - - pad_mux_list = [] - - for pad_mux in pad_mux_list_hjson: - - try: - pad_active_mux = external_pads[key]['mux'][pad_mux]['active'] - except KeyError: - pad_active_mux = 'high' - - try: - if ('True' in external_pads[key]['mux'][pad_mux]['driven_manually']): - pad_driven_manually_mux = True - else: - pad_driven_manually_mux = False - except KeyError: - pad_driven_manually_mux = False - - try: - if ('True' in external_pads[key]['mux'][pad_mux]['skip_declaration']): - pad_skip_declaration_mux = True - else: - pad_skip_declaration_mux = False - except KeyError: - pad_skip_declaration_mux = False - - p = Pad(pad_mux, '', external_pads[key]['mux'][pad_mux]['type'], pad_mapping, 0, pad_active_mux, pad_driven_manually_mux, pad_skip_declaration_mux, [], pads_attributes!=None, pads_attributes_bits) - pad_mux_list.append(p) - - if pad_num > 1: - for p in range(pad_num): - pad_cell_name = "pad_" + key + "_" + str(p+pad_offset) + "_i" - pad_obj = Pad(pad_name + "_" + str(p+pad_offset), pad_cell_name, pad_type, pad_mapping, external_pad_index, pad_active, pad_driven_manually, pad_skip_declaration, pad_mux_list, pads_attributes!=None, pads_attributes_bits) - pad_obj.create_pad_ring() - pad_obj.create_pad_ring_bonding() - pad_obj.create_internal_signals() - pad_obj.create_constant_driver_assign() - pad_obj.create_multiplexers() - external_pad_index_counter = external_pad_index_counter + 1 - external_pad_index = external_pad_index + 1 - external_pad_list.append(pad_obj) - pad_constant_driver_assign+= pad_obj.constant_driver_assign - pad_mux_process+=pad_obj.mux_process - if (pad_obj.is_muxed): - pad_muxed_list.append(pad_obj) - - else: - pad_cell_name = "pad_" + key + "_i" - pad_obj = Pad(pad_name, pad_cell_name, pad_type, pad_mapping, external_pad_index, pad_active, pad_driven_manually, pad_skip_declaration, pad_mux_list, pads_attributes!=None, pads_attributes_bits) - pad_obj.create_pad_ring() - pad_obj.create_pad_ring_bonding() - pad_obj.create_internal_signals() - pad_obj.create_constant_driver_assign() - pad_obj.create_multiplexers() - external_pad_index_counter = external_pad_index_counter + 1 - external_pad_index = external_pad_index + 1 - external_pad_list.append(pad_obj) - pad_constant_driver_assign+= pad_obj.constant_driver_assign - pad_mux_process+=pad_obj.mux_process - if (pad_obj.is_muxed): - pad_muxed_list.append(pad_obj) - - total_pad_list = [] - - total_pad_list = pad_list + external_pad_list - - max_total_pad_mux_bitlengh = -1 - for pad in pad_muxed_list: - if (len(pad.pad_mux_list)-1).bit_length() > max_total_pad_mux_bitlengh: - max_total_pad_mux_bitlengh = (len(pad.pad_mux_list)-1).bit_length() - - - total_pad = pad_index_counter + external_pad_index_counter - - total_pad_muxed = len(pad_muxed_list) - - ##remove comma from last PAD io_interface - last_pad = total_pad_list.pop() - last_pad.remove_comma_io_interface() - total_pad_list.append(last_pad) - - kwargs = { - "xheep" : xheep, - "cpu_type" : cpu_type, - "external_domains" : external_domains, - "debug_start_address" : debug_start_address, - "debug_size_address" : debug_size_address, - "ao_peripheral_start_address" : ao_peripheral_start_address, - "ao_peripheral_size_address" : ao_peripheral_size_address, - "ao_peripherals" : ao_peripherals, - "ao_peripherals_count" : ao_peripherals_count, - "peripheral_start_address" : peripheral_start_address, - "peripheral_size_address" : peripheral_size_address, - "peripherals" : peripherals, - "peripherals_count" : peripherals_count, - "ext_slave_start_address" : ext_slave_start_address, - "ext_slave_size_address" : ext_slave_size_address, - "flash_mem_start_address" : flash_mem_start_address, - "flash_mem_size_address" : flash_mem_size_address, - "stack_size" : stack_size, - "heap_size" : heap_size, - "plic_used_n_interrupts" : plic_used_n_interrupts, - "plit_n_interrupts" : plit_n_interrupts, - "interrupts" : interrupts, - "pad_list" : pad_list, - "external_pad_list" : external_pad_list, - "total_pad_list" : total_pad_list, - "total_pad" : total_pad, - "pad_constant_driver_assign" : pad_constant_driver_assign, - "pad_mux_process" : pad_mux_process, - "pad_muxed_list" : pad_muxed_list, - "total_pad_muxed" : total_pad_muxed, - "max_total_pad_mux_bitlengh" : max_total_pad_mux_bitlengh, - "pads_attributes" : pads_attributes, - } + with open(args.infile, "rb") as f: + kwargs = pickle.load(f) ########### # Package # diff --git a/util/mk_cfg.py b/util/mk_cfg.py new file mode 100755 index 000000000..a25c44659 --- /dev/null +++ b/util/mk_cfg.py @@ -0,0 +1,190 @@ +#!/usr/bin/env python3 + +# 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 + +#Simplified version of occamygen.py https://github.com/pulp-platform/snitch/blob/master/util/occamygen.py + +import argparse +import pickle +import hjson +import pathlib +import sys +import logging +from jsonref import JsonRef +import x_heep_gen.load_config +from x_heep_gen.system import BusType + + +def string2int(hex_json_string): + return (hex_json_string.split('x')[1]).split(',')[0] + + +def main(): + parser = argparse.ArgumentParser(prog="mk_cfg") + parser.add_argument("--cfg_peripherals", + "-c", + metavar="file", + type=argparse.FileType('r'), + required=True, + help="A configuration file") + + parser.add_argument("--config", + metavar="file", + type=str, + required=True, + help="X-Heep general configuration") + + parser.add_argument("--pads_cfg", + "-pc", + metavar="file", + type=argparse.FileType('r'), + required=True, + help="A pad configuration file") + + parser.add_argument("--outfile", + "-o", + type=pathlib.Path, + required=True, + help="config object file") + + # Parse arguments. + + parser.add_argument("--cpu", + metavar="cv32e20,cv32e40p,cv32e40x,cv32e40px", + nargs='?', + default="", + help="CPU type (default value from cfg file)") + + parser.add_argument("--bus", + metavar="onetoM,NtoM", + nargs='?', + default="", + help="Bus type (default value from cfg file)") + + parser.add_argument("--memorybanks", + metavar="from 2 to 16", + nargs='?', + default="", + help="Number of 32KB Banks (default value from cfg file)") + + parser.add_argument("--memorybanks_il", + metavar="0, 2, 4 or 8", + nargs='?', + default="", + help="Number of interleaved memory banks (default value from cfg file)") + + parser.add_argument("--external_domains", + metavar="from 0 to 32", + nargs='?', + default="1", + help="Number of external domains") + + + parser.add_argument("--external_pads", + metavar="file", + type=argparse.FileType('r'), + required=False, + nargs='?', + default=None, + const=None, + help="Name of the hjson file contaiting extra pads") + + parser.add_argument("-v", + "--verbose", + help="increase output verbosity", + action="store_true") + + args = parser.parse_args() + + if args.verbose: + logging.basicConfig(level=logging.DEBUG) + + # Read HJSON description of System. + with args.cfg_peripherals as file: + try: + srcfull = file.read() + obj = hjson.loads(srcfull, use_decimal=True) + obj = JsonRef.replace_refs(obj) + except ValueError: + raise SystemExit(sys.exc_info()[1]) + + with args.pads_cfg as file: + try: + srcfull = file.read() + obj_pad = hjson.loads(srcfull, use_decimal=True) + obj_pad = JsonRef.replace_refs(obj_pad) + except ValueError: + raise SystemExit(sys.exc_info()[1]) + + + outfile = args.outfile + + config_override = x_heep_gen.system.Override(None, None, None) + + if args.cpu != None and args.cpu != '': + cpu_type = args.cpu + else: + cpu_type = obj['cpu_type'] + + if args.bus != None and args.bus != '': + config_override.bus_type = BusType(args.bus) + + if args.memorybanks != None and args.memorybanks != '': + config_override.numbanks = int(args.memorybanks) + + if args.memorybanks_il != None and args.memorybanks_il != '': + config_override.numbanks_il = int(args.memorybanks_il) + + if args.external_domains != None and args.external_domains != '': + external_domains = int(args.external_domains) + else: + external_domains = 0 + + if external_domains > 32: + exit("external_domains must be less than 32 instead of " + str(external_domains)) + + + + xheep = x_heep_gen.load_config.load_cfg_file(pathlib.PurePath(str(args.config)), config_override) + + debug_start_address = string2int(obj['debug']['address']) + if int(debug_start_address, 16) < int('10000', 16): + exit("debug start address must be greater than 0x10000") + + debug_size_address = string2int(obj['debug']['length']) + + ext_slave_start_address = string2int(obj['ext_slaves']['address']) + ext_slave_size_address = string2int(obj['ext_slaves']['length']) + + flash_mem_start_address = string2int(obj['flash_mem']['address']) + flash_mem_size_address = string2int(obj['flash_mem']['length']) + + stack_size = string2int(obj['linker_script']['stack_size']) + heap_size = string2int(obj['linker_script']['heap_size']) + + + if ((int(stack_size,16) + int(heap_size,16)) > xheep.ram_size_address()): + exit("The stack and heap section must fit in the RAM size, instead they takes " + str(stack_size + heap_size)) + + + kwargs = { + "xheep" : xheep, + "cpu_type" : cpu_type, + "external_domains" : external_domains, + "debug_start_address" : debug_start_address, + "debug_size_address" : debug_size_address, + "ext_slave_start_address" : ext_slave_start_address, + "ext_slave_size_address" : ext_slave_size_address, + "flash_mem_start_address" : flash_mem_start_address, + "flash_mem_size_address" : flash_mem_size_address, + "stack_size" : stack_size, + "heap_size" : heap_size, + } + + with open(outfile, "wb") as f: + pickle.dump(kwargs, f) + +if __name__ == "__main__": + main() diff --git a/util/structs_gen.py b/util/structs_gen.py index 3c776b42f..9009fa2a3 100644 --- a/util/structs_gen.py +++ b/util/structs_gen.py @@ -54,15 +54,15 @@ def read_json(json_file): return j_data -def write_template(tpl, structs, enums, struct_name): +def write_template(tpl, structs, enums, struct_name, periph_names): """ Opens a given template and substitutes the structs and enums fields. Returns a string with the content of the updated template """ - lower_case_name = struct_name.lower() - upper_case_name = struct_name.upper() - start_addr_def = "{}_peri ((volatile {} *) {}_START_ADDRESS)".format(lower_case_name, struct_name, upper_case_name) + start_addr_def = "" + for name in periph_names: + start_addr_def += f"#define {name.lower()}_peri ((volatile {struct_name} *) {name.upper()}_START_ADDRESS)\n" today = date.today() today = today.strftime("%d/%m/%Y") @@ -74,7 +74,7 @@ def write_template(tpl, structs, enums, struct_name): return template.substitute( structures_definitions=structs, enums_definitions=enums, peripheral_name=struct_name, - peripheral_name_upper=upper_case_name, + peripheral_name_upper=struct_name.upper(), date=today, start_address_define=start_addr_def) @@ -376,8 +376,9 @@ def main(arg_vect): "structure provided by the template.") parser.add_argument("--template_filename", help="filename of the template for the final file generation") - # parser.add_argument("--peripheral_name", - # help="name of the peripheral for which the structs are generated") + parser.add_argument("--peripheral_name", + nargs="*", + help="name of the peripheral for which the structs are generated") parser.add_argument("--json_filename", help="filename of the input json basing on which the structs and enums will begenerated") parser.add_argument("--output_filename", @@ -389,7 +390,7 @@ def main(arg_vect): input_template = args.template_filename input_hjson_file = args.json_filename output_filename = args.output_filename - # peripheral_name = args.peripheral_name + peripheral_names = args.peripheral_name data = read_json(input_hjson_file) @@ -405,7 +406,7 @@ def main(arg_vect): structs_definitions += "}} {};".format(data["name"]) - final_output = write_template(input_template, structs_definitions, enums_definitions, data["name"]) + final_output = write_template(input_template, structs_definitions, enums_definitions, data["name"], peripheral_names) write_output(output_filename, final_output) diff --git a/util/structs_periph_gen.py b/util/structs_periph_gen.py index c737370c9..1fc485ac4 100644 --- a/util/structs_periph_gen.py +++ b/util/structs_periph_gen.py @@ -1,67 +1,62 @@ -import hjson +import argparse +import pathlib +import pickle +from typing import Dict, List + +from reggen.ip_block import IpBlock import structs_gen +from x_heep_gen.system import XHeep +from x_heep_gen.peripherals.peripheral_helper import ip_block_paths # Path to the header_structs template template_path = "./sw/device/lib/drivers/template.tpl" -# hjson file from which the peripherals info are taken -mcu_cfg_file = "./mcu_cfg.hjson" # path in which the structs header files are generated, has to be formatted with # the name of the peripheral out_files_base_path = "./sw/device/lib/drivers/{}/{}_structs.h" -JSON_FILES = [] # list of the peripherals' json files -OUTPUT_FILES = [] # list of the output filenames -PERIPHERAL_NAMES = [] # list of the peripherals' names - - -""" - Given the name of a peripheral and the path to its descriptive json file, - it appends the info relative to the peripheral to the three lists used - for generation -""" -def add_peripheral(name, path): - JSON_FILES.append(path) - OUTPUT_FILES.append(out_files_base_path.format(name, name)) - # PERIPHERAL_NAMES.append(name) - -""" - It loops over the json containing infos of several peripherals. - When it encounters one with the "path" field, it adds it to the - lists -""" -def scan_peripherals(json_list): - for p in json_list: - for field in json_list[p]: - if(field == 'path'): - add_peripheral(p, json_list[p]["path"]) +def mk_out(file: str) -> str: + ip_block = IpBlock.from_path(file, []) + name = ip_block.name.lower() + return out_files_base_path.format(name, name) - # for i in range(len(JSON_FILES)): - # print("{}\n{}\n{}\n\n\n".format(PERIPHERAL_NAMES[i], JSON_FILES[i], OUTPUT_FILES[i])) if __name__ == "__main__": - - # Open the json file adn takes the data - with open(mcu_cfg_file) as f: - data = hjson.load(f) - - # Get the info relative to the various peripherals - ao_peripherals = data["ao_peripherals"] - peripherals = data["peripherals"] - - # loops through the peripherals and add the useful ones - scan_peripherals(ao_peripherals) - scan_peripherals(peripherals) + parser = argparse.ArgumentParser(prog="structs_periph_gen") + + parser.add_argument("--infile", + "-i", + type=pathlib.Path, + required=True, + help="config data object") + + args = parser.parse_args() + + with open(args.infile, "rb") as f: + kwargs = pickle.load(f) + + system: XHeep = kwargs["xheep"] + + ip_files: Dict[str, List[str]] = dict() + for path in ip_block_paths: + ip_files[path] = [] + + for domain in system.iter_peripheral_domains(): + for periph in domain.iter_peripherals(): + path = periph.get_ip_path() + if path is not None: + ip_files.setdefault(path, []).append(periph.full_name) # Call the generation script, once for every peripheral - for i in range(len(JSON_FILES)): + for file, periphs in ip_files.items(): + print(f"Generate file {mk_out(file)} from {file}") structs_gen.main([ "--template_filename", template_path, - # "--peripheral_name", PERIPHERAL_NAMES[i], - "--json_filename", JSON_FILES[i], - "--output_filename", OUTPUT_FILES[i]] + "--peripheral_name", *periphs, + "--json_filename", file, + "--output_filename", mk_out(file)] ) \ No newline at end of file diff --git a/util/test_all.sh b/util/test_all.sh index 0025cb154..ef0aa804f 100755 --- a/util/test_all.sh +++ b/util/test_all.sh @@ -325,17 +325,14 @@ echo -e "\n\nStart? (y/N)" read yn case $yn in [Yy]* ) ;; - [Nn]* ) return;; - * ) return;; + [Nn]* ) exit;; + * ) exit;; esac ############################################################# # SET-UP THE TOOLS ############################################################# -# All peripherals are included to make sure all apps can be built. -sed 's/is_included: "no",/is_included: "yes",/' -i mcu_cfg.hjson - if [ $DEBUG -eq 0 ]; then # The MCU is generated with several memory banks to avoid example code not fitting. make mcu-gen X_HEEP_CFG=configs/testall.hjson EXTERNAL_DOMAINS=1 @@ -399,29 +396,6 @@ do fi done -############################################################# -# FINISH UP -############################################################# - -# Because there were changed made to the mcu_cfg.json file, and the mcu was -# re-generated, some files were changed with respect to the original state when -# the script was launched. -# Ideally, the user should have commited their changes before sourcing the script, -# but if they didn't they can opt-out of the stashing of the changes and make the stash -# manually themselves. -echo -e ${LONG_W} - -git status -uno - -echo -e "${WHITE}During the execution, some files might have been modified." -echo -e "${WHITE}Do you want to revert all these changes? (Y/n)${RESET}" -read yn -case $yn in - [Yy]* ) git restore .;; - [Nn]* ) ;; - * ) git restore .;; -esac - ############################################################# # SHOW RESULTS ############################################################# diff --git a/util/x_heep_gen/__init__.py b/util/x_heep_gen/__init__.py index c1a6b0068..e69de29bb 100644 --- a/util/x_heep_gen/__init__.py +++ b/util/x_heep_gen/__init__.py @@ -1,4 +0,0 @@ -from .system import XHeep -from . import system -from . import load_config -from . import ram_bank \ No newline at end of file diff --git a/util/x_heep_gen/config_helpers.py b/util/x_heep_gen/config_helpers.py new file mode 100644 index 000000000..be3714b86 --- /dev/null +++ b/util/x_heep_gen/config_helpers.py @@ -0,0 +1,57 @@ +from typing import Optional + + +def to_int(input) -> Optional[int]: + """ + A helper to read integers from configuration files. + + It can parse integers as `int` or strings. + It supports prefixes to strings for alternative bases. + + :param input: input + :return: The integer, None if it could not parse. + :rtype: Optional[int] + """ + if type(input) is int: + return input + + if type(input) is str: + base = 10 + if len(input) >= 2: + if input[0:2].upper() == "0X": + base = 16 + input = input[2:] + elif input[0:2] == "0o": + base = 8 + input = input[2:] + elif input[0:2].upper() == "0b": + base = 2 + input = input[2:] + + return int(input, base) + return None + +def to_bool(input) -> Optional[bool]: + """ + A helper to read booleans from configuration files. + + It can parse integers as `bool` integers or strings. + Integers are parsed with `ot_int()`, strings can be `yes`, `true`, `no` or `false` and are not case sensistive. + + :param input: input + :return: The boolean, None if it could not parse. + :rtype: Optional[bool] + """ + if type(input) is int: + return input != 0 + if type(input) is bool: + return input + if type(input) is str: + if input.lower() in ["yes", "true"]: + return True + if input.lower() in ["no", "false"]: + return False + + return to_bool(to_int(input)) + + return None \ No newline at end of file diff --git a/util/x_heep_gen/load_config.py b/util/x_heep_gen/load_config.py index 1c2da738a..bdfa7a1f5 100644 --- a/util/x_heep_gen/load_config.py +++ b/util/x_heep_gen/load_config.py @@ -3,29 +3,13 @@ from typing import List, Optional, Union import hjson +from .pads import PadManager +from .peripherals.peripheral_domain import FixedDomain, PeripheralDomain +from .config_helpers import to_bool, to_int from .linker_section import LinkerSection from .system import BusType, Override, XHeep - -def to_int(input) -> Union[int, None]: - if type(input) is int: - return input - - if type(input) is str: - base = 10 - if len(input) >= 2: - if input[0:2].upper() == "0X": - base = 16 - input = input[2:] - elif input[0:2] == "0o": - base = 8 - input = input[2:] - elif input[0:2].upper() == "0b": - base = 2 - input = input[2:] - - return int(input, base) - return None - +from .peripherals.peripheral_helper import peripheral_factories +from .peripherals.peripherals import * def ram_list(l: "List[int]", entry): """ @@ -169,6 +153,72 @@ def load_linker_config(system: XHeep, config: list): +def _add_peripheral_to_domain(domain: PeripheralDomain, conf: hjson.OrderedDict): + if not "type" in conf or type(conf["type"]) is not str: + raise RuntimeError("type parameter of peripheral is mandatory and should be a string") + + name = conf["type"] + + if not name in peripheral_factories: + raise RuntimeError(f"{name} is not a known peripheral name.") + domain.add_peripheral(peripheral_factories[name].from_odict(conf)) + + + +def load_peripheral_domains(system: XHeep, peripherals_d: hjson.OrderedDict): + """ + Reads the peripheral configuration. + + :param XHeep system: the system to add periperal and peripheral domains to. + :param hjson.OrderedDict peripherals_d: ad dictionary with the configuration. + """ + if not isinstance(peripherals_d, hjson.OrderedDict): + raise RuntimeError("Peripheral domain config should be a dictionary") + + for name, domain_dict in peripherals_d.items(): + if not isinstance(domain_dict, hjson.OrderedDict): + raise RuntimeError("The config of each domain should be a dictionary") + + if type(name) is not str or name == "": + raise RuntimeError("The name of the peripheral domains (dictionary keys) should be non empty strings") + + if not "address" in domain_dict: + raise RuntimeError("Peripheral domains need an address specified") + if not "length" in domain_dict: + raise RuntimeError("Peripheral domains need a length") + + address = to_int(domain_dict["address"]) + length = to_int(domain_dict["length"]) + + if address is None: + raise RuntimeError("The address of peripheral domains should be integers.") + if length is None: + raise RuntimeError("The length of peripheral domains should be an integer") + + domain = None + t = domain_dict.setdefault("type", "normal") + if t == "fixed": + domain = FixedDomain(name, address, length) + elif t == "normal": + hcd = False + if "clock_domain" in domain_dict: + hcd = to_bool(domain_dict.pop("clock_domain")) + if hcd is None: + raise RuntimeError("clock") + + domain = PeripheralDomain(name, address, length, has_clock_domain=hcd) + else: + raise RuntimeError(f"Unkown peripheral domain type {t}, use fixed or normal(default)") + + if not "peripherals" in domain_dict: + print("Warning: empty peripheral domain.") + elif not isinstance(domain_dict["peripherals"], hjson.OrderedDict): + raise RuntimeError("Peripheral config list should be dictionaries") + else: + for _, p in domain_dict["peripherals"].items(): + _add_peripheral_to_domain(domain, p) + system.add_domain(domain) + def load_cfg_hjson(src: str, override: Optional[Override] = None) -> XHeep: """ @@ -185,6 +235,9 @@ def load_cfg_hjson(src: str, override: Optional[Override] = None) -> XHeep: bus_config = None ram_address_config = None linker_config = None + peripheral_config = None + pad_file = None + external_interrupts = None for key, value in config.items(): if key == "ram_banks": @@ -195,6 +248,12 @@ def load_cfg_hjson(src: str, override: Optional[Override] = None) -> XHeep: ram_address_config = value elif key == "linker_sections": linker_config = value + elif key == "peripheral_domains": + peripheral_config = value + elif key == "pad_file": + pad_file = value + elif key == "external_interrupts": + external_interrupts = value if mem_config is None: raise RuntimeError("No memory configuration found") @@ -213,6 +272,24 @@ def load_cfg_hjson(src: str, override: Optional[Override] = None) -> XHeep: if linker_config is not None: load_linker_config(system, linker_config) + if peripheral_config is not None: + load_peripheral_domains(system, peripheral_config) + else: + print("Warning: No peripheral domains configured. The configuration will likely fail.") + + if pad_file is not None: + if type(pad_file) is str: + with open(pad_file) as f: + system.add_pad_manager(PadManager.load(f.read())) + else: + print("Warning: no pad file specified") + + if external_interrupts is not None: + external_interrupts = to_int(external_interrupts) + if external_interrupts is None: + raise RuntimeError("external_interrupts should be an integer") + system.set_ext_intr(external_interrupts) + system.build() if not system.validate(): raise RuntimeError("Could not validate system configuration") diff --git a/util/x_heep_gen/pads.py b/util/x_heep_gen/pads.py new file mode 100644 index 000000000..cef895690 --- /dev/null +++ b/util/x_heep_gen/pads.py @@ -0,0 +1,724 @@ +from copy import deepcopy +from enum import * +from itertools import chain +from typing import Dict, Iterable, List, Optional, Tuple +import hjson + +from .signal_routing.endpoints import Endpoint + +from .config_helpers import to_bool, to_int +from .signal_routing.routing_helper import RoutingHelper +from .signal_routing.node import Node + +@unique +class PadActive(Enum): + """Pad active level""" + LOW = "low" + HIGH = "high" + +@unique +class PadType(Enum): + """Type of pads""" + INPUT = "input" + OUTPUT = "output" + INOUT = "inout" + +@unique +class IODirection(Enum): + """Direction of an io signal""" + INPUT = "input" + OUTPUT = "output" + + + +class IoEP(Endpoint): + """Endpoint representing a general internal io connections""" + def __init__(self): + super().__init__() + self.t = "logic" + self.reserved = True + +class IoInputEP(IoEP): + """Endpoint representing an input internal io connections""" + def __init__(self): + super().__init__() + self.source_direction: str = "input" + self.target_direction: str = "output" + + def target_nc(self) -> str: + return "" + + + +class IoOutputEP(IoEP): + """Endpoint representing an output internal io connections""" + def __init__(self): + super().__init__() + self.source_direction: str = "output" + self.target_direction: str = "input" + + def target_nc(self) -> str: + return "1'b0" + +class IoOutputEnEP(IoEP): + """Endpoint representing an output enable internal io connections""" + def __init__(self): + super().__init__() + self.source_direction: str = "output" + self.target_direction: str = "input" + + def target_nc(self) -> str: + return "1'b1" + + + + +MAPPING_DICT = { + 'top' : 'core_v_mini_mcu_pkg::TOP', + 'right' : 'core_v_mini_mcu_pkg::RIGHT', + 'bottom' : 'core_v_mini_mcu_pkg::BOTTOM', + 'left' : 'core_v_mini_mcu_pkg::LEFT' +} + +CELL_PATTERNS = { +PadType.INPUT: +""" + pad_cell_input #( + .PADATTR({attr_bits}), + .SIDE({side}) + ) pad_{name}_i ( + .pad_in_i(1'b0), + .pad_oe_i(1'b0), + .pad_out_o({in}), + .pad_io({io_signal}), + .pad_attributes_i({attr}) + ); +""", +PadType.OUTPUT: +""" + pad_cell_output #( + .PADATTR({attr_bits}), + .SIDE({side}) + ) pad_{name}_i ( + .pad_in_i({out}), + .pad_oe_i({out_e}), + .pad_out_o(), + .pad_io({io_signal}), + .pad_attributes_i({attr}) + ); +""", +PadType.INOUT: +""" + pad_cell_inout #( + .PADATTR({attr_bits}), + .SIDE({side}) + ) pad_{name}_i ( + .pad_in_i({out}), + .pad_oe_i({out_e}), + .pad_out_o({in}), + .pad_io({io_signal}), + .pad_attributes_i({attr}) + ); +""" +} + +class Pad: + """ + A class representing a pad or an element of a pad multilpexer. + """ + def __init__(self, name: str, num: int, pad_type: PadType, keep_internal: bool = False, pad_active: PadActive = PadActive.HIGH, num_offset = 0, mapping: str = "top", no_num: bool = False): + """ + + :param str name: the name of the pad + :param int num: the number of pads (width) + :param PadType pad_type: the type of pad. + :param bool keep_internal: keep_internal parameter + :param PadActive pad_active: the level where the pad is active + :param int num_offset: the offset to the pad numbers + :param str mapping: the position of the pad + :param bool no_num: if True the number is not added to the pad signal name. + """ + self._name = name + self._num = num + self._pad_type = pad_type + self._keep_internal = keep_internal + self._pad_type = pad_type + self._pad_active = pad_active + self._num_offset = num_offset + self._mapping = mapping + self._no_num = no_num + + @staticmethod + def from_config(pad_name: str, pad_config: hjson.OrderedDict, in_mux: bool = False) -> "Pad": + """ + Make a pad from a configuration dictionary + + :param str pad_name: the name of the pad + :param hjson.OrderedDict pad_config: the dictionary containing the configuration + :param bool in_mux: signal that the function is called recursively to read multiplexed pads. + :return: A pad or multiplexed pad + :rtype: Pad + """ + if type(pad_name) is not str: + raise TypeError("pad_name should be of type str") + if type(pad_config) is not hjson.OrderedDict: + raise TypeError("pad_config should be of type hjson.OrderdDict") + + num = None + if not "num" in pad_config: + num = 1 + else: + num = to_int(pad_config["num"]) + if num is None: + raise RuntimeError("the num parameter should have an integer") + + if not "type" in pad_config: + raise RuntimeError("pads must have a type field.") + + pad_type_str = pad_config["type"] + pad_type_values = list(map(lambda x: x.value, PadType.__members__.values())) + + if not pad_type_str in pad_type_values: + raise RuntimeError(f"the type of a pad should be one of {pad_type_values}") + pad_type = PadType(pad_type_str) + + no_num = False + if "no_num" in pad_config: + no_num = to_bool(pad_config["no_num"]) + if no_num is None: + raise RuntimeError("no_num should be a boolean") + + keep_internal = False + if "keep_internal" in pad_config: + keep_internal = to_bool(pad_config["keep_internal"]) + if keep_internal is None: + raise RuntimeError("keep_internal should be a boolean") + + pad_active = PadActive.HIGH + if "active" in pad_config: + pad_active_str = pad_config["active"] + pad_active_values = list(map(lambda x: x.value, PadActive.__members__.values())) + if not pad_active_str in pad_active_values: + raise RuntimeError(f"the active field of a pad should be one of {pad_active_values}") + pad_active = PadActive(pad_active_str) + + num_offset = 0 + if "num_offset" in pad_config: + num_offset = to_int(pad_config["num_offset"]) + if num_offset is None: + raise RuntimeError("num_offset field should have an integer as parameter") + + mapping = "top" + if "mapping" in pad_config: + mapping = pad_config["mapping"] + if type(mapping) is not str: + raise RuntimeError("mapping should be a string") + if not mapping in ["left", "right", "top", "bottom"]: + raise RuntimeError("mapping should be bottom, top, left or right") + + if "mux" in pad_config: + if in_mux: + raise RuntimeError("nested muxed pads are not supported.") + + mux_raw = pad_config["mux"] + if type(mux_raw) is not hjson.OrderedDict: + raise RuntimeError("the mux field of a pad should be a dictionary.") + + mux: List[Pad] = [] + for key, value in mux_raw.items(): + if type(key) is not str: + raise RuntimeError("names in the mux field should be strings") + if type(value) is not hjson.OrderedDict: + raise RuntimeError("values in the mux field should be dictionaries") + + mux.append(Pad.from_config(key, value, in_mux=True)) + + return MuxedPad(pad_name, num, pad_type, mux_in=mux, keep_internal=keep_internal, pad_active=pad_active, num_offset=num_offset, mapping=mapping, no_num=no_num) + else: + return Pad(pad_name, num, pad_type, keep_internal, pad_active, num_offset, mapping=mapping, no_num=no_num) + + @staticmethod + def name_to_target_name(name: str, i: int) -> str: + """ + gets the name used for io targets without suffix + + Example: `Pad.name_to_target_name(pad_name, index)+"_i"` + + :param str name: the name of the pad + :param int i: the index of the pad + :return: the name of the target without suffix + :rtype: str + """ + return f"io_pad_target_{name}_{i}" + + def target_name(self, i: int) -> str: + """ + like `name_to_target_name` but relative to the instance + + :param int i: the index of the pad relative to this instance offset + :return: the name of the target without suffix + :rtype: str + """ + return self.name_to_target_name(self._name, i + self._num_offset) + + def io_name(self, i:int) -> str: + """ + Gets the name of the outward going singal. + + :param int i: the index of the pad relative to this instance offset + :return: the name of the outward facing signal. + :rtype: str + """ + suffix = "n" if self._pad_active == PadActive.LOW else "" + suffix += { + PadType.INPUT: "i", + PadType.OUTPUT: "o", + PadType.INOUT: "io", + }[self._pad_type] + + num = f"_{i + self._num_offset}" if not self._no_num else "" + + return f"{self._name}{num}_{suffix}" + + def _internal_pre_route(self, rh: RoutingHelper, node: Node, route_root: bool): + """ + Internal methode for pre routing + """ + for i in range(self._num): + if self._pad_type in [PadType.INPUT, PadType.INOUT]: + rh.add_target(node, self.target_name(i)+"_i", IoInputEP()) + if self._pad_type in [PadType.OUTPUT, PadType.INOUT]: + rh.add_target(node, self.target_name(i)+"_o", IoOutputEP()) + rh.add_target(node, self.target_name(i)+"_oe", IoOutputEnEP()) + + def pre_route(self, rh: RoutingHelper, pad_ring_node: Node): + """ + Task to be done before routing + + :param RoutingHelper rh: the routing helper + :param Node pad_ring_node: the pad ring node + """ + self._internal_pre_route(rh, pad_ring_node, True) + + def _make_pad_cell_tsig(self, i: int) -> str: + """Internal method to get the name of the signals of the pad cells""" + return self.target_name(i) + + def make_pad_cell(self, rh: RoutingHelper, p_node: Node, attr_bits: int) -> str: + """ + Makes the sv code of the pad cells. + + :param RoutingHelper rh: the routing helper + :param Node p_node: the parent node + :param int attr_bits: the number of attr bits + :return: sv code + :rtype: str + """ + pads = "" + for i in range(self._num): + signals = dict() + if self._pad_type in [PadType.INPUT, PadType.INOUT]: + signals["in"] = rh.use_target_as_sv(self._make_pad_cell_tsig(i)+"_i", p_node) + if self._pad_type in [PadType.OUTPUT, PadType.INOUT]: + signals["out"] = rh.use_target_as_sv(self._make_pad_cell_tsig(i)+"_o", p_node) + signals["out_e"] = rh.use_target_as_sv(self._make_pad_cell_tsig(i)+"_oe", p_node) + + pads += CELL_PATTERNS[self._pad_type].format( + name = f"{self._name}_{i}", + **signals, + io_signal = self.io_name(i), + side = MAPPING_DICT[self._mapping], + attr_bits = attr_bits, + attr = f"pad_attributes_i[core_v_mini_mcu_pkg::{self.idx_name(i)}]" if attr_bits != 0 else "'0" + ) + return pads + + def get_name(self) -> str: + """ + :return: the name of this pad + :rtype: str + """ + return self._name + + def get_num(self) -> int: + """ + :return: the number of pads represented by the instance + :rtype: int + """ + return self._num + + def get_type(self) -> PadType: + """ + :return: the type of pad + :rytpe: PadType + """ + return self._pad_type + + def make_root_io_ports(self, internal: bool) -> str: + """ + Makes the sv code for the definition of outwards facing singals. + + :param bool internal: if True this is used to make an internal connection + :return: the sv code + :rtype: str + """ + if self._keep_internal is True and internal is False: + return "" + + out = "" + for i in range(self._num): + out += f"inout wire {self.io_name(i)}," + + return out + + def make_root_io_ports_use(self, internal) -> str: + """ + Makes the sv code for the use of outwards facing singals in module instantiation. + + :param bool internal: if True this is used to make an internal connection + :return: the sv code + :rtype: str + """ + if self._keep_internal is True and internal is False: + return "" + + out = "" + for i in range(self._num): + out += f".{self.io_name(i)}," + + return out + + def idx_name(self, i: int) -> str: + """ + The name used as index in arrays conserning pads + + :param int i: the index of the pad relative to this instance offset + :return: The index name of this pad. + :rtype: str + """ + return f"PAD_{self._name}_{self._num_offset + i}".upper() + + def iterate_pad_index(self) -> Iterable[str]: + """ + Iterate all possible result of `idx_name()` + + :return: an iterator over all index names + :rtype: Iterable[str] + """ + return iter([self.idx_name(i) for i in range(self._num)]) + + + + + +class MuxedPad(Pad): + """ + A representation of a multiplexed pad + """ + def __init__(self, *args, mux_in: List[Pad], **kwargs): + """ + + :param List[Pad] mux_in: list of pads that should act as one multiplexed pad. + :param str name: the name of the pad + :param int num: the number of pads (width) + :param PadType pad_type: the type of pad. + :param bool keep_internal: keep_internal parameter + :param PadActive pad_active: the level where the pad is active + :param int num_offset: the offset to the pad numbers + :param str mapping: the position of the pad + :param bool no_num: if True the number is not added to the pad signal name. + """ + super().__init__(*args, **kwargs) + self._sub_pads = mux_in + + def get_mux_num(self) -> int: + """ + :return the number of multiplexed pads + :rtype: int + """ + return len(self._sub_pads) + + def muxer_connection_name(self, i: int) -> str: + """ + Internal name for connections to the muxer + + :param int i: the index of the pad relative to this instance offset + :return: the name + :rtype: str + """ + return f"muxer_pad_connector_{self._name}_{i + self._num_offset}" + + def pre_route(self, rh: RoutingHelper, pad_ring_node: Node): + for p in self._sub_pads: + p._internal_pre_route(rh, rh.get_root_node(), False) + + + for i in range(self._num): + #rh.add_source(pad_ring_node, self.io_source_name(i), IoRootEP()) + + cname = self.muxer_connection_name(i) + if self._pad_type in [PadType.INPUT, PadType.INOUT]: + rh.add_target(pad_ring_node, cname+"_i", IoInputEP()) + rh.add_source(rh.get_root_node(), cname+"_i", IoInputEP(), to = cname+"_i") + if self._pad_type in [PadType.OUTPUT, PadType.INOUT]: + rh.add_target(pad_ring_node, cname+"_o", IoOutputEP()) + rh.add_source(rh.get_root_node(), cname+"_o", IoOutputEP(), to = cname+"_o") + + rh.add_target(pad_ring_node, cname+"_oe", IoOutputEnEP()) + rh.add_source(rh.get_root_node(), cname+"_oe", IoOutputEnEP(), to = cname+"_oe") + + def _make_pad_cell_tsig(self, i: int) -> str: + return self.muxer_connection_name(i) + + + def _make_muxer_case_entry(self, rh: RoutingHelper, sub_p: Pad, name: str, i: int) -> str: + """Internal methode to help making case entries""" + out = f"{name}: begin\n" + if sub_p._pad_type in [PadType.INPUT, PadType.INOUT]: + sig_periph_in = rh.use_target_as_sv(sub_p.target_name(i)+"_i", rh.get_root_node()) + sig_to_pad_in = rh.use_source_as_sv(self.muxer_connection_name(i)+"_i", rh.get_root_node()) + if sig_periph_in != "": + out += f"{sig_periph_in} = {sig_to_pad_in};" + + if sub_p._pad_type in [PadType.OUTPUT, PadType.INOUT]: + sig_periph_o = rh.use_target_as_sv(sub_p.target_name(i)+"_o", rh.get_root_node()) + sig_to_pad_o = rh.use_source_as_sv(self.muxer_connection_name(i)+"_o", rh.get_root_node()) + sig_periph_oe = rh.use_target_as_sv(sub_p.target_name(i)+"_oe", rh.get_root_node()) + sig_to_pad_oe = rh.use_source_as_sv(self.muxer_connection_name(i)+"_oe", rh.get_root_node()) + out += f"{sig_to_pad_o} = {sig_periph_o};" + out += f"{sig_to_pad_oe} = {sig_periph_oe};" + elif self._pad_type in [PadType.OUTPUT, PadType.INOUT]: + sig_to_pad_o = rh.use_source_as_sv(self.muxer_connection_name(i)+"_o", rh.get_root_node()) + sig_to_pad_oe = rh.use_source_as_sv(self.muxer_connection_name(i)+"_oe", rh.get_root_node()) + out += f"{sig_to_pad_o} = 1'b0;" + out += f"{sig_to_pad_oe} = 1'b0;" + out += "end\n" + return out + + def make_muxer(self, rh: RoutingHelper) -> str: + """ + Make the sv code of multiplexers + + :param RoutingHelper rh: the routing helper + :return: sv code + :rtype: str + """ + out = "" + for i in range(self._num): + out += "always_comb begin\n" + for p in self._sub_pads: + if p.get_type() in [PadType.INPUT, PadType.INOUT]: + sig_periph = rh.use_target_as_sv(p.target_name(i)+"_i", rh.get_root_node()) + if sig_periph == "": + print(f"Warning: {p.target_name(i)+'_i'} is not connected maybe a peripheral is missing.") + else: + out += f"{sig_periph} = 1'b0;" + out += f"unique case (pad_muxes[core_v_mini_mcu_pkg::{self.idx_name(i)}])" + for j, p in enumerate(self._sub_pads): + out += self._make_muxer_case_entry(rh, p, str(j), i) + + out += self._make_muxer_case_entry(rh, self._sub_pads[0], "default", i) + + out += "endcase\n" + out += "end\n\n" + return out + + def iterate_pad_index_with_num(self) -> Iterable[Tuple[str, int]]: + """ + Iterate all possible result of `idx_name()` combined with the internal number + + :return: an iterator over all index names + :rtype: Iterable[Tuple[str, int]] + """ + return iter([(self.idx_name(i), len(self._sub_pads)) for i in range(self._num)]) + + + +class PadManager: + """ + A class managing all pads + """ + def __init__(self): + self._pads: List[Pad] = [] + self._pad_ring_node: Optional[Node] = None + self._attr_bits: int = 0 + + def add_from_config(self, config: hjson.OrderedDict): + """ + Add pads from a configuration file + + :param hjson.OrderedDict config: the configuration file content + """ + self._attr_bits = to_int(config.pop("attributes", {}).pop("bits")) + + if "pads" in config: + for pad, pad_config in config["pads"].items(): + if type(pad) is not str: + raise RuntimeError("pad names should be strings in configuration files") + if type(pad_config) is not hjson.OrderedDict: + raise RuntimeError("pad configuration should be dictionaries.") + + self._pads.append(Pad.from_config(pad, pad_config)) + + @staticmethod + def load(src: str) -> "PadManager": + """ + Creates an instance pased on a configuration file + + :param str src: the content of the hjson file + :return: the pad manager instance + :rtype: PadManager + """ + manager = PadManager() + + config = hjson.loads(src, parse_int=int, object_pairs_hook=hjson.OrderedDict) + manager.add_from_config(config) + + return manager + + def pre_route(self, rh: RoutingHelper): + """ + Task to be done before routing + + :param RoutingHelper rh: the routing helper + """ + self._pad_ring_node = Node("pad_ring", rh.get_root_node().name) + rh.register_node(self._pad_ring_node) + + for pad in self._pads: + pad.pre_route(rh, self._pad_ring_node) + + def make_pad_cells(self, rh: RoutingHelper) -> str: + """ + Makes the sv code of the pad cells. + + :param RoutingHelper rh: the routing helper + :return: sv code + :rtype: str + """ + out = "" + for p in self._pads: + out += p.make_pad_cell(rh, self._pad_ring_node, self._attr_bits) + out += "\n\n" + + return out + + def make_muxers(self, rh: RoutingHelper) -> str: + """ + Makes the sv code of the multiplexers. + + :param RoutingHelper rh: the routing helper + :return: sv code + :rtype: str + """ + out = "" + for p in self._pads: + if isinstance(p, MuxedPad): + out += p.make_muxer(rh) + + return out + + def make_root_io_ports(self, internal=False) -> str: + """ + Makes the sv code for the definition of outwards facing singals. + + :param bool internal: if True this is used to make an internal connection + :return: the sv code + :rtype: str + """ + out = "" + for p in self._pads: + out += p.make_root_io_ports(internal) + return out + + def make_root_io_ports_use(self, internal=False) -> str: + """ + Makes the sv code for the use of outwards facing singals in module instantiation. + + :param bool internal: if True this is used to make an internal connection + :return: the sv code + :rtype: str + """ + out = "" + for p in self._pads: + out += p.make_root_io_ports_use(internal) + return out + + + def get_pad_ring_node(self) -> Node: + """ + Get the node of the pad_ring + + :return: the pad_ring node + :rtype: Node + """ + return deepcopy(self._pad_ring_node) + + def iterate_pad_index(self) -> Iterable[str]: + """ + Iterate all possible pad index name + + :return: an iterator over all index names + :rtype: Iterable[Tuple[str, int]] + """ + return chain.from_iterable([p.iterate_pad_index() for p in self._pads]) + + def iterate_muxed_pad_index(self) -> Iterable[str]: + """ + Iterate all possible muxed pad index name + + :return: an iterator over all index names + :rtype: Iterable[Tuple[str, int]] + """ + return chain.from_iterable([p.iterate_pad_index() for p in filter(lambda p: isinstance(p, MuxedPad), self._pads)]) + + def iterate_muxed_pad_index_with_num(self) -> Iterable[Tuple[str, int]]: + """ + Iterate all possible muxed pad index name, with the width of each name + + :return: an iterator over all index names + :rtype: Iterable[Tuple[str, int]] + """ + return chain.from_iterable([p.iterate_pad_index_with_num() for p in filter(lambda p: isinstance(p, MuxedPad), self._pads)]) + + def get_pad_num(self) -> int: + """ + :return: the number of pads in the system + :rtype: int + """ + count = 0 + for p in self._pads: + count += p.get_num() + return count + + def get_muxed_pad_num(self) -> int: + """ + :return: the number of muxed pads in the system + :rtype: int + """ + count = 0 + for p in filter(lambda p: isinstance(p, MuxedPad), self._pads): + count += p.get_num() + return count + + def get_attr_bits(self) -> int: + """ + :return: the number of attr_bits + :rtype: int + """ + return self._attr_bits + + def get_mk_ctrl(self) -> bool: + """ + :return: shortcut to test if muxed pads are present or attributes bits are used. + :rtype: bool + """ + return self.get_muxed_pad_num() > 0 or self.get_attr_bits() != 0 + + def get_max_mux_bitlengh(self) -> int: + """ + :return: the maximum number of bits needed for all muxed pads control + :rtype: int + """ + pads = filter(lambda p: isinstance(p, MuxedPad), self._pads) + return (max([p.get_mux_num() for p in pads])-1).bit_length() \ No newline at end of file diff --git a/util/x_heep_gen/peripherals/__init__.py b/util/x_heep_gen/peripherals/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/util/x_heep_gen/peripherals/basic_peripheral.py b/util/x_heep_gen/peripherals/basic_peripheral.py new file mode 100644 index 000000000..12555b540 --- /dev/null +++ b/util/x_heep_gen/peripherals/basic_peripheral.py @@ -0,0 +1,400 @@ +from dataclasses import * +from typing import Dict, Generator, Iterable, List, Optional, Union + +import reggen +from reggen.ip_block import IpBlock + +from .sv_helper import SvSignal +from ..pads import IoInputEP, IoOutputEP, IoOutputEnEP, Pad +from ..signal_routing.node import Node +from ..signal_routing.routing_helper import RoutingHelper +from ..signal_routing.endpoints import InterruptEP, InterruptPlicEP + + + +class BasicPeripheral: + """ + A class representing peripherals in general. + + This class is manly used through `@peripheral_from_file`. + + :param Optional[str] name: the base name of the peripheral + :param Optional[str] domain: the name of the domain + :param Optional[int] offset: the address offset relative to the peripheral domain. + :param Optional[int] addr_size: the amount of space that should be used for this peripheral. + """ + def __init__(self, name: "str|None" = None, domain: "str|None" = None, offset: Optional[int] = None, addr_size: Optional[int] = None): + self.name: str|None = name + """The name of the peripheral""" + + self._sp_name_suffix: str|None = self.name + + self.domain: str|None = domain + """ + The name of the domain the peripheral is in. + + This will be set by `PeripheralDomain`. + """ + + self._offset: Optional[int] = offset + self._addr_size: Optional[int] = addr_size + + self._ip_block: Optional[IpBlock] = None + self._ip_block_path: Optional[str] = None + + self.io_local_idx: Optional[int] = None + + self.interrupt_dest: Union[str, Dict[str, str]] = "plic" + self.interrupt_handler: Dict[str, str] = dict() + self.interrupt_handler_base: Dict[str, str] = dict() + + + @property + def name(self) -> str: + return self._name + + @property + def full_name(self) -> str: + """The name with it's suffix, how it will actually be used in the generated output.""" + if self._sp_name_suffix is not None and self._sp_name_suffix != "": + return f"{self._name}_{self._sp_name_suffix}" + return self.name + + @name.setter + def name(self, value: "str|None"): + if type(value) is not str and value is not None: + raise TypeError("value should be of type str") + + self._name = value + + @property + def domain(self) -> str: + return self._domain + + @domain.setter + def domain(self, value: "str|None"): + if type(value) is not str and value is not None: + raise TypeError("value should be of type str") + + self._domain = value + + + + + def set_specialized_name(self, suffix: str): + """ + Set the the suffix of the name. + + :param str suffix: suffix of the name + :raise TypeError: if argument does not have the right type. + """ + if type(suffix) is not str: + raise TypeError("argument suffix should be of type str") + self._sp_name_suffix = suffix + + + def specialize_name(self, n: int) -> int: + """ + Adds a name suffix to the name based on the integer provided. + + To specialize this methode in a subclass `set_specialized_name` can be overriden. + + :param int n: number to be suffixed + :return: next value for this name, here n+1, but a subclass could do a bigger increment + :rtype: int + :raise TypeError: if argument does not have the right type. + """ + if type(n) is not int: + raise TypeError("argument n should be of type int") + self.set_specialized_name(str(n)) + return n + 1 + + def _intr_sig_name(self, sig: reggen.signal.Signal) -> str: + """ + Methode providing the name of the interrupt sources. + """ + return f"{self.name}_{self._sp_name_suffix}_{sig.name}_intr" + + def _io_sig_name(self, sig: List[dict]) -> str: + """ + Methode providing the name of io sources. + """ + return f"{self.name}{self._sp_name_suffix}_{sig['name']}" + + def register_connections(self, rh: RoutingHelper, p_node: Node): + """ + register connections for this peripheral. + + :param RoutingHelper rh: the routing helper + :param Node p_node: the parent node. + """ + self._p_node = p_node + if self._ip_block is None: + raise RuntimeError("No ip block configured") + + for sig in self._ip_block.interrupts: + if type(self.interrupt_dest) is str: + intr_dest = self.interrupt_dest + elif type(self.interrupt_dest) is dict: + intr_dest = self.interrupt_dest[sig.name] + else: + raise NotImplementedError() + + handler_suffix = "" + if sig.name in self.interrupt_handler: + handler_suffix = f"{self.interrupt_handler[sig.name]}" + + handler_name = self.full_name + if sig.name in self.interrupt_handler_base: + handler_name = f"{self.interrupt_handler_base[sig.name]}" + + EP = None + if intr_dest == "fast": + EP = InterruptEP(handler=f"fic_irq_{handler_name}{handler_suffix}") + elif intr_dest == "plic": + EP = InterruptPlicEP(handler=f"handler_irq_{handler_name}{handler_suffix}") + else: + raise NotImplementedError(f"interrupt destination {self.interrupt_dest} is not implemented") + + rh.add_source(p_node, self._intr_sig_name(sig), EP) + + for sig in self.get_io_connections(): + for i in range(sig["width"]): + iosn = self._io_sig_name(sig) + if sig["type"] in ["input", "inout"]: + rh.add_source(p_node, f"{iosn}{i}_i", IoInputEP(), to=Pad.name_to_target_name(iosn, i)+"_i") + if sig["type"] in ["output", "inout", "output_no_en"]: + rh.add_source(p_node, f"{iosn}{i}_o", IoOutputEP(), to=Pad.name_to_target_name(iosn, i)+"_o") + if sig["type"] in ["output", "inout"]: + rh.add_source(p_node, f"{iosn}{i}_oe", IoOutputEnEP(), to=Pad.name_to_target_name(iosn, i)+"_oe") + + + + def make_instantiation_connections(self, rh: RoutingHelper) -> str: + """ + Make the connections for the sv code. + + This function can be overriden to add more signals. Generally the content of this function should be prepended. + + :param routingHelper rh: The routing helper + :return: the connections to the periperhals in sv with trainling comma. + :rtype: str + """ + if self._ip_block is None: + raise RuntimeError("No ip block configured") + + inst: str = ".clk_i(clk_cg)," + inst += ".rst_ni," + + for sig in self._ip_block.interrupts: + lsig_name = rh.use_source_as_sv(self._intr_sig_name(sig), self._p_node) + inst += f".intr_{sig.name}_o({lsig_name})," + + inst += self._make_io_connections(rh) + + return inst + + def make_instantiation_generics(self) -> List[str]: + """ + Get the generics used for the instantiation + + This should be overriden to add generics. + + :return: a list of parameters in sv. + :rtype: List[str] + """ + return [] + + def make_instantiation(self, rh: RoutingHelper) -> str: + """ + Make the sv code for this peripheral. + + This function can be extended to add other modules, or other things needed in sv in order to use this peripheral. + Example `TLULPeripheral`. + + :param routingHelper rh: The routing helper + :return: the connections to the periperhal. + :rtype: str + """ + if self._ip_block is None: + raise RuntimeError("No ip block configured") + + inst: str = self.name + + generics = self.make_instantiation_generics() + if len(generics) != 0: + generics = [f".{g}" for g in generics] + inst += "#(" + inst += ','.join(generics) + inst += ")" + + inst += f" {self.name}_{self._sp_name_suffix}_i(" + + inst += self.make_instantiation_connections(rh) + + if inst[-1] == ',': + inst = inst[:-1] + + inst += ");" + + return inst + + def make_local_signals(self) -> Iterable[SvSignal]: + """ + make signals for use only in the peripheral domain. + + For new things the routing helper should be prefered. + """ + return iter([]) + + + def get_io_connections(self) -> List[Dict]: + """ + Get io connections. + + This should be overriden to add new or missing io_connections. + + The `type`, `name` and `width` entry from the dictionaries are used. + + :return: a list of dictionaries + :rtype: List[Dict] + """ + return self._ip_block.get_signals_as_list_of_dicts() + + def get_io_prefix(self) -> str: + """ + :return: the perfix for io signals. + :rtype: str + + This should be overriden if the default does not match the rtl code. + """ + return "cio_" + + def get_io_suffix(self) -> Dict[str, str]: + """ + :return: the suffixes for io signals. + :rtype: Dict[str,str] + + This should be overriden if the default does not match the rtl code. + The fileds that are required are `"i"`, `"o"` and `"oe"` + """ + return {"i": "i", "o": "o", "oe": "en_o"} + + + def _make_io_connections(self, rh: RoutingHelper) -> str: + """ + Internal methode to make io connections, + Override instead, `get_io_connections, `get_io_prefix` and `get_io_suffix`. + """ + inst: str = "" + for sig in self.get_io_connections(): + name = sig["name"] + t = sig["type"] + subs = [] + if t == "inout" or t == "input": + subs.append("i") + if t == "inout" or t == "output" or t == "output_no_en": + subs.append("o") + if t == "inout" or t == "output": + subs.append("oe") + for sub in subs: + snames = [ + rh.use_source_as_sv(f"{self._io_sig_name(sig)}{i}_{sub}", self._p_node) + for i in range(sig["width"]) + ] + snames = ','.join(snames[::-1]) + if sig["width"] > 1: + snames = f"{{{snames}}}" + inst += f".{self.get_io_prefix()}{name}_{self.get_io_suffix()[sub]}({snames})," + + return inst + + + def get_addr_bits(self) -> int: + """ + :return: the number of address bits used by this peripehral + :rtype: int + """ + if self._ip_block is None: + raise RuntimeError("No ip block configured") + + length = 0 + found = False + for _, b in self._ip_block.reg_blocks.items(): + length = b.get_addr_width() + if found: + raise RuntimeError("IP has mor than one register block") + found = True + + return length + + def get_min_length(self) -> int: + """ + :return: The minimum address space needed by this peripheral. + :rtype: int + """ + return 2**max(self.get_addr_bits(), 2) + + def addr_setup(self): + """ + Sets up the address of the peripheral + """ + if self._addr_size is None: + self._addr_size = self.get_min_length() + + elif self._addr_size < self.get_min_length(): + raise RuntimeError(f"A length of 0x{self._addr_size} was request for peripheral {self._name} {self._sp_name_suffix} but a length of at least {self.get_min_length()} is required.") + + def get_offset(self) -> Optional[int]: + """ + :return: The offset relative to the domain + :rtype: Optional[int] + """ + return self._offset + + def get_offset_checked(self) -> int: + """ + :return: The offset relative to the domain, if already set. + :rtype: Optional[int] + :raise RuntimeError: if the offset is not set yet. + """ + if type(self._offset) is not int: + raise RuntimeError("checked failed offset is not set properly") + return self._offset + + def get_address_length(self) -> Optional[int]: + """ + :return: the address length + :rtype: Optional[int] + """ + return self._addr_size + + def get_address_length_checked(self) -> int: + """ + :return: The address length, if already set. + :rtype: Optional[int] + :raise RuntimeError: if the address length is not set yet. + """ + if type(self._addr_size) is not int: + raise RuntimeError("checked failed address size is not set properly") + return self._addr_size + + def set_offset(self, offset: int): + """ + Set the offset of this peripheral. + + It should be aligned to the size. + The rtl can not know how this is aligned either. + + :param int offset: the offset + """ + self._offset = offset + + def get_ip_path(self) -> Optional[str]: + """ + Get the path of the file descibing this peripheral. + + :return: The path, if present + :rtype: Optional[str] + """ + return self._ip_block_path \ No newline at end of file diff --git a/util/x_heep_gen/peripherals/fixed_peripheral.py b/util/x_heep_gen/peripherals/fixed_peripheral.py new file mode 100644 index 000000000..0451f55ed --- /dev/null +++ b/util/x_heep_gen/peripherals/fixed_peripheral.py @@ -0,0 +1,49 @@ +from typing import Any, Dict, Optional + +import hjson +from .basic_peripheral import BasicPeripheral +from .peripheral_helper import PeripheralConfigFactory, add_peripheral_factory, ip_block_paths +from ..signal_routing.node import Node +from ..signal_routing.routing_helper import RoutingHelper + +class FixedPeripheralFactory(PeripheralConfigFactory): + def dict_to_kwargs(self, d: hjson.OrderedDict) -> Dict[str, Any]: + ret = dict() + if "name" in d: + ret["name"] = d.pop("name") + else: + raise RuntimeError("name is mandatory in fixed peripheral") + + if "suffix" in d: + ret["suffix"] = d.pop("suffix") + + ret.update(super().dict_to_kwargs(d)) + return ret +class FixedPeripheral(BasicPeripheral): + """ + A special kind of peripheral for hte fixed domain. + + name offset and address siue have to be set. + """ + def __init__(self, name: str, domain: Optional[str] = None, *, offset: int, addr_size: int, suffix: str = ""): + if offset is None: + raise RuntimeError("fixed peripherals must have the offset set.") + if addr_size is None: + raise RuntimeError("fixed peripherals must have addr_size set.") + + super().__init__(name, domain, offset, addr_size) + + self._sp_name_suffix = suffix + + for p in ip_block_paths: + if p.endswith(f"{name}.hjson"): + self._ip_block_path = p + + + def register_connections(self, rh: RoutingHelper, p_node: Node): + pass + + def set_specialized_name(self, suffix: str): + pass + +add_peripheral_factory("fixed", FixedPeripheralFactory, FixedPeripheral) \ No newline at end of file diff --git a/util/x_heep_gen/peripherals/gpio.py b/util/x_heep_gen/peripherals/gpio.py new file mode 100644 index 000000000..5037f153e --- /dev/null +++ b/util/x_heep_gen/peripherals/gpio.py @@ -0,0 +1,131 @@ +from typing import Any, Dict + +import hjson +from .peripheral_helper import PeripheralConfigFactory, peripheral_from_file +from ..config_helpers import to_int +from ..pads import IoInputEP, IoOutputEP, IoOutputEnEP, Pad +from ..signal_routing.endpoints import InterruptEP, InterruptPlicEP +from ..signal_routing.node import Node +from ..signal_routing.routing_helper import RoutingHelper + +class GpioPeripheralConfigFactory(PeripheralConfigFactory): + """ + A class adding configuration information for gpio peripherals. + """ + def dict_to_kwargs(self, d: hjson.OrderedDict) -> Dict[str, Any]: + ret = dict() + + gpios_used = {} + io_offset = 0 + if "io_offset" in d: + io_offset = to_int(d.pop("io_offset")) + if io_offset is None: + raise RuntimeError("io_offset should be an integer") + + if "gpios_used" in d: + gu = d.pop("gpios_used") + if isinstance(gu, list): + for g in gu: + g = to_int(g) + if g is None: + raise RuntimeError("gpio numbers should be integers") + gpios_used[g] = g + io_offset + + elif isinstance(gu, hjson.OrderedDict): + if io_offset != 0: + print("Warning: io_offset is not used for dictionaries in gpio config") + for k, v in gu.items(): + k = to_int(k) + v = to_int(v) + if v is None or k is None: + raise RuntimeError("gpio numbers should be integers") + gpios_used[k] = v + + elif gu == "full": + gpios_used.update({i:i+io_offset for i in range(32)}) + + elif gu == "range": + start = to_int(d.pop("start", 0)) + end = to_int(d.pop("end", 31)) + if end is None or start is None or start < 0 or end > 31 or start > end: + raise RuntimeError("start and end should be integers, in range 0-31, start <= end") + gpios_used.update({i:i+io_offset for i in range(start, end+1)}) + + else: + raise RuntimeError("gpios_used should either be a dictionary, a list, range or full") + + intr = d.pop("intr", "plic") + if not intr in ["plic", "fast"]: + raise RuntimeError("intr parameter of gpio should either be fast or plic") + + intr_map = {i:intr for i in gpios_used.values()} + + ret["intr_map"] = intr_map + ret["gpios_used"] = gpios_used + + ret.update(super().dict_to_kwargs(d)) + return ret + +@peripheral_from_file("./hw/vendor/pulp_platform_gpio/gpio_regs.hjson", config_factory_t=GpioPeripheralConfigFactory) +class GpioPeripheral(): + """ + A class representing a gpio peripheral. + + :param Dict[int, int] gpios_used: a dictionairy mapping internal numbers to external number used for port names, a missing number is an unconnected number. Default to `{}`. + :param Dict[int, str] intr_map: a dictionary mapping internal oi numbers to interrupt destinations, the destination are either `"fast"` or `"plic"`, defaults to `"plic"` for each io used in `gpios_used`. + """ + def __init__(self, *args, **kwargs) -> None: + self._gpios_used: Dict[int, int] = kwargs.pop("gpios_used", {}) + self._intr_map: Dict[int, str] = kwargs.pop("intr_map", {i:"plic" for i in self._gpios_used.values()}) + super().__init__(*args, **kwargs) + + def register_connections(self, rh: RoutingHelper, p_node: Node): + super().register_connections(rh, p_node) + for p_num, io_num in self._gpios_used.items(): + rh.add_source(p_node, Pad.name_to_target_name("gpio", io_num)+"_i", IoInputEP(), Pad.name_to_target_name("gpio", io_num)+"_i") + rh.add_source(p_node, Pad.name_to_target_name("gpio", io_num)+"_o", IoOutputEP(), Pad.name_to_target_name("gpio", io_num)+"_o") + rh.add_source(p_node, Pad.name_to_target_name("gpio", io_num)+"_oe", IoOutputEnEP(), Pad.name_to_target_name("gpio", io_num)+"_oe") + + if self._intr_map[io_num] == "fast": + rh.add_source(p_node, f"gpio_{io_num}_intr", InterruptEP(handler=f"fic_irq_gpio_{io_num}_intr")) + elif self._intr_map[io_num] == "plic": + rh.add_source(p_node, f"gpio_{io_num}_intr", InterruptPlicEP(handler=f"handler_irq_gpio_{io_num}_intr")) + + + def make_instantiation(self, rh: RoutingHelper) -> str: + out = "" + out += f"logic [32-1:0] {self.name}_{self._sp_name_suffix}_intr;" + out += f"logic [32-1:0] {self.name}_{self._sp_name_suffix}_in;" + out += f"logic [32-1:0] {self.name}_{self._sp_name_suffix}_out;" + out += f"logic [32-1:0] {self.name}_{self._sp_name_suffix}_out_en;" + + for i in range(32): + if i in self._gpios_used: + io_num = self._gpios_used[i] + intr_sig = rh.use_source_as_sv(f"gpio_{io_num}_intr", self._p_node) + in_sig = rh.use_source_as_sv(Pad.name_to_target_name("gpio", io_num)+"_i", self._p_node) + out_sig = rh.use_source_as_sv(Pad.name_to_target_name("gpio", io_num)+"_o", self._p_node) + oe_sig = rh.use_source_as_sv(Pad.name_to_target_name("gpio", io_num)+"_oe", self._p_node) + + + out += f"assign {intr_sig} = {self.name}_{self._sp_name_suffix}_intr[{i}];" + out += f"assign {self.name}_{self._sp_name_suffix}_in[{i}] = {in_sig};" + out += f"assign {out_sig} = {self.name}_{self._sp_name_suffix}_out[{i}];" + out += f"assign {oe_sig} = {self.name}_{self._sp_name_suffix}_out_en[{i}];" + else: + out += f"assign {self.name}_{self._sp_name_suffix}_in[{i}] = 1'b0;" + + out += "\n\n" + + return out + super().make_instantiation(rh) + + def make_instantiation_connections(self, rh: RoutingHelper) -> str: + out = "" + out += f".gpio_in({self.name}_{self._sp_name_suffix}_in)," + out += f".gpio_out({self.name}_{self._sp_name_suffix}_out)," + out += f".gpio_tx_en_o({self.name}_{self._sp_name_suffix}_out_en)," + out += f".gpio_in_sync_o()," + out += f".pin_level_interrupts_o({self.name}_{self._sp_name_suffix}_intr)," + out += f".global_interrupt_o()," + + return super().make_instantiation_connections(rh) + out \ No newline at end of file diff --git a/util/x_heep_gen/peripherals/i2s.py b/util/x_heep_gen/peripherals/i2s.py new file mode 100644 index 000000000..875845057 --- /dev/null +++ b/util/x_heep_gen/peripherals/i2s.py @@ -0,0 +1,70 @@ + +from typing import Any, Dict, List + +import hjson +from .peripheral_helper import PeripheralConfigFactory, peripheral_from_file +from ..config_helpers import to_bool +from ..signal_routing.endpoints import DmaTriggerEP +from ..signal_routing.node import Node +from ..signal_routing.routing_helper import RoutingHelper + +class I2SConfigFactory(PeripheralConfigFactory): + """ + A class adding configureation information for i2s peripherals. + """ + def dict_to_kwargs(self, d: hjson.OrderedDict) -> Dict[str, Any]: + ret = dict() + dma = None + if "dma" in d: + dma = to_bool(d.pop("dma")) + if dma is None: + raise RuntimeError("dma parameter should be a boolean.") + else: + raise RuntimeError("i2s require the dma argument to be set") + + ret["dma"] = dma + + ret.update(super().dict_to_kwargs(d)) + return ret + +@peripheral_from_file("./hw/ip/i2s/data/i2s.hjson", config_factory_t=I2SConfigFactory) +class I2SPeripheral(): + """ + A peripheral used to represent an `i2s` periperhal. + + :param bool dma: should the dma triggers be connected? + """ + def __init__(self, *args, **kwargs): + if not "dma" in kwargs: + raise TypeError("dma keyword argument is required") + self._i2s_uses_dma: bool = kwargs.pop("dma") + if type(self._i2s_uses_dma) is not bool: + raise RuntimeError("dma flag should be of type bool") + super().__init__(*args, **kwargs) + + def register_connections(self, rh: RoutingHelper, p_node: Node): + super().register_connections(rh, p_node) + if self._i2s_uses_dma: + rh.add_source(p_node, f"{self.name}_{self._sp_name_suffix}_rx", DmaTriggerEP()) + + def get_io_prefix(self) -> str: + return "i2s_" + + def get_io_connections(self) -> List[Dict]: + d = [ + {"name": "sck", "type": "inout", "width": 1}, + {"name": "ws" , "type": "inout", "width": 1}, + {"name": "sd" , "type": "inout", "width": 1}, + ] + return d + + def make_instantiation_connections(self, rh: RoutingHelper) -> str: + out = "" + if self._i2s_uses_dma: + out += f".i2s_rx_valid_o({rh.use_source_as_sv(f'{self.name}_{self._sp_name_suffix}_rx', self._p_node)})," + else: + out += ".i2s_rx_valid_o()," + return super().make_instantiation_connections(rh) + out + + def get_io_suffix(self) -> Dict[str, str]: + return {"i": "i", "o": "o", "oe": "oe_o"} \ No newline at end of file diff --git a/util/x_heep_gen/peripherals/pdm2pcm.py b/util/x_heep_gen/peripherals/pdm2pcm.py new file mode 100644 index 000000000..e169a631e --- /dev/null +++ b/util/x_heep_gen/peripherals/pdm2pcm.py @@ -0,0 +1,18 @@ +from typing import Dict, List +from .peripheral_helper import peripheral_from_file + + +@peripheral_from_file("./hw/ip/pdm2pcm/data/pdm2pcm.hjson") +class Pdm2PcmPeripheral(): + """ + A class representing a `pdm2pcm` peripheral. + """ + def get_io_prefix(self) -> str: + return "" + + def get_io_connections(self) -> List[Dict]: + d = [ + {"name": "pdm", "type": "input", "width": 1}, + {"name": "pdm_clk" , "type": "output_no_en", "width": 1}, + ] + return d \ No newline at end of file diff --git a/util/x_heep_gen/peripherals/peripheral_domain.py b/util/x_heep_gen/peripherals/peripheral_domain.py new file mode 100644 index 000000000..b7fe9b335 --- /dev/null +++ b/util/x_heep_gen/peripherals/peripheral_domain.py @@ -0,0 +1,217 @@ +from copy import deepcopy +from typing import Dict, Iterable, List, Optional, Tuple + +from .sv_helper import SvSignal, SvSignalArray +from .basic_peripheral import BasicPeripheral +from ..signal_routing.node import Node +from ..signal_routing.routing_helper import RoutingHelper + +class PeripheralDomain: + """ + A peripheral domain + + :param str name: + :param int address: the base address used to address this domain. + :param int addr_size: the size reserved for this peripheral domain. + :param bool has_clock_domain: Flag to tell if the domain should have it's own clock domain (currently unused) + """ + def __init__(self, name: str, address: int, addr_size: int, has_clock_domain: bool = False): + if type(name) is not str: + raise TypeError("name should be of type str") + if name == "": + raise ValueError("name should not be empty") + self._name: str = name + self._peripherals: List[BasicPeripheral] = [] + self._io_ifs: Dict[str, SvSignalArray] = {} + self._io_if_offsets: Dict[str, int] = {} + self._node: Optional[Node] = None + + self._address: int = address + self._addr_size: int = addr_size + self._type: str = "normal" + self._has_clock_domain: bool = has_clock_domain + + def get_type(self) -> str: + """ + get the type of the domain + + :return: the kind of domain either `"normal"` or `"fixed"` + :rtype: str + """ + return self._type + + def add_peripheral(self, p: BasicPeripheral): + """ + Add a peripheral to this domain. + + The peripheral is copied, further changes to this peripheral will not be taken in account. + The smae peripheral can also be added multiple times. + + :param BasicPeripheral p: The peripheral to add + """ + if not isinstance(p, BasicPeripheral): + raise TypeError("peripheral should be an instance of BasicPeripheral") + + if p.name is None or len(p.name) == 0: + raise RuntimeError("The peripheral should get a name before it is added to a PeripheralDomain object") + + new_p = deepcopy(p) + new_p.domain = self._name + self._peripherals.append(new_p) + + def specialize_names(self, used_names: "Dict[str, int]"): + """ + This method sets suffixes for the peripheral name. + + :param Dict[str, int] used_names: the dictionary with the last suffix for each peripheral base name. + """ + for p in self._peripherals: + n = 0 + base_name = p.name + if base_name in used_names: + n = used_names.get(base_name) + + n = p.specialize_name(n) + + used_names.update({base_name: n}) + + + def get_name(self) -> str: + """ + :return: the name of the domain + :rtype: str + """ + return self._name + + + def iter_peripherals(self) -> Iterable[BasicPeripheral]: + """ + iterate through all peripherals + + :return: an iterator of peripherals + :rtype: Iterable[BasicPeripheral] + """ + return iter(self._peripherals) + + def register_connections(self, rh: RoutingHelper, p_node: Node): + """ + Register all connections for this domain and peripherals. + + :param RoutingHelper rh: the routing helper + :param Node p_node: the parent node. + """ + node = Node("pd_" + self.get_name(), p_node.name) + rh.register_node(node) + self._node = node + + for p in self._peripherals: + p.register_connections(rh, node) + + def build(self): + """ + Does build operations for this peripheral domain. + """ + pass + + def peripheral_count(self) -> int: + """ + :return: the number of peripherals + :rtype: int + """ + return len(self._peripherals) + + def get_node(self) -> Node: + """ + :return: The domains node. + :rtype: Node + """ + if self._node is None: + raise RuntimeError("Node is not registered yet") + + return deepcopy(self._node) + + def get_address(self) -> int: + """ + :return: the base address of this domain + :rtype: int + """ + return self._address + + def get_address_length(self) -> int: + """ + :return: the amount of address reserved for this domain + :rtype: int + """ + return self._addr_size + + def addr_setup(self): + """ + Does the callculation and for all addresses of the peripherals. + """ + reserved: List[Tuple[int, int, int]] = [] + missing: List[Tuple[int, int]] = [] + for i, p in enumerate(self._peripherals): + p.addr_setup() + ab = p.get_addr_bits() + offset = p.get_offset() + size = p.get_address_length() + + if offset is not None: + if ((self._address + offset) & (2**ab - 1)) != 0: + raise RuntimeError("peripheral offset is not aligned") + reserved.append((offset, offset + size, i)) + else: + missing.append((size, i)) + + reserved.sort() + missing.sort(key=lambda x: x[0], reverse=True) # we sort the peripherals that do not have an offset + + for (_, end, i), (start, _, j) in zip(reserved, reserved[1:]): + if start < end: + raise RuntimeError(f"peripheral {self._peripherals[i].name} and {self._peripherals[j].name} have overlapping memory range") + + + for _, p_idx in missing: + p = self._peripherals[p_idx] + ab = p.get_addr_bits() + size = p.get_address_length() + for (_, end, _), (start, _, j) in zip(reserved, reserved[1:]): + if ((end + self._address) & (2**ab - 1)) != 0: + end = ((end + self._address) | 2**ab - 1) + 1 - self._address # align potential start address + + if end + size <= start: + reserved.insert(j, (end, end + size, p_idx)) + break + else: + end = 0 + if len(reserved) > 0: + end = reserved[-1][1] + if ((end + self._address) & (2**ab - 1)) != 0: + end = ((end + self._address) | 2**ab - 1) + 1 - self._address # align potential start address + reserved.append((end, end + size, p_idx)) + + for offset, _, p_idx in reserved: + p = self._peripherals[p_idx] + p.set_offset(offset) + + def has_clock_domain(self) -> bool: + """ + :retrurn: if this peripheral domain has a clock domain + :rtype: bool + """ + return self._has_clock_domain + +class FixedDomain(PeripheralDomain): + """ + A peripheral domain type for the `ao_peripheral` domain + + Should not be used for something else. + """ + def __init__(self, name: str, address: int, addr_size: int): + super().__init__(name, address, addr_size) + self._type = "fixed" + + def specialize_names(self, used_names: Dict[str, int]): + pass + def addr_setup(self): + pass \ No newline at end of file diff --git a/util/x_heep_gen/peripherals/peripheral_helper.py b/util/x_heep_gen/peripherals/peripheral_helper.py new file mode 100644 index 000000000..ebb67c0a7 --- /dev/null +++ b/util/x_heep_gen/peripherals/peripheral_helper.py @@ -0,0 +1,131 @@ + +import functools +from typing import Any, Dict, List, Optional, Set, Type +import hjson +import os +from reggen.bus_interfaces import BusProtocol +from reggen.ip_block import IpBlock + +from ..config_helpers import to_int +from .basic_peripheral import BasicPeripheral +from .reg_iface_peripheral import RegIfacePeripheral +from .tlul_peripheral import TLULPeripheral + +ip_block_paths: Set[str] = { # prefill with fixed only peripherals + "./hw/ip/fast_intr_ctrl/data/fast_intr_ctrl.hjson", + "./hw/ip/power_manager/data/power_manager.hjson", + "./hw/ip/dma/data/dma.hjson", + "./hw/ip/soc_ctrl/data/soc_ctrl.hjson" +} +"""All the paths used to make peripherals headers""" + +class PeripheralConfigFactory(): + """ + A class providing individual peripheral configuration options. + + Peripheral makers should implement `dict_to_kwargs` to parse additional parameters. If `__init__` is overriden `super()` has to be called or its functionality has to be replaced. + + :param Type[BasicPeripheral]: The type of the peripheral to configure. + """ + def __init__(self, t: Type[BasicPeripheral]) -> None: + self.t = t + + def dict_to_kwargs(self, d: hjson.OrderedDict) -> Dict[str, Any]: + """ + Converts a dictionary of parameters to a dictionary of kwargs to create the peripheral class. + + Here the parameters can be checked a first time. + + This provides an implementation for `offset` and `length`parameter. + + :param hjson.OrderedDict d: + :return: kwargs + :rtype: Dict[str, Any] + """ + ret = dict() + if "offset" in d: + addr = to_int(d.pop("offset")) + if addr is None: + raise RuntimeError("If address is provided it should be an integer") + ret["offset"] = addr + + if "length" in d: + length = to_int(d.pop("length")) + if length is None: + raise RuntimeError("If address is provided it should be an integer") + ret["addr_size"] = length + + return ret + + + def from_odict(self, p_dict: hjson.OrderedDict) -> BasicPeripheral: + """ + Creates the peripheral instance based on a config file dictionary. + + :param hjson:OrderedDict p_dict: parameters + :return: The peripheral instance. + :rtype: BasicPeripheral + """ + return self.t(**self.dict_to_kwargs(p_dict)) + + +peripheral_factories: Dict[str, PeripheralConfigFactory] = dict() +def add_peripheral_factory(name: str, t: Type[PeripheralConfigFactory], periph_t: Type[BasicPeripheral]): + """manually add a peripheral factory""" + peripheral_factories[name] = t(periph_t) + +def peripheral_from_file(path: str, name: str = "", config_factory_t: Type[PeripheralConfigFactory] = PeripheralConfigFactory): + """ + wrapper for peripheral classes + + It automatically adds parent classes based on a file, also it extracts interrupts and io signals if provided. + + :param str path: the path of the file + :param str name: the name if the name in the file is wrong. defualt to the one provided in the file. + :param Type[PeripheralConfigFactory] config_factory_t: the class to generate the configs info for configuration files, if no special options are needed a sane default is used. + """ + if "X_HEEP_PROJECT_ROOT" in os.environ: + path = os.environ["X_HEEP_PROJECT_ROOT"]+path + ip_block_paths.add(path) + name_c = name + def deco_peripheral_from_file(cls): + name = name_c + ip_block = IpBlock.from_path(path, []) + if name == "": + name = ip_block.name + if_list = ip_block.bus_interfaces.interface_list + if len(if_list) == 0: + raise NotImplementedError("Peripheral description without bus interface are not supported") + if len(if_list) > 1: + raise NotImplementedError("Peripheral decription with more than one bus interface are not supported") + if if_list[0]["is_host"]: + raise NotImplementedError("Only device interfaces are supported") + if "protocol" not in if_list[0]: + raise ValueError("Protocol not specified") + + proto = if_list[0]["protocol"] + + + + Base = None + if proto is BusProtocol.TLUL: + Base = TLULPeripheral + elif proto is BusProtocol.REG_IFACE: + Base = RegIfacePeripheral + else: + raise RuntimeError + + @functools.wraps(cls, updated=()) + class PeriphWrapper(cls, Base): + IP_BLOCK = ip_block + def __init__(self, domain: "str | None" = None, **kwargs): + super().__init__(name, domain, **kwargs) + self._ip_block = self.IP_BLOCK + self._ip_block_path = path + + add_peripheral_factory(name, config_factory_t, PeriphWrapper) + + return PeriphWrapper + + return deco_peripheral_from_file + \ No newline at end of file diff --git a/util/x_heep_gen/peripherals/peripherals.py b/util/x_heep_gen/peripherals/peripherals.py new file mode 100644 index 000000000..e30070844 --- /dev/null +++ b/util/x_heep_gen/peripherals/peripherals.py @@ -0,0 +1,19 @@ +from .peripheral_helper import peripheral_from_file +from .rv_timer import RvTimerPeripheral +from .spi_host import SpiHostPeripheral +from .i2s import I2SPeripheral +from .gpio import GpioPeripheral +from .rv_plic import RvPlicPeripheral +from .pdm2pcm import Pdm2PcmPeripheral +from .fixed_peripheral import FixedPeripheral + +@peripheral_from_file("./hw/vendor/lowrisc_opentitan/hw/ip/i2c/data/i2c.hjson") +class I2CPeripheral(): + """A class representing an `i2c` peripheral.""" + pass + + +@peripheral_from_file("./hw/vendor/lowrisc_opentitan/hw/ip/uart/data/uart.hjson") +class UartPeripheral(): + """A class representing an `uart` peripheral.""" + pass \ No newline at end of file diff --git a/util/x_heep_gen/peripherals/reg_iface_peripheral.py b/util/x_heep_gen/peripherals/reg_iface_peripheral.py new file mode 100644 index 000000000..a9fa154c8 --- /dev/null +++ b/util/x_heep_gen/peripherals/reg_iface_peripheral.py @@ -0,0 +1,25 @@ + +from typing import List +from ..signal_routing.routing_helper import RoutingHelper +from .basic_peripheral import BasicPeripheral + + +class RegIfacePeripheral(BasicPeripheral): + """ + A class representing a peripheral connected to the system bus via obi directly. + + It is automatically used by `@peripheral_from_file`. + """ + def make_instantiation_connections(self, rh: RoutingHelper) -> str: + inst: str = "" + inst += f".reg_req_i(peripheral_slv_req[core_v_mini_mcu_pkg::{self.full_name.upper()}_IDX])," + inst += f".reg_rsp_o(peripheral_slv_rsp[core_v_mini_mcu_pkg::{self.full_name.upper()}_IDX])," + + return super().make_instantiation_connections(rh) + inst + + def make_instantiation_generics(self) -> List[str]: + req_gen = [ + "reg_req_t(reg_pkg::reg_req_t)", + "reg_rsp_t(reg_pkg::reg_rsp_t)" + ] + return super().make_instantiation_generics() + req_gen \ No newline at end of file diff --git a/util/x_heep_gen/peripherals/rv_plic.py b/util/x_heep_gen/peripherals/rv_plic.py new file mode 100644 index 000000000..ecc51d405 --- /dev/null +++ b/util/x_heep_gen/peripherals/rv_plic.py @@ -0,0 +1,76 @@ +from typing import Set +from .peripheral_helper import peripheral_from_file +from ..signal_routing.endpoints import InterruptDirectEP, InterruptPlicEP +from ..signal_routing.node import Node +from ..signal_routing.routing_helper import RoutingHelper + + +@peripheral_from_file("./hw/vendor/lowrisc_opentitan/hw/ip/rv_plic/data/rv_plic.hjson", name="rv_plic") +class RvPlicPeripheral(): + """ + A class representing an `rv_plic` peripheral. + """ + def _rv_plic_target_name(self) -> str: + return "plic_target" + + def _rv_plic_source_name_irq(self) -> str: + return f"{self.name}_{self._sp_name_suffix}_irq" + + def _rv_plic_source_name_msip(self) -> str: + return f"{self.name}_{self._sp_name_suffix}_msip" + + def register_connections(self, rh: RoutingHelper, p_node: Node): + super().register_connections(rh, p_node) + rh.add_target(p_node, self._rv_plic_target_name(), InterruptPlicEP()) + rh.add_source(p_node, self._rv_plic_source_name_irq(), InterruptDirectEP(), "irq_external") + rh.add_source(p_node, self._rv_plic_source_name_msip(), InterruptDirectEP(), "irq_software") + + def make_instantiation_connections(self, rh: RoutingHelper) -> str: + out = f".intr_src_i({self.name}_{self._sp_name_suffix}_intr_vector)," + out += ".irq_id_o()," + out += f".irq_o({rh.use_source_as_sv(self._rv_plic_source_name_irq(), self._p_node)})," + out += f".msip_o({rh.use_source_as_sv(self._rv_plic_source_name_msip(), self._p_node)})," + + + return super().make_instantiation_connections(rh) + out + + def make_instantiation(self, rh: RoutingHelper) -> str: + intr_sources = rh.use_target_as_sv_multi(self._rv_plic_target_name(), self._p_node) + + out = "" + out += f"logic [rv_plic_reg_pkg::NumTarget-1:0] {self.name}_{self._sp_name_suffix}_irq_plic;" + out += f"logic [rv_plic_reg_pkg::NumSrc-1:0] {self.name}_{self._sp_name_suffix}_intr_vector;\n\n" + out += f"assign {self.name}_{self._sp_name_suffix}_intr_vector[0] = 1'b0; // ID [0] is a special case and must be tied to zero.\n" + for i, intr in enumerate(intr_sources): + out += f"assign {self.name}_{self._sp_name_suffix}_intr_vector[{i+1}] = {intr};" + for i in range(i+1, 64): + out += f"assign {self.name}_{self._sp_name_suffix}_intr_vector[{i}] = 1'b0;" + out += "\n\n" + + return out + super().make_instantiation(rh) + + def make_intr_defs(self, rh: RoutingHelper) -> str: + out = "" + intr_sources = rh.use_target_as_sv_multi(self._rv_plic_target_name(), self._p_node) + for i, intr in enumerate(intr_sources): + intr = intr.split(".")[-1] + out += f"#define {intr.upper()} {i+1}\n" + return out + + def make_handler_array(self, rh: RoutingHelper) -> str: + out = "handler_irq_dummy," + intr_sources = rh.use_target_as_sv_multi(self._rv_plic_target_name(), self._p_node) + for i, intr in enumerate(intr_sources): + ep: InterruptPlicEP = rh.get_source_ep_copy(intr.split(".")[-1]) + out += f"{ep.handler}," + for _ in range(i+1, 64): + out += "handler_irq_dummy," + return out + + def make_handler_set(self, rh: RoutingHelper) -> Set[str]: + out = {"handler_irq_dummy"} + intr_sources = rh.use_target_as_sv_multi(self._rv_plic_target_name(), self._p_node) + for intr in intr_sources: + ep: InterruptPlicEP = rh.get_source_ep_copy(intr.split(".")[-1]) + out.add(ep.handler) + return out diff --git a/util/x_heep_gen/peripherals/rv_timer.py b/util/x_heep_gen/peripherals/rv_timer.py new file mode 100644 index 000000000..49f014a30 --- /dev/null +++ b/util/x_heep_gen/peripherals/rv_timer.py @@ -0,0 +1,35 @@ +from .peripheral_helper import peripheral_from_file +from .tlul_peripheral import TLULPeripheral + +from reggen.ip_block import IpBlock + +@peripheral_from_file("./hw/vendor/lowrisc_opentitan/hw/ip/rv_timer/data/rv_timer.hjson") +class RvTimerPeripheral(): + """ + A class representing an `rv_timer` peripheral. + """ + + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self.interrupt_dest = "fast" + + def specialize_name(self, n: int) -> int: + """ + Adds a name suffix to the name based on the integer provided. + + It has to be called again when name is changed. + + :param int n: number to be suffixed + :return: next value for this name, here n+2, but a subclass could do an other increment + :rtype: int + :raise TypeError: if argument does not have the right type. + """ + if type(n) is not int: + raise TypeError("argument n should be of type int") + + self.set_specialized_name(f"{n}_{n+1}") + self.interrupt_handler_base = { + "timer_expired_0_0" : f"{self.name}_{n}", + "timer_expired_1_0" : f"{self.name}_{n + 1}", + } + return n + 2 \ No newline at end of file diff --git a/util/x_heep_gen/peripherals/spi_host.py b/util/x_heep_gen/peripherals/spi_host.py new file mode 100644 index 000000000..afdc91a29 --- /dev/null +++ b/util/x_heep_gen/peripherals/spi_host.py @@ -0,0 +1,79 @@ +from typing import Any, Dict + +import hjson +from .peripheral_helper import PeripheralConfigFactory, peripheral_from_file +from ..config_helpers import to_bool +from ..signal_routing.endpoints import DmaTriggerEP +from ..signal_routing.node import Node +from ..signal_routing.routing_helper import RoutingHelper + + +class SpiHostConfigFactory(PeripheralConfigFactory): + """ + A class adding configuration information for spi hosts + """ + def dict_to_kwargs(self, d: hjson.OrderedDict) -> Dict[str, Any]: + ret = dict() + dma = None + if "dma" in d: + dma = to_bool(d.pop("dma")) + if dma is None: + raise RuntimeError("dma parameter should be a boolean.") + else: + raise RuntimeError("spi_host require the dma argument to be set") + + if "event_is_fast_intr" in d: + eifi = to_bool(d["event_is_fast_intr"]) + if eifi is None: + raise RuntimeError("event_is_fast_intr should be a boolean") + ret["event_is_fast_intr"] = eifi + + ret["dma"] = dma + + ret.update(super().dict_to_kwargs(d)) + return ret + +@peripheral_from_file("./hw/vendor/lowrisc_opentitan_spi_host/data/spi_host.hjson", config_factory_t=SpiHostConfigFactory) +class SpiHostPeripheral(): + """ + A class representing an `spi_host` peripheral + + :param bool event_is_fast_intr: should the event interrupt be connected to the fast interrupt module? + :param bool dma: Should the dma trigger be connected? + """ + def __init__(self, *args, event_is_fast_intr=False, **kwargs): + if not "dma" in kwargs: + raise TypeError("dma keyword argument is required") + self._spi_uses_dma: bool = kwargs.pop("dma") + if type(self._spi_uses_dma) is not bool: + raise RuntimeError("dma flag should be of type bool") + + super().__init__(*args, **kwargs) + self.interrupt_dest = { + "error": "plic", + "spi_event": "fast" if event_is_fast_intr else "plic" + } + self.interrupt_handler = { + "error": "error", + "spi_event": "" + } + + def register_connections(self, rh: RoutingHelper, p_node: Node): + super().register_connections(rh, p_node) + if self._spi_uses_dma: + rh.add_source(p_node, f"{self.name}_{self._sp_name_suffix}_rx", DmaTriggerEP()) + rh.add_source(p_node, f"{self.name}_{self._sp_name_suffix}_tx", DmaTriggerEP()) + + def make_instantiation_connections(self, rh: RoutingHelper) -> str: + out = "" + out += ".alert_rx_i()," + out += ".alert_tx_o()," + out += ".passthrough_i(spi_device_pkg::PASSTHROUGH_REQ_DEFAULT)," + out += ".passthrough_o()," + if self._spi_uses_dma: + out += f".rx_valid_o({rh.use_source_as_sv(f'{self.name}_{self._sp_name_suffix}_rx', self._p_node)})," + out += f".tx_ready_o({rh.use_source_as_sv(f'{self.name}_{self._sp_name_suffix}_tx', self._p_node)})," + else: + out += ".rx_valid_o()," + out += ".tx_ready_o()," + return super().make_instantiation_connections(rh) + out \ No newline at end of file diff --git a/util/x_heep_gen/peripherals/sv_helper.py b/util/x_heep_gen/peripherals/sv_helper.py new file mode 100644 index 000000000..ea2ca1e27 --- /dev/null +++ b/util/x_heep_gen/peripherals/sv_helper.py @@ -0,0 +1,23 @@ +from dataclasses import dataclass + + +@dataclass +class SvSignal(): + """ + A dataclass to hold information about special local signals used with peripherals + """ + t: str + name: str + + def to_inst_declaration(self, comma: bool) -> str: + """ + get the sv code used for instantiation. + """ + return f"{self.t} {self.name}" + ("," if comma else "") + +@dataclass +class SvSignalArray(SvSignal): + width: int + + def to_inst_declaration(self, comma: bool) -> str: + return super().to_inst_declaration(False) + f"[{self.width}-1:0]" + ("," if comma else "") \ No newline at end of file diff --git a/util/x_heep_gen/peripherals/tlul_peripheral.py b/util/x_heep_gen/peripherals/tlul_peripheral.py new file mode 100644 index 000000000..546b648b1 --- /dev/null +++ b/util/x_heep_gen/peripherals/tlul_peripheral.py @@ -0,0 +1,57 @@ + +from itertools import chain +from typing import Iterable +from .basic_peripheral import * + +class TLULPeripheral(BasicPeripheral): + """ + A class representing a peripheral connected to the system bus via tlul. + + It is automatically used by `@peripheral_from_file`. + """ + def __init__(self, name: "str|None" = None, domain: "str|None" = None): + super().__init__(name=name, domain=domain) + + + + @property + def tlul_d2h_name(self) -> str: + return f"{self.name}_{self._sp_name_suffix}_tl_d2h" + + @property + def tlul_h2d_name(self) -> str: + return f"{self.name}_{self._sp_name_suffix}_tl_h2d" + + def make_instantiation(self, rh: RoutingHelper) -> str: + """docs""" + + return f"""reg_to_tlul #( + .req_t(reg_pkg::reg_req_t), + .rsp_t(reg_pkg::reg_rsp_t), + .tl_h2d_t(tlul_pkg::tl_h2d_t), + .tl_d2h_t(tlul_pkg::tl_d2h_t), + .tl_a_user_t(tlul_pkg::tl_a_user_t), + .tl_a_op_e(tlul_pkg::tl_a_op_e), + .TL_A_USER_DEFAULT(tlul_pkg::TL_A_USER_DEFAULT), + .PutFullData(tlul_pkg::PutFullData), + .Get(tlul_pkg::Get) + ) reg_to_tlul_{self.name}_{self._sp_name_suffix}_i ( + .tl_o({self.tlul_h2d_name}), + .tl_i({self.tlul_d2h_name}), + .reg_req_i(peripheral_slv_req[core_v_mini_mcu_pkg::{self.full_name.upper()}_IDX]), + .reg_rsp_o(peripheral_slv_rsp[core_v_mini_mcu_pkg::{self.full_name.upper()}_IDX]) + );""" + "\n\n" + super().make_instantiation(rh) + + def make_instantiation_connections(self, rh: RoutingHelper) -> str: + inst: str = f".tl_i({self.tlul_h2d_name})," + inst += f".tl_o({self.tlul_d2h_name})," + + return super().make_instantiation_connections(rh) + inst + + def make_local_signals(self) -> Iterable[SvSignal]: + sigs = [ + SvSignal("tlul_pkg::tl_h2d_t", self.tlul_h2d_name), + SvSignal("tlul_pkg::tl_d2h_t", self.tlul_d2h_name), + ] + + return chain(super().make_local_signals(), iter(sigs)) diff --git a/util/x_heep_gen/signal_routing/__init__.py b/util/x_heep_gen/signal_routing/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/util/x_heep_gen/signal_routing/endpoints.py b/util/x_heep_gen/signal_routing/endpoints.py new file mode 100644 index 000000000..919afc204 --- /dev/null +++ b/util/x_heep_gen/signal_routing/endpoints.py @@ -0,0 +1,136 @@ +from enum import * +from typing import List + + +class Endpoint: + """ + A class providing information about sources and targets that can be connected together. + """ + def __init__(self): + self.t: str = "logic" + self.source_direction: str = "output" + self.target_direction: str = "input" + self.reserved = False + self.used = False + self.nc = True + + def single_use(self) -> bool: + """ + Informs if a target with this endpoint informations can be used only once. + + :return: If it can be used only onde + :rtype: bool + """ + return True + + def use_target(self, name: str) -> bool: + """ + Function used by the routing helper to update the class after each new use. + + :param str name: the name of the source + :return: if the target is full, can no longer be connected to new sources, the current source is valid. + :rtype: bool + """ + self.used = True + self.nc = False + return True + + def target_nc(self) -> str: + """ + If an Endpoint can be unconnected on the target side it should implement this method. + + :return: the sv code in case the target is not connected. + :rtype: str + """ + raise NotImplementedError("target_nc is not implemented for this endpoint") + + +class InterruptEP(Endpoint): + """ + An Endpoint used to connect interrupts to the fast interrupt module. + """ + def __init__(self, handler=""): + super().__init__() + self.t = "logic" + self.source_direction: str = "output" + self.target_direction: str = "input" + self.count = 0 + self.source_names: List[str] = [] + self.handler = handler + + def single_use(self) -> bool: + return False + + def use_target(self, name: str) -> bool: + self.count += 1 + self.nc = False + self.used = True + + if self.count < 15: + return False + + return True + +class InterruptDirectEP(Endpoint): + """ + An endpoint to connect interrupts directly to the rv core + """ + def __init__(self): + super().__init__() + self.t = "logic" + self.source_direction: str = "output" + self.target_direction: str = "input" + + def target_nc(self) -> str: + return "1'b0" + +class InterruptPlicEP(Endpoint): + """ + An Endpoint to connect interrupts to the plic + """ + def __init__(self, handler="handler_irq_dummy"): + super().__init__() + self.t = "logic" + self.source_direction: str = "output" + self.target_direction: str = "input" + self.count = 0 + self.source_names: List[str] = [] + self.handler = handler + + def single_use(self) -> bool: + return False + + def use_target(self, name: str) -> bool: + self.count += 1 + self.nc = False + self.used = True + + if self.count < 63: + return False + + return True + +class DmaTriggerEP(Endpoint): + """ + An Endpoint to connect dma triggers + """ + def __init__(self): + super().__init__() + self.t = "logic" + self.source_direction: str = "output" + self.target_direction: str = "input" + self.count = 0 + self.source_names: List[str] = [] + + def single_use(self) -> bool: + return False + + def use_target(self, name: str) -> bool: + self.count += 1 + self.nc = False + self.used = True + + if self.count < 16: + return False + + return True diff --git a/util/x_heep_gen/signal_routing/node.py b/util/x_heep_gen/signal_routing/node.py new file mode 100644 index 000000000..5f097c098 --- /dev/null +++ b/util/x_heep_gen/signal_routing/node.py @@ -0,0 +1,10 @@ +from dataclasses import * + + +@dataclass +class Node: + """ + A dataclass representing a node of the routing helper. + """ + name: str + p_name: str = field(compare=False) \ No newline at end of file diff --git a/util/x_heep_gen/signal_routing/routing_helper.py b/util/x_heep_gen/signal_routing/routing_helper.py new file mode 100644 index 000000000..34f5b7b31 --- /dev/null +++ b/util/x_heep_gen/signal_routing/routing_helper.py @@ -0,0 +1,545 @@ +from copy import deepcopy +from typing import Dict, Generator, List, NamedTuple, Set, Tuple + +from ..sv_helpers import SvInterface +from .endpoints import Endpoint +from .node import Node + + +class TargetInf(NamedTuple): + """Named Tuple containing local information about targets""" + ep: Endpoint + parent: Node + +class SourceInf(NamedTuple): + """Named Tuple containing local information about sources""" + ep: Endpoint + parent: Node + to: str + +class ConIn(NamedTuple): + """Information about incomming connection to a node.""" + designator: Tuple[str, str] + direction: int + first: bool + +class BundledCon(NamedTuple): + """Holds informations about one connection in a bundle.""" + source: str + target: str + source_idx: int + + +class RoutingHelper(): + """ + Helper to route signals between nodes (generaly sv modules). + + Provided with nodes, sources and targets it can create all the definition of the signals and bundle them in interfaces. + + It has the following limitations: + - names have to be unique for each category, even across nodes. + """ + + def __init__(self) -> None: + self._root_node = Node("root", "") + self._nodes: Dict[str, Node] = {"root": deepcopy(self._root_node)} + self._sources: Dict[str, SourceInf] = dict() + self._targets: Dict[str, TargetInf] = dict() + self._node_childs: Dict[str, List[str]] = {"root": []} + + self._bundles: Dict[Tuple[str,str], List[BundledCon]] = dict() + self._local_connections: Dict[str, List[Tuple[str, str]]] = dict() + + self._source_full_sv: Dict[str, Dict[str, str]] = dict() + self._target_full_sv: Dict[str, Dict[str, str]] = dict() + self._target_full_sv_multi: Dict[str, Dict[str, List[str]]] = dict() + + def _add_node_child(self, parent: str, child: str): + """ + Internal methode to add childs to a node. + """ + self._node_childs[parent].append(str) + self._node_childs[child] = [] + + def register_node(self, node: Node): + """ + Register a node in the helper. + + This is needed in order to add sources or targets to this node. + + :param Node node: the node to add. + """ + if not isinstance(node, Node): + raise TypeError("node is not an instance of Node.") + + if node.name in self._nodes: + raise RuntimeError("A node with the same name is already registered.") + + if node.p_name == "": + raise RuntimeError("It is not possible to add a new root node.") #because the code does not handle it. + + if not node.p_name in self._nodes: + raise RuntimeError("Node added before it's parent.") + + self._nodes.update({node.name: deepcopy(node)}) + self._add_node_child(node.p_name, node.name) + + + def add_source(self, parent: Node, name: str, ep: Endpoint, to: str = ""): + """ + Add a source tied to a specific node. If `to` is not specified it will connect to the first available target. + + :param Node parent: The parent of this source + :param str name: the name of this source + :param Endpoint ep: The endpoint of this source + :param str to: the name of the target the source should be connected + """ + if not isinstance(parent, Node): + raise TypeError("parent should be an instance of Node") + if type(name) is not str or str == "": + raise TypeError("name should be a non empty string") + if not isinstance(ep, Endpoint): + raise TypeError("ep should be of type Endpoint") + if type(to) is not str: + raise TypeError("to should be of type str") + + if parent.name not in self._nodes: + raise RuntimeError("parent Node has to be added before usage") + if name in self._sources: + raise RuntimeError("a name can't be used twice as source name") + + self._sources.update({name: SourceInf(ep, parent, to)}) + + def add_target(self, parent: Node, name: str, ep: Endpoint): + """ + Add a target tied to a specific node. + + :param Node parent: The parent of this target + :param str name: the name of this target + :param Endpoint ep: The endpoint of this target + """ + if not isinstance(parent, Node): + raise TypeError("parent should be an instance of Node") + if type(name) is not str or str == "": + raise TypeError("name should be a non empty string") + if not isinstance(ep, Endpoint): + raise TypeError("ep should be of type Endpoint") + + if parent.name not in self._nodes: + raise RuntimeError("parent Node has to be added before usage") + + if name in self._targets: + raise RuntimeError("a name can't be used twice as target name") + + self._targets.update({name: TargetInf(ep, parent)}) + + def get_parent(self, node: str) -> str: + """ + Get the parent of a specific node by name + + :param str node: The name of the node + :return: the parent name + :rtype: str + """ + if type(node) is not str: + raise TypeError("node should be of type string") + if not node in self._nodes: + raise RuntimeError(f"node {node} not registerd") + return self._nodes[node].p_name + + def _parent_iter(self, node: str) -> Generator[str, None, None]: + """ + Internal methode to iterate over all parent of a node from the node to the root.""" + while True: + if node in self._nodes: + yield node + else: + return + + node = self.get_parent(node) + + def route(self): + """ + Do all the calculation to connect all targets and sources together. + + Targets and sources should be added before this is called. + """ + pairs: List[Tuple[str, str]] = [] + sources_used: Set[str] = set() + targets_used: Set[str] = set() + + # route source with named target + for s, inf in self._sources.items(): + if inf.to != "": + if inf.to in self._targets: + if not inf.to in targets_used: + + pairs.append((s, inf.to)) + sources_used.add(s) + full = self._targets[inf.to].ep.use_target(s) + if full: + targets_used.add(inf.to) + else: + raise RuntimeError(f"Unable to route {s} to {inf.to}: {inf.to} is already used or all ports are used.") + + else: + raise RuntimeError(f"Unable to route {s} to {inf.to}: {inf.to} is not provided to routing helper.") + + # route source without named target + for s, s_inf in self._sources.items(): + + if s_inf.to == "": + target = None + for t, t_inf in self._targets.items(): + if t in targets_used: + continue + + if isinstance(t_inf.ep, type(s_inf.ep)): + target = t + break + + if target is not None: + pairs.append((s, target)) + sources_used.add(s) + full = self._targets[target].ep.use_target(s) + if full: + targets_used.add(target) + else: + raise RuntimeError(f"Unable to route {s}: no tagets are available or all are used.") + + + # bundle connections together. + self._bundles = dict() + self._local_connections = dict() + + node_to_connect: Set[Tuple[str, str]] = set() + for s, t in pairs: + s_inf = self._sources[s] + t_inf = self._targets[t] + + if t_inf.parent == s_inf.parent: + self._local_connections.setdefault(t_inf.parent.name, []).append((s, t)) + + else: + p_set = tuple(sorted([s_inf.parent.name, t_inf.parent.name])) + node_to_connect.add(p_set) + direc = 0 if p_set[0] == s_inf.parent.name else 1 + self._bundles.setdefault(p_set, []).append(BundledCon(s, t, direc)) + + + self._connection_roots: Dict[str, List[Tuple[str, str]]] = dict() + self._connection_in: Dict[str, List[ConIn]] = dict() + + for i in node_to_connect: + path0 = list(self._parent_iter(i[0]))[::-1] + path1 = list(self._parent_iter(i[1]))[::-1] + + j = 0 + for p1, p2 in zip(path0, path1): + if p1 != p2: + break + j += 1 + + if not path0[j-1] in self._connection_roots: + self._connection_roots[path0[j-1]] = [] + self._connection_roots[path0[j-1]].append(i) + + first = True + for n in path0[j:]: + if not n in self._connection_in: + self._connection_in[n] = [] + self._connection_in[n].append(ConIn(i, 0, first)) + first = False + + first = True + for n in path1[j:]: + if not n in self._connection_in: + self._connection_in[n] = [] + self._connection_in[n].append(ConIn(i, 1, first)) + first = False + + self._generate_local_names() + + @staticmethod + def bundle_name(n_name: Tuple[str, str]) -> str: + """ + Get the name of of an interface connecting to nodes + + :param Tuple[str,str] n_name: The name of both nodes + :return: the name of the bundle + :rtype: str + """ + return f"bundle__{n_name[0]}__{n_name[1]}__if" + + @staticmethod + def bundle_type_name(n_name: Tuple[str, str]) -> str: + """ + Get the type name of of an interface connecting to nodes + + :param Tuple[str,str] n_name: The name of both nodes + :return: the type name of the bundle + :rtype: str + """ + return f"if_bundle__{n_name[0]}__{n_name[1]}" + + def _generate_local_names(self): + """ + Internal methode to generate the sv names for each target and source. + """ + for n_name, l in self._local_connections.items(): + d_s: Dict[str,str] = dict() + d_t: Dict[str,str] = dict() + d_t_multi: Dict[str,List[str]] = dict() + for s, t in l: + d_s.update({s: s}) + if self._targets[t].ep.single_use(): + d_t.update({t: s}) + else: + d_t_multi.setdefault(t, []).append(s) + + self._source_full_sv[n_name] = d_s + self._target_full_sv[n_name] = d_t + self._target_full_sv_multi[n_name] = d_t_multi + + for n_name, l in self._bundles.items(): + for con in l: + s_parent = n_name[con.source_idx] + t_parent = n_name[1-con.source_idx] + + self._source_full_sv.setdefault( + s_parent, {} + ).update( + {con.source: self.bundle_name(n_name)+"."+con.source} + ) + + if self._targets[con.target].ep.single_use(): + self._target_full_sv.setdefault( + t_parent, {} + ).update( + {con.target: self.bundle_name(n_name)+"."+con.source} + ) + else: + self._target_full_sv_multi.setdefault( + t_parent, {} + ).setdefault( + con.target, [] + ).append( + self.bundle_name(n_name)+"."+con.source + ) + + + + + + def use_source_as_sv(self, name: str, p_node: Node) -> str: + """ + Get the sv code to use a source in sv. + + :param str name: the name of the source + :param Node p_node: the parent node + :return: the sv code to use. + :rtype: str + """ + if type(name) is not str: + raise TypeError("name should be of type str") + if not isinstance(p_node, Node): + raise TypeError("p_node should be an instance of Node") + if not p_node.name in self._nodes: + raise RuntimeError(f"node {p_node.name} is not registered") + return self._source_full_sv[p_node.name][name] + + def use_target_as_sv(self, name: str, p_node: Node) -> str: + """ + Get the sv code to use a target in sv. + + If the target is not connected, some endpoints do specify an empty string for outgoing signals. + In some cases this has to be checked, like when an assignment is used. + + :param str name: the name of the target + :param Node p_node: the parent node + :return: the sv code to use. + :rtype: str + """ + if type(name) is not str: + raise TypeError("name should be of type str") + if not isinstance(p_node, Node): + raise TypeError("p_node should be an instance of Node") + if not p_node.name in self._nodes: + raise RuntimeError(f"node {p_node.name} is not registered") + + if self._targets[name].ep.nc: + return self._targets[name].ep.target_nc() + + return self._target_full_sv[p_node.name][name] + + def use_target_as_sv_multi(self, name: str, p_node: Node) -> List[str]: + """ + Get the sv code to use a target in sv, with multiple sources. + + If the target is not connected, some endpoints do specify an empty string for outgoing signals. + In some cases this has to be checked, like when an assignment is used. + + :param str name: the name of the target + :param Node p_node: the parent node + :return: the sv code to use. + :rtype: List[str] + """ + if type(name) is not str: + raise TypeError("name should be of type str") + if not isinstance(p_node, Node): + raise TypeError("p_node should be an instance of Node") + if not p_node.name in self._nodes: + raise RuntimeError(f"node {p_node.name} is not registered") + + if self._targets[name].ep.nc: + return self._targets[name].ep.target_nc() + + return self._target_full_sv_multi[p_node.name][name] + + def use_target_as_sv_array_multi(self, name: str, p_node: Node, size: int, default: str = "1'b0") -> List[str]: + """ + Get the sv code to use a target in sv, with multiple sources in an sv array. + + If the target is not connected, some endpoints do specify an empty string for outgoing signals. + In some cases this has to be checked, like when an assignment is used. + + :param str name: the name of the target + :param Node p_node: the parent node + :return: the sv code to use. + :rtype: List[str] + """ + if type(name) is not str: + raise TypeError("name should be of type str") + if not isinstance(p_node, Node): + raise TypeError("p_node should be an instance of Node") + if not p_node.name in self._nodes: + raise RuntimeError(f"node {p_node.name} is not registered") + + try: + names = self._target_full_sv_multi[p_node.name][name] + except KeyError: + names = [] + + names += [default for _ in range(size - len(names))] + return f"{{{','.join(names[::-1])}}}" + + def get_target_ep_copy(self, name: str) -> Endpoint: + """ + Get an endpoint of a target by name + + :param str name: the target name + :return: an endpoint + :rtype: Endpoint + """ + return deepcopy(self._targets[name].ep) + + def get_source_ep_copy(self, name: str) -> Endpoint: + """ + Get an endpoint of a source by name + + :param str name: the source name + :return: an endpoint + :rtype: Endpoint + """ + return deepcopy(self._sources[name].ep) + + + + def get_intf_sv_helpers(self) -> Generator[SvInterface, None, None]: + """ + Makes the sv code for all interfaces. + + :return: a generator of SvInterface over each interface that is required. + :rtype: Generator[SvInterface, None, None] + """ + for n_name, l_con in self._bundles.items(): + helper = SvInterface(self.bundle_type_name(n_name)) + for connection in l_con: + source_idx = connection.source_idx + target_idx = 1-connection.source_idx + + source_name = n_name[source_idx] + target_name = n_name[target_idx] + + source_ep = self._sources[connection.source].ep + + ports = [ + (source_name, source_ep.source_direction), + (target_name, source_ep.target_direction), + ] + + helper.add_signal(source_ep.t, connection.source, ports) + + yield helper + + def get_node_ports(self, node: Node) -> str: + """ + Makes the sv code for the definition of a module + + :param Node node: The node linked to the module + :return: the sv code with a trailing `,` + :rtype: str + """ + out = "" + for con_in in self._connection_in[node.name]: + type_name = self.bundle_type_name(con_in.designator) + name = self.bundle_name(con_in.designator) + port_name = con_in.designator[con_in.direction] + + out += f"{type_name}.{port_name} {name}," + return out + + + def get_node_local_signals(self, node: Node) -> str: + """ + Makes the sv code for the definition of local signals to a module + + :param Node node: The node linked to the module + :return: the sv code + :rtype: str + """ + out = "" + if node.name in self._connection_roots: + for n_name in self._connection_roots[node.name]: + type_name = self.bundle_type_name(n_name) + name = self.bundle_name(n_name) + + out += f"{type_name} {name};" + + if node.name in self._local_connections: + for s, t in self._local_connections[node.name]: + type_name = self._sources[s].ep.t + name = s + out += f"{type_name} {name};" + return out + + def get_instantiation_signals(self, node: Node) -> str: + """ + Makes the sv code for the instantiation of a module connections. + + :param Node node: The node linked to the module + :return: the sv code with a trailing `,` + :rtype: str + """ + out = "" + for con_in in self._connection_in[node.name]: + name = self.bundle_name(con_in.designator) + out += f".{name}" + + if con_in.first: + port_name = con_in.designator[con_in.direction] + out += f"({name}.{port_name})" + + out += "," + + return out + + + def get_root_node(self) -> Node: + """ + Get the root node of the helpers tree + + :return: the root node + :rtype: Node + """ + return self._root_node \ No newline at end of file diff --git a/util/x_heep_gen/sv_helpers.py b/util/x_heep_gen/sv_helpers.py new file mode 100644 index 000000000..5437b062c --- /dev/null +++ b/util/x_heep_gen/sv_helpers.py @@ -0,0 +1,82 @@ +from abc import * +from typing import Dict, List, Tuple +""" +This modules add types to help the generation of sv code. +It does not a lot of checks but helps to move sv generation out of the other code. + +Formatting is ignored, for this you should use a tool like verible for the post processing. +""" + +class SvHelper(ABC): + """ + General interface used by other classes in this module. + """ + @abstractmethod + def get_def(self) -> str: + """ + Get the definition in system verilog. + + :return: the sv definition + :rtype: str + """ + pass + + + + + +class SvInterface(SvHelper): + """ + Represents a sv interface, for code generation. + + :param str name: the name of the interface.""" + def __init__(self, name: str) -> None: + if type(name) is not str: + raise TypeError("name should be of type str") + self._name: str = name + self._ports: Dict[str, List[Tuple[str,str]]] = dict() + self._signals: List[Tuple[str,str]] = [] + + def add_signal(self, t: str, name: str, ports: List[Tuple[str, str]]): + """ + Add a signal. + + :param str t: the type of the signal. + :param str name: the name of the signal. + :param List[Tuple[str, str]] ports: Add the ports of the signal. Each tuple is composed of the port name and in second the direction.""" + if type(t) is not str: + raise TypeError("t should be of type str") + if type(name) is not str: + raise TypeError("name should be of type str") + if not isinstance(ports, list): + raise TypeError("ports should be an instance of list") + + self._signals.append((t, name)) + + for port, direction in ports: + if not port in self._ports: + self._ports[port] = [] + self._ports[port].append((direction, name)) + + def get_def(self) -> str: + out = f"interface {self._name} ();" + + for t, name in self._signals: + out += f"{t} {name};" + + for port, l in self._ports.items(): + out += f"modport {port} (" + + for direction, name in l: + out += f"{direction} {name}," + + if out[-1] == ",": + out = out[:-1] + + out += ");" + + out += "endinterface" + return out + + + diff --git a/util/x_heep_gen/system.py b/util/x_heep_gen/system.py index 09e4a855e..23ebca3a5 100644 --- a/util/x_heep_gen/system.py +++ b/util/x_heep_gen/system.py @@ -1,9 +1,17 @@ from copy import deepcopy from dataclasses import dataclass -from typing import Generator, Iterable, List, Optional, Set, Union +from typing import Dict, Generator, Iterable, List, Optional, Set, Union from enum import Enum + + +from .pads import IoInputEP, IoOutputEP, IoOutputEnEP, PadManager, Pad from .ram_bank import Bank, is_pow2, ILRamGroup from .linker_section import LinkerSection +from .peripherals.peripheral_domain import PeripheralDomain +from .peripherals.sv_helper import SvSignalArray +from .signal_routing.endpoints import DmaTriggerEP, InterruptDirectEP, InterruptEP, InterruptPlicEP +from .signal_routing.node import Node +from .signal_routing.routing_helper import RoutingHelper class BusType(Enum): """Enumeration of all supported bus types""" @@ -66,6 +74,16 @@ def __init__(self, bus_type: BusType, ram_start_address: int = 0, override: Opti self._ignore_ram_continous: bool = False self._ignore_ram_interleaved: bool = False + + self._peripheral_domains: List[PeripheralDomain] = [] + self._domain_names: Set[str] = set() + + self._pad_manager: Optional[PadManager] = None + + self._ext_intr_num: int = 0 + + self._init_fixed_nodes() + if override is not None and override.numbanks is not None: self.add_ram_banks([32]*override.numbanks) @@ -75,6 +93,59 @@ def __init__(self, bus_type: BusType, ram_start_address: int = 0, override: Opti self._override_numbanks_il = override.numbanks_il + def _init_fixed_nodes(self): + """ + Internal methode to generate all nodes, source and tragets node set by other abstractions. + """ + self._routing_helper: RoutingHelper = RoutingHelper() + + self._root_node = self._routing_helper.get_root_node() + self._routing_helper.add_source(self._root_node, "rst_n", IoInputEP(), Pad.name_to_target_name("rst", 0)+"_i") + self._routing_helper.add_source(self._root_node, "clk", IoInputEP(), Pad.name_to_target_name("clk", 0)+"_i") + + self._routing_helper.add_source(self._root_node, "dma_ext_rx", DmaTriggerEP()) + self._routing_helper.add_source(self._root_node, "dma_ext_tx", DmaTriggerEP()) + + self._mcu_node = Node("core_v_mini_mcu", self._root_node.name) + self._routing_helper.register_node(self._mcu_node) + self._routing_helper.add_target(self._mcu_node, "fast_irq_target", InterruptEP()) + self._routing_helper.add_target(self._mcu_node, "irq_software", InterruptDirectEP()) + self._routing_helper.add_target(self._mcu_node, "irq_external", InterruptDirectEP()) + self._routing_helper.add_target(self._mcu_node, "rv_timer_0_direct_irq", InterruptDirectEP()) + + self._routing_helper.add_source(self._mcu_node, "jtag_tck", IoInputEP(), Pad.name_to_target_name("jtag_tck", 0)+"_i") + self._routing_helper.add_source(self._mcu_node, "jtag_tms", IoInputEP(), Pad.name_to_target_name("jtag_tms", 0)+"_i") + self._routing_helper.add_source(self._mcu_node, "jtag_trst_n", IoInputEP(), Pad.name_to_target_name("jtag_trst", 0)+"_i") + self._routing_helper.add_source(self._mcu_node, "jtag_tdi", IoInputEP(), Pad.name_to_target_name("jtag_tdi", 0)+"_i") + self._routing_helper.add_source(self._mcu_node, "jtag_tdo", IoOutputEP(), Pad.name_to_target_name("jtag_tdo", 0)+"_o") + + self._ao_periph_node = Node("ao_periph", self._mcu_node.name) + self._routing_helper.register_node(self._ao_periph_node) + self._routing_helper.add_source(self._ao_periph_node, "boot_select", IoInputEP(), Pad.name_to_target_name("boot_select", 0)+"_i") + self._routing_helper.add_source(self._ao_periph_node, "execute_from_flash", IoInputEP(), Pad.name_to_target_name("execute_from_flash", 0)+"_i") + self._routing_helper.add_source(self._ao_periph_node, "exit_valid", IoOutputEP(), Pad.name_to_target_name("exit_valid", 0)+"_o") + + self._routing_helper.add_source(self._ao_periph_node, "spi_flash_sck_o", IoOutputEP(), Pad.name_to_target_name("spi_flash_sck", 0)+"_o") + self._routing_helper.add_source(self._ao_periph_node, "spi_flash_sck_en_o", IoOutputEnEP(), Pad.name_to_target_name("spi_flash_sck", 0)+"_oe") + for i in range(2): + self._routing_helper.add_source(self._ao_periph_node, f"spi_flash_csb_{i}_o", IoOutputEP(), Pad.name_to_target_name("spi_flash_csb", i)+"_o") + self._routing_helper.add_source(self._ao_periph_node, f"spi_flash_csb_{i}_en_o", IoOutputEnEP(), Pad.name_to_target_name("spi_flash_csb", i)+"_oe") + for i in range(4): + self._routing_helper.add_source(self._ao_periph_node, f"spi_flash_sd_{i}_o", IoOutputEP(), Pad.name_to_target_name("spi_flash_sd", i)+"_o") + self._routing_helper.add_source(self._ao_periph_node, f"spi_flash_sd_{i}_en_o", IoOutputEnEP(), Pad.name_to_target_name("spi_flash_sd", i)+"_oe") + self._routing_helper.add_source(self._ao_periph_node, f"spi_flash_sd_{i}_i", IoInputEP(), Pad.name_to_target_name("spi_flash_sd", i)+"_i") + + self._routing_helper.add_target(self._ao_periph_node, "dma_default_target", DmaTriggerEP()) + self._routing_helper.add_source(self._ao_periph_node, "spi_flash_dma_rx", DmaTriggerEP()) + self._routing_helper.add_source(self._ao_periph_node, "spi_flash_dma_tx", DmaTriggerEP()) + self._routing_helper.add_source(self._ao_periph_node, "spi_flash_intr", InterruptEP(handler="fic_irq_spi_flash")) + + self._routing_helper.add_source(self._ao_periph_node, "rv_timer_0_intr", InterruptDirectEP(), "rv_timer_0_direct_irq") + self._routing_helper.add_source(self._ao_periph_node, "rv_timer_1_intr", InterruptEP(handler="fic_irq_rv_timer_1")) + + self._routing_helper.add_source(self._ao_periph_node, "dma_done_intr", InterruptEP(handler="fic_irq_dma")) + self._routing_helper.add_source(self._ao_periph_node, "dma_window_intr", InterruptPlicEP(handler="handler_irq_dma")) + def add_ram_banks(self, bank_sizes: "List[int]", section_name: str = ""): """ Add ram banks in continuous address mode to the system. @@ -156,6 +227,10 @@ def add_ram_banks_il(self, num: int, bank_size: int, section_name: str = "", ign self._ram_banks_il_idx += indices self._ram_banks_il_groups.append(ILRamGroup(banks[0].start_address(), bank_size*num*1024, len(banks), banks[0].name())) self._il_banks_present = True + + + self._io_ifs: Dict[str, SvSignalArray] = {} + @@ -427,4 +502,156 @@ def build(self): if len(self._ram_banks) == 0: raise RuntimeError("There is no ram bank to infere the end of a section") old_sec.end = self._ram_banks[-1].end_address() - \ No newline at end of file + + self._periph_build() + + for i in range(self._ext_intr_num): + self._routing_helper.add_source(self._root_node, f"ext_intr_{i}", InterruptPlicEP()) + + if self._pad_manager is not None: + self._pad_manager.pre_route(self._routing_helper) + + self._routing_helper.route() + + for pd in self._peripheral_domains: + pd.addr_setup() + + + def add_domain(self, pd: PeripheralDomain): + """ + Adds a peripheral domain to the system. + + The domain should have a unique name. + + :param PeriperalDomain pd: The peripheral domain to be added. + :raise TypeError: if the argument is not an instance of PeripheralDomain + :raise RuntimeError: if the domain name is not unique. + """ + if not isinstance(pd, PeripheralDomain): + raise TypeError("argument should be an instance of PeripheralDomain") + + name = pd.get_name() + if name in self._domain_names: + raise RuntimeError("a domain with the same name was allready added") + + self._peripheral_domains.append(deepcopy(pd)) + + def iter_peripheral_domains(self) -> Iterable[PeripheralDomain]: + """ + Iterates through all peripheral domains. + + :return: an iterable over peripheral domain + :rtype: Iterable[PeripheralDomain] + """ + return iter(self._peripheral_domains) + + def num_peripheral_domains(self) -> int: + """ + Gets the number of peripheral domains. + + :return: the number of peripheral domains + :rtype: int + """ + return len(self._peripheral_domains) + + def iter_peripheral_domains_normal(self) -> Iterable[PeripheralDomain]: + """ + like `iter_peripheral_domains` but only on the normal type. + + :return: an iterable over peripheral domain + :rtype: Iterable[PeripheralDomain] + """ + return filter(lambda d: d.get_type() == "normal", self._peripheral_domains) + + def iter_peripheral_domains_fixed(self) -> Iterable[PeripheralDomain]: + """ + like `iter_peripheral_domains` but only on the fixed type. + + :return: an iterable over peripheral domain + :rtype: Iterable[PeripheralDomain] + """ + return filter(lambda d: d.get_type() == "fixed", self._peripheral_domains) + + def _periph_build(self): + """ + Internal method to build things related to peripherals and peripheral domains. + """ + used_names = { + "rv_timer": 2, + } + for pd in self._peripheral_domains: + pd.specialize_names(used_names) + pd.register_connections(self._routing_helper, self._mcu_node) + + for pd in self._peripheral_domains: + pd.build() + + def get_rh(self) -> RoutingHelper: + """ + Gets the routing helper used for this system + + :return: a reference to the routing helper + :rtype: RoutingHelper + """ + return self._routing_helper + + def get_mcu_node(self) -> Node: + """ + Gets the node of the mcu, coresponds to `core_v_mini_mcu` in sv. + + :return: a node + :rtype: Node + """ + return self._mcu_node + + def get_ao_node(self) -> Node: + """ + Gets the node of the ao peripheral domain. Could be removed if the ao domain is made more general. + + :return: a node + :rtype: Node + """ + return self._ao_periph_node + + def add_pad_manager(self, pad_manager: PadManager): + """ + Adds a `PadManager` to the system. Should be called before `build()`. + Only one pad manager can be added to the system, latter it can be used with `get_pad_manager()`. + + :param PadManager pad_manager: The padmanager to be added. + :raise TypeError: id the parameters are of the wrong type + :raise RuntimeError: if this function is used more than one.""" + if not isinstance(pad_manager, PadManager): + raise TypeError("pad_manager should be an instance of PadManager") + if self._pad_manager is not None: + raise RuntimeError("The pad manager is already set") + + self._pad_manager = pad_manager + + def get_pad_manager(self) -> PadManager: + """ + Gets the pad manager added by `add_pad_manager()`. + + :return: a pad manager + :rtype: PadManager + """ + return self._pad_manager + + def set_ext_intr(self, num: int): + """ + Sets the number of external interuppts. + If called it should be before `build()`. + The default is 0. + This interrupts will be connected to the rv_plic. + + :param int num: the number of external interrupts.""" + self._ext_intr_num = num + + def get_ext_intr(self) -> int: + """ + Get the number of external interrupts, if `set_ext_intr` was not called the default is 0. + + :return: the number of external interrupts + :rtype: int + """ + return self._ext_intr_num \ No newline at end of file diff --git a/x_heep_pythonpath.pth b/x_heep_pythonpath.pth new file mode 100644 index 000000000..27b6a20a0 --- /dev/null +++ b/x_heep_pythonpath.pth @@ -0,0 +1 @@ +import sys, os; sys.path.insert(0, os.path.abspath("ROOT_PATH/util")); sys.path.insert(0, os.path.abspath("ROOT_PATH/hw/vendor/pulp_platform_register_interface/vendor/lowrisc_opentitan/util")) \ No newline at end of file