diff --git a/Makefile b/Makefile index fa6e81ef5..0220b7c30 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ MAKE = make # Get the absolute path mkfile_path := $(shell dirname "$(realpath $(firstword $(MAKEFILE_LIST)))") +$(info $$You are executing from: $(mkfile_path)) # Include the self-documenting tool FILE=$(mkfile_path)/Makefile @@ -49,7 +50,7 @@ COMPILER_PREFIX ?= riscv32-unknown- ARCH ?= rv32imc # Path relative from the location of sw/Makefile from which to fetch source files. The directory of that file is the default value. -SOURCE ?= "." +SOURCE ?= $(".") # Simulation engines options are verilator (default) and questasim SIMULATOR ?= verilator @@ -57,6 +58,9 @@ SIMULATOR ?= verilator # Timeout for simulation, default 120 TIMEOUT ?= 120 +# Export variables to sub-makefiles +export + ## @section Conda conda: environment.yml conda env create -f environment.yml @@ -175,7 +179,7 @@ run-helloworld: mcu-gen verilator-sim ## Uses verilator to simulate the HW model and run the FW ## UART Dumping in uart0.log to show recollected results run-blinkyfreertos: mcu-gen verilator-sim - $(MAKE) -C sw PROJECT=blinky_freertos TARGET=$(TARGET) LINKER=$(LINKER) COMPILER=$(COMPILER) COMPILER_PREFIX=$(COMPILER_PREFIX) ARCH=$(ARCH); + $(MAKE) -C sw PROJECT=example_freertos_blinky TARGET=$(TARGET) LINKER=$(LINKER) COMPILER=$(COMPILER) COMPILER_PREFIX=$(COMPILER_PREFIX) ARCH=$(ARCH); cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim-verilator; \ ./Vtestharness +firmware=../../../sw/build/main.hex; \ cat uart0.log; \ diff --git a/README.md b/README.md index e63003cfc..b02d2712f 100644 --- a/README.md +++ b/README.md @@ -153,7 +153,7 @@ sudo apt-get install -y gtkwave We use version v0.0-1824-ga3b5bedf -See: [Install Verible](https://opentitan.org/guides/getting_started/index.html#step-6a-install-verible-optional) +See: [Install Verible](https://opentitan.org/guides/getting_started/index.html#step-7a-install-verible-optional) To format your RTL code type: @@ -514,9 +514,20 @@ to load the binaries with the HS2 cable over JTAG, or follow the [ExecuteFromFlash](./ExecuteFromFlash.md) guide if you have a FLASH attached to the FPGA. - Do not forget that the `pynq-z2` board requires you to have the ethernet cable attached to the board while running. +For example, if you want to run your application using flash_exec, do as follow: + +compile your application, e.g. `make app PROJECT=example_matfadd TARGET=pynq-z2 ARCH=rv32imfc LINKER=flash_exec` + +and then follow the [ExecuteFromFlash](./ExecuteFromFlash.md) to program the flash and set the boot buttons on the FPGA correctly. + +To look at the output of your printf, run in another terminal: + +`picocom -b 9600 -r -l --imap lfcrlf /dev/ttyUSB2` + +Please be sure to use the right `ttyUSB` number (you can discover it with `dmesg --time-format iso | grep FTDI` for example). + ### Linux-FEMU (Linux Fpga EMUlation) @@ -547,3 +558,12 @@ We are working on supporting OpenRoad and SkyWater 130nm PDK, please refer to th [OpenRoadFlow](./OpenRoadFlow.md) page. This is not ready yet, it has not been tested. This relies on a fork of [edalize](https://github.com/davideschiavone/edalize) that contains templates for Design Compiler and OpenRoad. + +## References + +1. [Schiavone, Pasquale Davide, et al. "X-HEEP: An Open-Source, Configurable and Extendible RISC-V Microcontroller." +Proceedings of the 20th ACM International Conference on Computing Frontiers. 2023.](https://dl.acm.org/doi/pdf/10.1145/3587135.3591431?casa_token=cAs3isVd0zkAAAAA:gmQBe3ip7X0Fz0hO8lSFbGN5-2fdu5vni1dxWWAIe9zCxQDW1PPerubUigOcl_an8HiZOhPuNrwzIw8) + + + + diff --git a/docs/source/How_to/ExecuteFromFlash.md b/docs/source/How_to/ExecuteFromFlash.md index a168a5b01..8413a1299 100644 --- a/docs/source/How_to/ExecuteFromFlash.md +++ b/docs/source/How_to/ExecuteFromFlash.md @@ -19,6 +19,8 @@ These three modes are mainly controlled by the two inputs pins | 1 | 1 | SPI Flash Execution | | 1 | 0 | SPI Flash Loading | + +On the FPGA, such inputs are mapped to two switch buttons. Below, a description of the three modes is provided. ### JTAG Boot Procedure diff --git a/docs/source/How_to/ExternalDevices.md b/docs/source/How_to/ExternalDevices.md index 530b9817b..bbc89bd32 100644 --- a/docs/source/How_to/ExternalDevices.md +++ b/docs/source/How_to/ExternalDevices.md @@ -97,3 +97,55 @@ For example, launching the script [`memcopy_periph_gen.sh`](./../../../hw/ip_exa 1. `memcopy_periph_reg_top.sv`: the register file module. It can be directly instantiated inside your peripheral RTL code (e.g., [`memcopy_periph.sv`](./../../../hw/ip_examples/memcopy_periph/rtl/memcopy_periph.sv)) and connected to the peripheral device controller(s). 2. `memcopy_periph_reg_pkg.sv`: SystemVerilog package containing the definitions used in the SystemVerilog module above. 3. `memcopy_periph_regs.h`: C/C++ header file defining the address offset of the peripheral configuration registers. Take a look at the C code [here](./../../../sw/applications/example_external_peripheral/memcopy_periph.c) for a usage example. + +## External Interrupts + +X-HEEP includes several empty external interrupts slots that can be assigned both in HW and SW. + +Firstly, connect your external device's interrupt to one of the slots of the `external_interrupt_vector` of X-HEEP: + +```systemverilog + +logic [core_v_mini_mcu_pkg::NEXT_INT-1:0] ext_intr_vector; + +always_comb begin +for (int i = 0; i < core_v_mini_mcu_pkg::NEXT_INT; i++) begin + ext_intr_vector[i] = 1'b0; // All interrupt lines set to zero by default +end +ext_intr_vector[0] = my_device_int; // Re-assign the interrupt lines used here +end + +x_heep_system #( + . . . +) x_heep_system_i ( + .intr_vector_ext_i(ext_intr_vector), + . . . +) + +``` + +Then, when initializing the PLIC system in software, do not forget to assign the corresponding interrupt ID to your custom handler. + +```C +#define MY_DEVICE_INTR EXT_INTR_0 + +void handler_irq_my_device(uint32_t id) { + my_device_intr_flag = 1; + // Do whatever you need here +} + +void main() { + plic_Init(); // Init the PLIC, this will clear all external interrupts assigned previously. + plic_irq_set_priority(MY_DEVICE_INTR, 1); // Set the priority of the external device's interrupt. + plic_irq_set_enabled(MY_DEVICE_INTR, kPlicToggleEnabled); // Enable the external device's interrupt. + plic_assign_external_irq_handler( MY_DEVICE_INTR, (void *) &handler_irq_my_device); // Assign a handler taht will be called when this interrupt is triggered. + + // Enable global interrupt for machine-level interrupts + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + // Set mie.MEIE bit to one to enable machine-level external interrupts + const uint32_t mask = 1 << 11;//IRQ_EXT_ENABLE_OFFSET; + CSR_SET_BITS(CSR_REG_MIE, mask); + + . . . +} +``` \ 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 index 4a3073b89..504fed223 100644 --- a/hw/core-v-mini-mcu/ao_peripheral_subsystem.sv +++ b/hw/core-v-mini-mcu/ao_peripheral_subsystem.sv @@ -118,7 +118,10 @@ module ao_peripheral_subsystem // EXTERNAL PERIPH output reg_req_t ext_peripheral_slave_req_o, - input reg_rsp_t ext_peripheral_slave_resp_i + input reg_rsp_t ext_peripheral_slave_resp_i, + + input logic ext_dma_slot_tx_i, + input logic ext_dma_slot_rx_i ); import core_v_mini_mcu_pkg::*; @@ -364,13 +367,15 @@ module ao_peripheral_subsystem .intr_timer_expired_1_0_o(rv_timer_1_intr_o) ); - parameter DMA_TRIGGER_SLOT_NUM = 5; + parameter DMA_TRIGGER_SLOT_NUM = 7; logic [DMA_TRIGGER_SLOT_NUM-1:0] dma_trigger_slots; assign dma_trigger_slots[0] = spi_rx_valid; assign dma_trigger_slots[1] = spi_tx_ready; 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; dma #( .reg_req_t (reg_pkg::reg_req_t), diff --git a/hw/core-v-mini-mcu/core_v_mini_mcu.sv b/hw/core-v-mini-mcu/core_v_mini_mcu.sv index 4a1ef2e97..3b86b0954 100644 --- a/hw/core-v-mini-mcu/core_v_mini_mcu.sv +++ b/hw/core-v-mini-mcu/core_v_mini_mcu.sv @@ -315,7 +315,10 @@ module core_v_mini_mcu 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 + 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::*; @@ -628,7 +631,9 @@ module core_v_mini_mcu .uart_intr_rx_parity_err_o(uart_intr_rx_parity_err), .i2s_rx_valid_i(i2s_rx_valid), .ext_peripheral_slave_req_o, - .ext_peripheral_slave_resp_i + .ext_peripheral_slave_resp_i, + .ext_dma_slot_tx_i, + .ext_dma_slot_rx_i ); peripheral_subsystem peripheral_subsystem_i ( 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 b4935df46..4dcfc0f01 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 @@ -69,7 +69,10 @@ ${pad.core_v_mini_mcu_interface} 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 + 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::*; @@ -380,7 +383,9 @@ ${pad.core_v_mini_mcu_interface} .uart_intr_rx_parity_err_o(uart_intr_rx_parity_err), .i2s_rx_valid_i(i2s_rx_valid), .ext_peripheral_slave_req_o, - .ext_peripheral_slave_resp_i + .ext_peripheral_slave_resp_i, + .ext_dma_slot_tx_i, + .ext_dma_slot_rx_i ); peripheral_subsystem peripheral_subsystem_i ( diff --git a/hw/fpga/scripts/xilinx_generate_clk_wizard.tcl b/hw/fpga/scripts/xilinx_generate_clk_wizard.tcl index 6a01c149f..1c2a41a09 100644 --- a/hw/fpga/scripts/xilinx_generate_clk_wizard.tcl +++ b/hw/fpga/scripts/xilinx_generate_clk_wizard.tcl @@ -5,7 +5,7 @@ set design_name xilinx_clk_wizard set in_clk_freq_MHz 125 -set out_clk_freq_MHz 20 +set out_clk_freq_MHz 15 # Select board set_property -name "board_part_repo_paths" -value "[file normalize "../../../hw/fpga/board_files/"]" -objects [current_project] @@ -25,7 +25,7 @@ set_property -dict [ list \ CONFIG.CLKIN1_JITTER_PS {80.0} \ CONFIG.CLKOUT1_JITTER {172.798} \ CONFIG.CLKOUT1_PHASE_ERROR {96.948} \ - CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {20} \ + CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {15} \ CONFIG.MMCM_CLKFBOUT_MULT_F {8.000} \ CONFIG.MMCM_CLKIN1_PERIOD {8.000} \ CONFIG.MMCM_CLKOUT0_DIVIDE_F {50.000} \ diff --git a/hw/fpga/xilinx_core_v_mini_mcu_wrapper.sv b/hw/fpga/xilinx_core_v_mini_mcu_wrapper.sv index 1324bfb11..de6ab4582 100644 --- a/hw/fpga/xilinx_core_v_mini_mcu_wrapper.sv +++ b/hw/fpga/xilinx_core_v_mini_mcu_wrapper.sv @@ -191,7 +191,9 @@ module xilinx_core_v_mini_mcu_wrapper .pdm2pcm_pdm_io, .i2s_sck_io(i2s_sck_io), .i2s_ws_io(i2s_ws_io), - .i2s_sd_io(i2s_sd_io) + .i2s_sd_io(i2s_sd_io), + .ext_dma_slot_tx_i('0), + .ext_dma_slot_rx_i('0) ); assign exit_value_o = exit_value[0]; diff --git a/hw/ip_examples/iffifo/data/iffifo.hjson b/hw/ip_examples/iffifo/data/iffifo.hjson new file mode 100644 index 000000000..919cceaf6 --- /dev/null +++ b/hw/ip_examples/iffifo/data/iffifo.hjson @@ -0,0 +1,76 @@ +// Copyright EPFL contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +{ name: "iffifo" + clock_primary: "clk_i" + bus_interfaces: [ + { protocol: "reg_iface", direction: "device" } + ], + regwidth: 32 + registers: [ + + { name: "FIFO_OUT" + desc: "Data coming from the FIFO (Fifo Output/Software RX)" + swaccess: "ro" + hwaccess: "hrw" # required for RE signal + hwext: "true" # required for RE signal + hwre: "true" # Used to emulate a window behaviour + fields: [ + { bits: "31:0" } + ] + } + + { name: "FIFO_IN" + desc: "Data sent to the FIFO (Fifo Input/Software TX)" + hwaccess: "hro" + swaccess: "rw" # required for QE signal + hwqe: "true" # Used to emulate a window behaviour + fields: [ + { bits: "31:0" } + ] + } + + { name: "STATUS" + desc: "General purpose status register" + swaccess: "ro" + hwaccess: "hwo" + fields: [ + { bits: "0", name: "EMPTY", desc: "Asserted when FIFO empty." } + { bits: "1", name: "AVAILABLE", desc: "Asserted when data is available in FIFO." } + { bits: "2", name: "REACHED", desc: "Asserted when occupied data slots count greater than threshold." } + { bits: "3", name: "FULL", desc: "Asserted when all FIFO slots are occupied." } + ] + } + + { name: "OCCUPANCY" + desc: "Current number of occupied FIFO slots" + swaccess: "ro" + hwaccess: "hwo" + fields: [ + { bits: "31:0" } + ] + } + + { name: "WATERMARK" + desc: "FIFO occupancy at which the STATUS:REACHED bit is asserted" + swaccess: "rw" + hwaccess: "hro" + fields: [ + { bits: "31:0" } + ] + } + + { name: "INTERRUPTS" + desc: "Write any value to assert an interrupt. Write 0 or 1 to disable or enable an interrupt." + swaccess: "rw" + hwaccess: "hro" + hwqe: "true" # Used to catch software writes + fields: [ + { bits: "0", name: "REACHED", desc: "Watermark reached interrupt" } + ] + } + + ] +} + diff --git a/hw/ip_examples/iffifo/iffifo.core b/hw/ip_examples/iffifo/iffifo.core new file mode 100644 index 000000000..f0e234634 --- /dev/null +++ b/hw/ip_examples/iffifo/iffifo.core @@ -0,0 +1,26 @@ +CAPI=2: + +name: "example:ip:iffifo" +description: "core-v-mini-mcu iffifo peripheral" + +# Copyright 2023 EPFL +# Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +# +# Author: Pierre Guillod , EPFL, STI-SEL +# Date: 18.10.2023 + +filesets: + files_rtl: + depend: + - pulp-platform.org::common_cells + files: + - rtl/iffifo_reg_pkg.sv + - rtl/iffifo_reg_top.sv + - rtl/iffifo.sv + file_type: systemVerilogSource + +targets: + default: + filesets: + - files_rtl diff --git a/hw/ip_examples/iffifo/iffifo.vlt b/hw/ip_examples/iffifo/iffifo.vlt new file mode 100644 index 000000000..9820d0381 --- /dev/null +++ b/hw/ip_examples/iffifo/iffifo.vlt @@ -0,0 +1,15 @@ +// Copyright 2023 EPFL +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Author: Pierre Guillod , EPFL, STI-SEL +// Date: 18.10.2023 + +`verilator_config + +lint_off -rule DECLFILENAME -file "*/iffifo/rtl/iffifo_reg_top.sv" -match "Filename 'iffifo_reg_top' does not match MODULE name: 'iffifo_reg_top_intf'*" +lint_off -rule WIDTH -file "*/iffifo/rtl/iffifo_reg_top.sv" -match "Operator ASSIGNW expects 3 bits on the Assign RHS, but Assign RHS's SEL generates 32*" +lint_off -rule UNUSED -file "*/iffifo/rtl/iffifo.sv" -match "Bits of signal are not used: 'reg2hw'[0]*" + +lint_off -rule UNUSED -file "*/iffifo/rtl/iffifo_window.sv" -match "Bits of signal are not used: 'rx_win_i'[67:64,31:0]" +lint_off -rule WIDTH -file "*/iffifo/rtl/iffifo_*.sv" -match "Operator ASSIGNW expects*" diff --git a/hw/ip_examples/iffifo/iffifo_gen.sh b/hw/ip_examples/iffifo/iffifo_gen.sh new file mode 100755 index 000000000..45cc8f1cc --- /dev/null +++ b/hw/ip_examples/iffifo/iffifo_gen.sh @@ -0,0 +1,8 @@ +# Copyright EPFL contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +echo "Generating RTL" +${PYTHON} ../../vendor/pulp_platform_register_interface/vendor/lowrisc_opentitan/util/regtool.py -r -t rtl data/iffifo.hjson +echo "Generating SW" +${PYTHON} ../../vendor/pulp_platform_register_interface/vendor/lowrisc_opentitan/util/regtool.py --cdefines -o ../../../sw/device/lib/drivers/iffifo/iffifo_regs.h data/iffifo.hjson diff --git a/hw/ip_examples/iffifo/rtl/iffifo.sv b/hw/ip_examples/iffifo/rtl/iffifo.sv new file mode 100644 index 000000000..35a6b008b --- /dev/null +++ b/hw/ip_examples/iffifo/rtl/iffifo.sv @@ -0,0 +1,115 @@ +// Copyright 2023 EPFL +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Author: Pierre Guillod , EPFL, STI-SEL +// Date: 18.10.2023 + +module iffifo #( + parameter type reg_req_t = logic, + parameter type reg_rsp_t = logic, + localparam int WIDTH = 32, + localparam int DEPTH = 4, + localparam int DEPTHw = $clog2(DEPTH + 1) +) ( + input logic clk_i, + input logic rst_ni, + input reg_req_t reg_req_i, + output reg_rsp_t reg_rsp_o, + + // DMA slots + output logic iffifo_in_ready_o, + output logic iffifo_out_valid_o, + + // Interrupt lines + output logic iffifo_int_o +); + + import iffifo_reg_pkg::*; + + iffifo_reg2hw_t reg2hw; + iffifo_hw2reg_t hw2reg; + + logic [WIDTH-1:0] fifout; + logic [DEPTHw-1:0] occupancy; + logic empty, full, reached, available; + + assign hw2reg.fifo_out.d = fifout + 1; + + // Status (full/empty/watermark) reporting circuitry + assign empty = (occupancy == 0); + assign available = !empty; + assign hw2reg.status.empty.de = 1; + assign hw2reg.status.empty.d = empty; + assign hw2reg.status.available.de = 1; + assign hw2reg.status.available.d = available; + assign hw2reg.status.full.de = 1; + assign hw2reg.status.full.d = full; + assign hw2reg.status.reached.de = 1; + assign hw2reg.status.reached.d = reached; + assign hw2reg.occupancy.de = 1; + assign hw2reg.occupancy.d = {{32 - DEPTHw{1'b0}}, occupancy}; + assign reached = ({{32 - DEPTHw{1'b0}}, occupancy} >= reg2hw.watermark.q); + + // Interrupts circuitry + always_ff @(posedge clk_i or negedge rst_ni) begin + if (~rst_ni) begin + + iffifo_int_o <= 0; + + end else begin + + // Interrupts firing + if (reached & reg2hw.interrupts.q) begin + iffifo_int_o <= 1; + end + + // Interrupts assertion + if (reg2hw.interrupts.qe) begin + iffifo_int_o <= 0; + end + + end + end + + iffifo_reg_top #( + .reg_req_t(reg_req_t), + .reg_rsp_t(reg_rsp_t) + ) iffifo_reg_top_i ( + .clk_i, + .rst_ni, + .reg2hw, + .hw2reg, + .reg_req_i, + .reg_rsp_o, + .devmode_i(1'b0) + ); + + prim_fifo_sync #( + .Width(WIDTH), + .Depth(DEPTH), + .Pass(1'b0), + .OutputZeroIfEmpty(1'b0) + ) iffifo_fifo_i ( + + .clk_i, + .rst_ni, + .clr_i(1'b0), + + // From DMA (output) to FIFO (input, TX) + .wvalid_i(reg2hw.fifo_in.qe), + .wready_o(iffifo_in_ready_o), + .wdata_i (reg2hw.fifo_in.q), + + // From FIFO (output) to DMA (input, RX) + .rvalid_o(iffifo_out_valid_o), + .rready_i(reg2hw.fifo_out.re), + .rdata_o (fifout), + + .full_o (full), + .depth_o(occupancy) + + ); + +endmodule : iffifo + diff --git a/hw/ip_examples/iffifo/rtl/iffifo_reg_pkg.sv b/hw/ip_examples/iffifo/rtl/iffifo_reg_pkg.sv new file mode 100644 index 000000000..e362798d5 --- /dev/null +++ b/hw/ip_examples/iffifo/rtl/iffifo_reg_pkg.sv @@ -0,0 +1,106 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Register Package auto-generated by `reggen` containing data structure + +package iffifo_reg_pkg; + + // Address widths within the block + parameter int BlockAw = 5; + + //////////////////////////// + // Typedefs for registers // + //////////////////////////// + + typedef struct packed { + logic [31:0] q; + logic re; + } iffifo_reg2hw_fifo_out_reg_t; + + typedef struct packed { + logic [31:0] q; + logic qe; + } iffifo_reg2hw_fifo_in_reg_t; + + typedef struct packed {logic [31:0] q;} iffifo_reg2hw_watermark_reg_t; + + typedef struct packed { + logic q; + logic qe; + } iffifo_reg2hw_interrupts_reg_t; + + typedef struct packed {logic [31:0] d;} iffifo_hw2reg_fifo_out_reg_t; + + typedef struct packed { + struct packed { + logic d; + logic de; + } empty; + struct packed { + logic d; + logic de; + } available; + struct packed { + logic d; + logic de; + } reached; + struct packed { + logic d; + logic de; + } full; + } iffifo_hw2reg_status_reg_t; + + typedef struct packed { + logic [31:0] d; + logic de; + } iffifo_hw2reg_occupancy_reg_t; + + // Register -> HW type + typedef struct packed { + iffifo_reg2hw_fifo_out_reg_t fifo_out; // [99:67] + iffifo_reg2hw_fifo_in_reg_t fifo_in; // [66:34] + iffifo_reg2hw_watermark_reg_t watermark; // [33:2] + iffifo_reg2hw_interrupts_reg_t interrupts; // [1:0] + } iffifo_reg2hw_t; + + // HW -> register type + typedef struct packed { + iffifo_hw2reg_fifo_out_reg_t fifo_out; // [72:41] + iffifo_hw2reg_status_reg_t status; // [40:33] + iffifo_hw2reg_occupancy_reg_t occupancy; // [32:0] + } iffifo_hw2reg_t; + + // Register offsets + parameter logic [BlockAw-1:0] IFFIFO_FIFO_OUT_OFFSET = 5'h0; + parameter logic [BlockAw-1:0] IFFIFO_FIFO_IN_OFFSET = 5'h4; + parameter logic [BlockAw-1:0] IFFIFO_STATUS_OFFSET = 5'h8; + parameter logic [BlockAw-1:0] IFFIFO_OCCUPANCY_OFFSET = 5'hc; + parameter logic [BlockAw-1:0] IFFIFO_WATERMARK_OFFSET = 5'h10; + parameter logic [BlockAw-1:0] IFFIFO_INTERRUPTS_OFFSET = 5'h14; + + // Reset values for hwext registers and their fields + parameter logic [31:0] IFFIFO_FIFO_OUT_RESVAL = 32'h0; + + // Register index + typedef enum int { + IFFIFO_FIFO_OUT, + IFFIFO_FIFO_IN, + IFFIFO_STATUS, + IFFIFO_OCCUPANCY, + IFFIFO_WATERMARK, + IFFIFO_INTERRUPTS + } iffifo_id_e; + + // Register width information to check illegal writes + parameter logic [3:0] IFFIFO_PERMIT[6] = '{ + 4'b1111, // index[0] IFFIFO_FIFO_OUT + 4'b1111, // index[1] IFFIFO_FIFO_IN + 4'b0001, // index[2] IFFIFO_STATUS + 4'b1111, // index[3] IFFIFO_OCCUPANCY + 4'b1111, // index[4] IFFIFO_WATERMARK + 4'b0001 // index[5] IFFIFO_INTERRUPTS + }; + +endpackage + diff --git a/hw/ip_examples/iffifo/rtl/iffifo_reg_top.sv b/hw/ip_examples/iffifo/rtl/iffifo_reg_top.sv new file mode 100644 index 000000000..cd8d2f560 --- /dev/null +++ b/hw/ip_examples/iffifo/rtl/iffifo_reg_top.sv @@ -0,0 +1,451 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Register Top module auto-generated by `reggen` + + +`include "common_cells/assertions.svh" + +module iffifo_reg_top #( + parameter type reg_req_t = logic, + parameter type reg_rsp_t = logic, + parameter int AW = 5 +) ( + input logic clk_i, + input logic rst_ni, + input reg_req_t reg_req_i, + output reg_rsp_t reg_rsp_o, + // To HW + output iffifo_reg_pkg::iffifo_reg2hw_t reg2hw, // Write + input iffifo_reg_pkg::iffifo_hw2reg_t hw2reg, // Read + + + // Config + input devmode_i // If 1, explicit error return for unmapped register access +); + + import iffifo_reg_pkg::*; + + localparam int DW = 32; + localparam int DBW = DW / 8; // Byte Width + + // register signals + logic reg_we; + logic reg_re; + logic [ AW-1:0] reg_addr; + logic [ DW-1:0] reg_wdata; + logic [DBW-1:0] reg_be; + logic [ DW-1:0] reg_rdata; + logic reg_error; + + logic addrmiss, wr_err; + + logic [DW-1:0] reg_rdata_next; + + // Below register interface can be changed + reg_req_t reg_intf_req; + reg_rsp_t reg_intf_rsp; + + + assign reg_intf_req = reg_req_i; + assign reg_rsp_o = reg_intf_rsp; + + + assign reg_we = reg_intf_req.valid & reg_intf_req.write; + assign reg_re = reg_intf_req.valid & ~reg_intf_req.write; + assign reg_addr = reg_intf_req.addr; + assign reg_wdata = reg_intf_req.wdata; + assign reg_be = reg_intf_req.wstrb; + assign reg_intf_rsp.rdata = reg_rdata; + assign reg_intf_rsp.error = reg_error; + assign reg_intf_rsp.ready = 1'b1; + + assign reg_rdata = reg_rdata_next; + assign reg_error = (devmode_i & addrmiss) | wr_err; + + + // Define SW related signals + // Format: __{wd|we|qs} + // or _{wd|we|qs} if field == 1 or 0 + logic [31:0] fifo_out_qs; + logic fifo_out_re; + logic [31:0] fifo_in_qs; + logic [31:0] fifo_in_wd; + logic fifo_in_we; + logic status_empty_qs; + logic status_available_qs; + logic status_reached_qs; + logic status_full_qs; + logic [31:0] occupancy_qs; + logic [31:0] watermark_qs; + logic [31:0] watermark_wd; + logic watermark_we; + logic interrupts_qs; + logic interrupts_wd; + logic interrupts_we; + + // Register instances + // R[fifo_out]: V(True) + + prim_subreg_ext #( + .DW(32) + ) u_fifo_out ( + .re (fifo_out_re), + .we (1'b0), + .wd ('0), + .d (hw2reg.fifo_out.d), + .qre(reg2hw.fifo_out.re), + .qe (), + .q (reg2hw.fifo_out.q), + .qs (fifo_out_qs) + ); + + + // R[fifo_in]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("RW"), + .RESVAL (32'h0) + ) u_fifo_in ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(fifo_in_we), + .wd(fifo_in_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(reg2hw.fifo_in.qe), + .q (reg2hw.fifo_in.q), + + // to register interface (read) + .qs(fifo_in_qs) + ); + + + // R[status]: V(False) + + // F[empty]: 0:0 + prim_subreg #( + .DW (1), + .SWACCESS("RO"), + .RESVAL (1'h0) + ) u_status_empty ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + .we(1'b0), + .wd('0), + + // from internal hardware + .de(hw2reg.status.empty.de), + .d (hw2reg.status.empty.d), + + // to internal hardware + .qe(), + .q (), + + // to register interface (read) + .qs(status_empty_qs) + ); + + + // F[available]: 1:1 + prim_subreg #( + .DW (1), + .SWACCESS("RO"), + .RESVAL (1'h0) + ) u_status_available ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + .we(1'b0), + .wd('0), + + // from internal hardware + .de(hw2reg.status.available.de), + .d (hw2reg.status.available.d), + + // to internal hardware + .qe(), + .q (), + + // to register interface (read) + .qs(status_available_qs) + ); + + + // F[reached]: 2:2 + prim_subreg #( + .DW (1), + .SWACCESS("RO"), + .RESVAL (1'h0) + ) u_status_reached ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + .we(1'b0), + .wd('0), + + // from internal hardware + .de(hw2reg.status.reached.de), + .d (hw2reg.status.reached.d), + + // to internal hardware + .qe(), + .q (), + + // to register interface (read) + .qs(status_reached_qs) + ); + + + // F[full]: 3:3 + prim_subreg #( + .DW (1), + .SWACCESS("RO"), + .RESVAL (1'h0) + ) u_status_full ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + .we(1'b0), + .wd('0), + + // from internal hardware + .de(hw2reg.status.full.de), + .d (hw2reg.status.full.d), + + // to internal hardware + .qe(), + .q (), + + // to register interface (read) + .qs(status_full_qs) + ); + + + // R[occupancy]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("RO"), + .RESVAL (32'h0) + ) u_occupancy ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + .we(1'b0), + .wd('0), + + // from internal hardware + .de(hw2reg.occupancy.de), + .d (hw2reg.occupancy.d), + + // to internal hardware + .qe(), + .q (), + + // to register interface (read) + .qs(occupancy_qs) + ); + + + // R[watermark]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("RW"), + .RESVAL (32'h0) + ) u_watermark ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(watermark_we), + .wd(watermark_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.watermark.q), + + // to register interface (read) + .qs(watermark_qs) + ); + + + // R[interrupts]: V(False) + + prim_subreg #( + .DW (1), + .SWACCESS("RW"), + .RESVAL (1'h0) + ) u_interrupts ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(interrupts_we), + .wd(interrupts_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(reg2hw.interrupts.qe), + .q (reg2hw.interrupts.q), + + // to register interface (read) + .qs(interrupts_qs) + ); + + + + + logic [5:0] addr_hit; + always_comb begin + addr_hit = '0; + addr_hit[0] = (reg_addr == IFFIFO_FIFO_OUT_OFFSET); + addr_hit[1] = (reg_addr == IFFIFO_FIFO_IN_OFFSET); + addr_hit[2] = (reg_addr == IFFIFO_STATUS_OFFSET); + addr_hit[3] = (reg_addr == IFFIFO_OCCUPANCY_OFFSET); + addr_hit[4] = (reg_addr == IFFIFO_WATERMARK_OFFSET); + addr_hit[5] = (reg_addr == IFFIFO_INTERRUPTS_OFFSET); + end + + assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0; + + // Check sub-word write is permitted + always_comb begin + wr_err = (reg_we & + ((addr_hit[0] & (|(IFFIFO_PERMIT[0] & ~reg_be))) | + (addr_hit[1] & (|(IFFIFO_PERMIT[1] & ~reg_be))) | + (addr_hit[2] & (|(IFFIFO_PERMIT[2] & ~reg_be))) | + (addr_hit[3] & (|(IFFIFO_PERMIT[3] & ~reg_be))) | + (addr_hit[4] & (|(IFFIFO_PERMIT[4] & ~reg_be))) | + (addr_hit[5] & (|(IFFIFO_PERMIT[5] & ~reg_be))))); + end + + assign fifo_out_re = addr_hit[0] & reg_re & !reg_error; + + assign fifo_in_we = addr_hit[1] & reg_we & !reg_error; + assign fifo_in_wd = reg_wdata[31:0]; + + assign watermark_we = addr_hit[4] & reg_we & !reg_error; + assign watermark_wd = reg_wdata[31:0]; + + assign interrupts_we = addr_hit[5] & reg_we & !reg_error; + assign interrupts_wd = reg_wdata[0]; + + // Read data return + always_comb begin + reg_rdata_next = '0; + unique case (1'b1) + addr_hit[0]: begin + reg_rdata_next[31:0] = fifo_out_qs; + end + + addr_hit[1]: begin + reg_rdata_next[31:0] = fifo_in_qs; + end + + addr_hit[2]: begin + reg_rdata_next[0] = status_empty_qs; + reg_rdata_next[1] = status_available_qs; + reg_rdata_next[2] = status_reached_qs; + reg_rdata_next[3] = status_full_qs; + end + + addr_hit[3]: begin + reg_rdata_next[31:0] = occupancy_qs; + end + + addr_hit[4]: begin + reg_rdata_next[31:0] = watermark_qs; + end + + addr_hit[5]: begin + reg_rdata_next[0] = interrupts_qs; + end + + default: begin + reg_rdata_next = '1; + end + endcase + end + + // Unused signal tieoff + + // wdata / byte enable are not always fully used + // add a blanket unused statement to handle lint waivers + logic unused_wdata; + logic unused_be; + assign unused_wdata = ^reg_wdata; + assign unused_be = ^reg_be; + + // Assertions for Register Interface + `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit)) + +endmodule + +module iffifo_reg_top_intf #( + parameter int AW = 5, + localparam int DW = 32 +) ( + input logic clk_i, + input logic rst_ni, + REG_BUS.in regbus_slave, + // To HW + output iffifo_reg_pkg::iffifo_reg2hw_t reg2hw, // Write + input iffifo_reg_pkg::iffifo_hw2reg_t hw2reg, // Read + // Config + input devmode_i // If 1, explicit error return for unmapped register access +); + localparam int unsigned STRB_WIDTH = DW / 8; + + `include "register_interface/typedef.svh" + `include "register_interface/assign.svh" + + // Define structs for reg_bus + typedef logic [AW-1:0] addr_t; + typedef logic [DW-1:0] data_t; + typedef logic [STRB_WIDTH-1:0] strb_t; + `REG_BUS_TYPEDEF_ALL(reg_bus, addr_t, data_t, strb_t) + + reg_bus_req_t s_reg_req; + reg_bus_rsp_t s_reg_rsp; + + // Assign SV interface to structs + `REG_BUS_ASSIGN_TO_REQ(s_reg_req, regbus_slave) + `REG_BUS_ASSIGN_FROM_RSP(regbus_slave, s_reg_rsp) + + + + iffifo_reg_top #( + .reg_req_t(reg_bus_req_t), + .reg_rsp_t(reg_bus_rsp_t), + .AW(AW) + ) i_regs ( + .clk_i, + .rst_ni, + .reg_req_i(s_reg_req), + .reg_rsp_o(s_reg_rsp), + .reg2hw, // Write + .hw2reg, // Read + .devmode_i + ); + +endmodule + + diff --git a/hw/system/x_heep_system.sv.tpl b/hw/system/x_heep_system.sv.tpl index 7d58ed796..c88bdacad 100644 --- a/hw/system/x_heep_system.sv.tpl +++ b/hw/system/x_heep_system.sv.tpl @@ -48,6 +48,9 @@ module x_heep_system output logic [31:0] exit_value_o, + input logic ext_dma_slot_tx_i, + input logic ext_dma_slot_rx_i, + // eXtension interface if_xif.cpu_compressed xif_compressed_if, if_xif.cpu_issue xif_issue_if, @@ -137,7 +140,9 @@ ${pad.core_v_mini_mcu_bonding} .external_subsystem_rst_no, .external_ram_banks_set_retentive_no, .external_subsystem_clkgate_en_no, - .exit_value_o + .exit_value_o, + .ext_dma_slot_tx_i, + .ext_dma_slot_rx_i ); pad_ring pad_ring_i ( diff --git a/hw/vendor/waiver/lint/cv32e40p.vlt b/hw/vendor/waiver/lint/cv32e40p.vlt index 5f55d4577..65542b42f 100644 --- a/hw/vendor/waiver/lint/cv32e40p.vlt +++ b/hw/vendor/waiver/lint/cv32e40p.vlt @@ -111,3 +111,6 @@ lint_off -rule WIDTH -file "*/rtl/cv32e40p_controller.sv" -match "Logical operat lint_off -rule WIDTH -file "*/rtl/cv32e40p_controller.sv" -match "Logical operator IF expects 1 bit on the If, but If's VARREF 'COREV_PULP' generates 32 bits." lint_off -rule WIDTH -file "*/rtl/cv32e40p_cs_registers.sv" -match "Logical operator LOGNOT expects 1 bit on the LHS, but LHS's VARREF 'COREV_PULP' generates 32 bits." lint_off -rule WIDTH -file "*/rtl/cv32e40p_decoder.sv" -match "Logical operator LOGAND expects 1 bit on the LHS, but LHS's VARREF 'FPU' generates 32 bits*" +lint_off -rule WIDTH -file "*/rtl/cv32e40p_controller.sv" -match "Logical operator LOGAND expects 1 bit on the LHS, but LHS's VARREF 'FPU' generates 32 bits.*" +lint_off -rule WIDTH -file "*/rtl/cv32e40p_cs_registers.sv" -match "Logical operator LOGOR expects 1 bit on the LHS, but LHS's VARREF 'FPU' generates 32 bits.*" +lint_off -rule LATCH -file "*/rtl/cv32e40p_id_stage.sv" -match "Latch inferred for signal*apu_read_regs*" diff --git a/hw/vendor/waiver/lint/cv32e40px.vlt b/hw/vendor/waiver/lint/cv32e40px.vlt index 480681037..a6665860b 100644 --- a/hw/vendor/waiver/lint/cv32e40px.vlt +++ b/hw/vendor/waiver/lint/cv32e40px.vlt @@ -111,3 +111,6 @@ lint_off -rule WIDTH -file "*/rtl/cv32e40px_controller.sv" -match "Logical opera lint_off -rule WIDTH -file "*/rtl/cv32e40px_controller.sv" -match "Logical operator IF expects 1 bit on the If, but If's VARREF 'COREV_PULP' generates 32 bits." lint_off -rule WIDTH -file "*/rtl/cv32e40px_cs_registers.sv" -match "Logical operator LOGNOT expects 1 bit on the LHS, but LHS's VARREF 'COREV_PULP' generates 32 bits." lint_off -rule WIDTH -file "*/rtl/cv32e40px_decoder.sv" -match "Logical operator LOGAND expects 1 bit on the LHS, but LHS's VARREF 'FPU' generates 32 bits*" +lint_off -rule WIDTH -file "*/rtl/cv32e40px_controller.sv" -match "Logical operator LOGAND expects 1 bit on the LHS, but LHS's VARREF 'FPU' generates 32 bits.*" +lint_off -rule WIDTH -file "*/rtl/cv32e40px_cs_registers.sv" -match "Logical operator LOGOR expects 1 bit on the LHS, but LHS's VARREF 'FPU' generates 32 bits.*" +lint_off -rule LATCH -file "*/rtl/cv32e40px_id_stage.sv" -match "Latch inferred for signal*apu_read_regs*" diff --git a/mcu_cfg.hjson b/mcu_cfg.hjson index 4bc1e1df9..f1d435dff 100644 --- a/mcu_cfg.hjson +++ b/mcu_cfg.hjson @@ -27,6 +27,8 @@ lenght: whatisleft, #keyword used to calculate the size as: ram.length - code.lenght } }, + stack_size: 0x800, + heap_size: 0x800, } debug: { diff --git a/sw/Makefile b/sw/Makefile index 3582fb256..745c1c057 100644 --- a/sw/Makefile +++ b/sw/Makefile @@ -38,7 +38,7 @@ COMPILER_PREFIX ?= riscv32-unknown- ARCH ?= rv32imc # Path relative from the location of sw/Makefile from which to fetch source files. The directory of that file is the default value. -SOURCE ?= "." +SOURCE ?= $(".") # riscv toolchain install path RISCV ?= ~/.riscv @@ -56,7 +56,7 @@ source_path := $(realpath $(mkfile_path)/$(SOURCE)) $(info $$You are fetching sources from $(source_path) ) -SOURCE_PATH = $(source_path)/ +SOURCE_PATH = $(source_path)/ ROOT_PROJECT = $(mkfile_path)/ INC_FOLDERS = $(mkfile_path)/device/target/$(TARGET)/ LINK_FOLDER = $(mkfile_path)/linker @@ -70,6 +70,9 @@ else CMAKE=cmake3 endif +# Export variables to sub-makefiles +export + # Let's CMake! include cmake/targets.mak diff --git a/sw/applications/example_iffifo/main.c b/sw/applications/example_iffifo/main.c new file mode 100644 index 000000000..b62fab6aa --- /dev/null +++ b/sw/applications/example_iffifo/main.c @@ -0,0 +1,206 @@ +/* + * Copyright EPFL contributors. + * Licensed under the Apache License, Version 2.0, see LICENSE for details. + * SPDX-License-Identifier: Apache-2.0 + * + * Author: Pierre Guillod + */ + +#include +#include + +#include "core_v_mini_mcu.h" + +#include "x-heep.h" +#include "iffifo_regs.h" + +#include "mmio.h" +#include "handler.h" +#include "csr.h" +#include "hart.h" + +#include "rv_plic.h" + +#include "dma.h" +#include "dma_regs.h" +#include "fast_intr_ctrl.h" + + +/* By default, printfs are activated for FPGA and disabled for simulation. */ +#define PRINTF_IN_FPGA 1 +#define PRINTF_IN_SIM 0 + +#if TARGET_SIM && PRINTF_IN_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else + #define PRINTF(...) +#endif + +unsigned int IFFIFO_START_ADDRESS = EXT_PERIPHERAL_START_ADDRESS + 0x2000; + +int32_t to_fifo [6] __attribute__ ((aligned (4))) = { 1, 2, 3, 4, 5, 6 }; +int32_t from_fifo[4] __attribute__ ((aligned (4))) = { 0, 0, 0, 0 }; + +int8_t dma_intr_flag = 0; +void dma_intr_handler_trans_done() +{ + dma_intr_flag = 1; +} + +void protected_wait_for_dma_interrupt(void) +{ + while(!dma_is_ready()) { + CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); + if (!dma_is_ready()) { + wait_for_interrupt(); + } + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + } +} + +iffifo_intr_flag = 0; +static void handler_irq_iffifo( uint32_t int_id ) +{ + mmio_region_t iffifo_base_addr = mmio_region_from_addr((uintptr_t)IFFIFO_START_ADDRESS); + mmio_region_write32(iffifo_base_addr, IFFIFO_INTERRUPTS_REG_OFFSET, 0b0); + iffifo_intr_flag = 1; + PRINTF(" ** REACH intr. fired.\n"); +} + +static dma_target_t tgt_src; +static dma_target_t tgt_dst; +static dma_trans_t trans; + +int compare_print_fifo_array(void) { + int errors = 0; + PRINTF("from_fifo = {"); + for (int i = 0; i < 4; i+=1) { + PRINTF("%d",from_fifo[i]); + if(i != 4-1) {PRINTF(", ");}; + if (to_fifo[i]+1 != from_fifo[i]) {++errors;} + } + PRINTF("}\n"); + return errors; +} + +void print_status_register(void) +{ + mmio_region_t iffifo_base_addr = mmio_region_from_addr((uintptr_t)IFFIFO_START_ADDRESS); + int32_t status = mmio_region_read32(iffifo_base_addr, IFFIFO_STATUS_REG_OFFSET); + PRINTF("STATUS = "); + PRINTF(status & (1 << IFFIFO_STATUS_EMPTY_BIT) ? "E" : "-"); // FIFO empty + PRINTF(status & (1 << IFFIFO_STATUS_AVAILABLE_BIT) ? "A" : "-"); // Data available in FIFO + PRINTF(status & (1 << IFFIFO_STATUS_REACHED_BIT) ? "R" : "-"); // Watermark reached + PRINTF(status & (1 << IFFIFO_STATUS_FULL_BIT) ? "F" : "-"); // FIFO full + PRINTF("\n"); +} + +int is_iffifo_full(void) +{ + mmio_region_t iffifo_base_addr = mmio_region_from_addr((uintptr_t)IFFIFO_START_ADDRESS); + int32_t status = mmio_region_read32(iffifo_base_addr, IFFIFO_STATUS_REG_OFFSET); + return status & (1 << IFFIFO_STATUS_FULL_BIT); +} + +int main(int argc, char *argv[]) { + + mmio_region_t iffifo_base_addr = mmio_region_from_addr((uintptr_t)IFFIFO_START_ADDRESS); + + // Enable interrupt on processor side + // Enable global interrupt for machine-level interrupts + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + // Set mie.MEIE bit to one to enable machine-level external interrupts + 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;}; + + plic_assign_external_irq_handler(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); + + dma_config_flags_t ret; + + // -- DMA CONFIGURATION -- + + dma_init(NULL); + tgt_src.ptr = to_fifo; + tgt_src.inc_du = 1; + tgt_src.trig = DMA_TRIG_MEMORY; + tgt_src.type = DMA_DATA_TYPE_WORD; + tgt_src.size_du = 6; + + 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.type = DMA_DATA_TYPE_WORD; + + trans.src = &tgt_src; + trans.dst = &tgt_dst; + trans.end = DMA_TRANS_END_INTR; + + ret = dma_validate_transaction( &trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY ); + if (ret != 0) {return EXIT_FAILURE;} + ret = dma_load_transaction(&trans); + if (ret != 0) {return EXIT_FAILURE;} + + if (compare_print_fifo_array() != 4) {return EXIT_FAILURE;} + + print_status_register(); + + PRINTF("Launch MM -> Stream DMA\n"); + // Launch a 6-word TX DMA transaction to a 4-word FIFO. The FIFO will be full. + dma_launch( &trans ); + + // To terminate the DMA transaction, 2 words must be manually popped from the FIFO. + while(!is_iffifo_full()); + int32_t read0 = mmio_region_read32(iffifo_base_addr, IFFIFO_FIFO_OUT_REG_OFFSET); + while(!is_iffifo_full()); + int32_t read1 = mmio_region_read32(iffifo_base_addr, IFFIFO_FIFO_OUT_REG_OFFSET); + + print_status_register(); + + PRINTF("Manual readings: {%d, %d}\n", read0, read1); + + protected_wait_for_dma_interrupt(); + + 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.type = DMA_DATA_TYPE_WORD; + tgt_src.size_du = 4; + + tgt_dst.ptr = from_fifo; + tgt_dst.inc_du = 1; + tgt_dst.trig = DMA_TRIG_MEMORY; + tgt_dst.type = DMA_DATA_TYPE_WORD; + + trans.src = &tgt_src; + trans.dst = &tgt_dst; + trans.end = DMA_TRANS_END_INTR; + + ret = dma_validate_transaction( &trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY ); + if (ret != 0) {return EXIT_FAILURE;} + ret = dma_load_transaction(&trans); + if (ret != 0) {return EXIT_FAILURE;} + PRINTF("Launch Stream -> MM DMA\n"); + dma_launch( &trans ); + + protected_wait_for_dma_interrupt(); + + print_status_register(); + + if (compare_print_fifo_array() == 0) {return EXIT_FAILURE;}; + + if (!iffifo_intr_flag) {return EXIT_FAILURE;}; + + return EXIT_SUCCESS; + +} + diff --git a/sw/applications/example_matadd/main.c b/sw/applications/example_matadd/main.c index 5e4069a2b..80fdb6555 100644 --- a/sw/applications/example_matadd/main.c +++ b/sw/applications/example_matadd/main.c @@ -30,16 +30,17 @@ int main() int N = WIDTH; int M = HEIGHT; uint32_t errors = 0; - unsigned int instr, cycles, ldstall, jrstall, imstall; + unsigned int instr, cycles; + + //enable mcycle csr + CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); CSR_WRITE(CSR_REG_MCYCLE, 0); //execute the kernel matrixAdd(m_a, m_b, m_c, N, M); - CSR_READ(CSR_REG_MCYCLE, &cycles) ; - - //stop the HW counter used for monitoring + CSR_READ(CSR_REG_MCYCLE, &cycles); errors = check_results(m_c, N, M); diff --git a/sw/applications/example_matfadd/main.c b/sw/applications/example_matfadd/main.c index e9eac70f0..ab2191bdf 100644 --- a/sw/applications/example_matfadd/main.c +++ b/sw/applications/example_matfadd/main.c @@ -117,11 +117,14 @@ int main() int N = WIDTH; int M = HEIGHT; uint32_t errors = 0; - unsigned int instr, cycles, ldstall, jrstall, imstall; + unsigned int instr, cycles; //enable FP operations CSR_SET_BITS(CSR_REG_MSTATUS, (FS_INITIAL << 13)); + //enable mcycle csr + CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + CSR_WRITE(CSR_REG_MCYCLE, 0); //execute the kernel diff --git a/sw/device/lib/drivers/dma/dma.h b/sw/device/lib/drivers/dma/dma.h index 1956f9e8b..85ee64751 100644 --- a/sw/device/lib/drivers/dma/dma.h +++ b/sw/device/lib/drivers/dma/dma.h @@ -104,6 +104,8 @@ typedef enum 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__size, /*!< Not used, only for sanity checks. */ DMA_TRIG__undef, /*!< DMA will not be used. */ } dma_trigger_slot_mask_t; @@ -463,4 +465,4 @@ uint8_t dma_window_ratio_warning_threshold(void); /** **/ /** EOF **/ /** **/ -/****************************************************************************/ \ No newline at end of file +/****************************************************************************/ diff --git a/sw/device/lib/drivers/gpio/gpio.c b/sw/device/lib/drivers/gpio/gpio.c index 8da1a2ec8..3e733ecd8 100644 --- a/sw/device/lib/drivers/gpio/gpio.c +++ b/sw/device/lib/drivers/gpio/gpio.c @@ -33,6 +33,7 @@ #include "gpio.h" #include "gpio_regs.h" // Generated. #include "gpio_structs.h" +#include "core_v_mini_mcu.h" #include "bitfield.h" #include "x-heep.h" @@ -42,6 +43,12 @@ /** **/ /****************************************************************************/ +/** + * GPIO_AO pointer + */ +#define gpio_ao_peri ((volatile gpio *) GPIO_AO_START_ADDRESS) + + /** * GPIO_EN values */ @@ -55,8 +62,8 @@ #define GPIO_REMOVE_MASK 0x00 /** - * GPIO is set or reset. The value read from gpio_peri->GPIO_IN0 or - * write to gpio_peri->GPIO_OUT0 + * GPIO is set or reset. The value read from gpio_perif->GPIO_IN0 or + * write to gpio_perif->GPIO_OUT0 */ #define GPIO_IS_SET 1 #define GPIO_IS_RESET 0 @@ -119,9 +126,19 @@ 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 */ @@ -179,11 +196,13 @@ gpio_result_t gpio_set_mode (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_peri->GPIO_MODE0 = bitfield_write(gpio_peri->GPIO_MODE0, + gpio_perif->GPIO_MODE0 = bitfield_write(gpio_perif->GPIO_MODE0, BIT_MASK_3, 2*pin, mode); else - gpio_peri->GPIO_MODE1 = bitfield_write(gpio_peri->GPIO_MODE1, + gpio_perif->GPIO_MODE1 = bitfield_write(gpio_perif->GPIO_MODE1, BIT_MASK_3, 2*(pin-GPIO_MODE_NUM_PINS), mode); return GpioOk; } @@ -192,7 +211,8 @@ gpio_result_t gpio_en_input_sampling (gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - gpio_peri->GPIO_EN0 = bitfield_write(gpio_peri->GPIO_EN0, + select_gpio_domain(pin); + gpio_perif->GPIO_EN0 = bitfield_write(gpio_perif->GPIO_EN0, BIT_MASK_1, pin, GPIO_EN__ENABLED); return GpioOk; } @@ -201,7 +221,8 @@ gpio_result_t gpio_dis_input_sampling (gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - gpio_peri->GPIO_EN0 = bitfield_write(gpio_peri->GPIO_EN0, + select_gpio_domain(pin); + gpio_perif->GPIO_EN0 = bitfield_write(gpio_perif->GPIO_EN0, BIT_MASK_1, pin, GPIO_EN__DISABLED); return GpioOk; } @@ -211,12 +232,13 @@ gpio_result_t gpio_reset (gpio_pin_number_t pin) if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - gpio_intr_set_mode (0); + gpio_intr_set_mode (pin, 0); gpio_set_mode (pin, GpioModeIn); gpio_dis_input_sampling (pin); - gpio_peri->GPIO_CLEAR0 = bitfield_write(gpio_peri->GPIO_CLEAR0, + select_gpio_domain(pin); + gpio_perif->GPIO_CLEAR0 = bitfield_write(gpio_perif->GPIO_CLEAR0, BIT_MASK_1, pin, GPIO_REMOVE_MASK); - gpio_peri->GPIO_SET0 = bitfield_write(gpio_peri->GPIO_SET0, + 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); @@ -225,17 +247,33 @@ gpio_result_t gpio_reset (gpio_pin_number_t pin) gpio_result_t gpio_reset_all (void) { - gpio_peri->GPIO_MODE0 = 0; - gpio_peri->GPIO_MODE1 = 0; - gpio_peri->GPIO_EN0 = 0; - gpio_peri->GPIO_CLEAR0 = 0; - gpio_peri->GPIO_SET0 = 0; - gpio_peri->GPIO_TOGGLE0 = 0; - gpio_peri->INTRPT_RISE_EN0 = 0; - gpio_peri->INTRPT_FALL_EN0 = 0; - gpio_peri->INTRPT_LVL_HIGH_EN0 = 0; - gpio_peri->INTRPT_LVL_LOW_EN0 = 0; - gpio_peri->INTRPT_STATUS0 = 0xFFFFFFFF; + + /* 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; + 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; gpio_reset_handlers_list( ); } @@ -244,7 +282,8 @@ gpio_result_t gpio_read (gpio_pin_number_t pin, bool *val) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - *val = bitfield_read(gpio_peri->GPIO_IN0, BIT_MASK_1, pin); + select_gpio_domain(pin); + *val = bitfield_read(gpio_perif->GPIO_IN0, BIT_MASK_1, pin); return GpioOk; } @@ -252,8 +291,9 @@ gpio_result_t gpio_toggle (gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - gpio_peri->GPIO_OUT0 = bitfield_write(gpio_peri->GPIO_OUT0, BIT_MASK_1, - pin, !(bitfield_read(gpio_peri->GPIO_OUT0, BIT_MASK_1, pin))); + 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; } @@ -261,7 +301,8 @@ gpio_result_t gpio_write (gpio_pin_number_t pin, bool val) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - gpio_peri->GPIO_OUT0 = bitfield_write(gpio_peri->GPIO_OUT0, + select_gpio_domain(pin); + gpio_perif->GPIO_OUT0 = bitfield_write(gpio_perif->GPIO_OUT0, BIT_MASK_1, pin, val); return GpioOk; @@ -271,8 +312,9 @@ gpio_result_t gpio_intr_en_rise (gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - gpio_peri->INTRPT_RISE_EN0 = bitfield_write( - gpio_peri->INTRPT_RISE_EN0, BIT_MASK_1, pin, GPIO_INTR_ENABLE); + 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; } @@ -280,7 +322,8 @@ gpio_result_t gpio_intr_en_fall (gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - gpio_peri->INTRPT_FALL_EN0 = bitfield_write(gpio_peri->INTRPT_FALL_EN0, + 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; } @@ -289,8 +332,9 @@ gpio_result_t gpio_intr_en_lvl_high (gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - gpio_peri->INTRPT_LVL_HIGH_EN0 = bitfield_write( - gpio_peri->INTRPT_LVL_HIGH_EN0, BIT_MASK_1, pin, GPIO_INTR_ENABLE); + 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; } @@ -298,8 +342,9 @@ gpio_result_t gpio_intr_en_lvl_low (gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - gpio_peri->INTRPT_LVL_LOW_EN0 = bitfield_write( - gpio_peri->INTRPT_LVL_LOW_EN0, BIT_MASK_1, pin, GPIO_INTR_ENABLE); + 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; } @@ -307,8 +352,9 @@ gpio_result_t gpio_intr_dis_rise (gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - gpio_peri->INTRPT_RISE_EN0 = bitfield_write( - gpio_peri->INTRPT_RISE_EN0, BIT_MASK_1, pin, GPIO_INTR_DISABLE); + 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; } @@ -316,8 +362,9 @@ gpio_result_t gpio_intr_dis_fall (gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - gpio_peri->INTRPT_FALL_EN0 = bitfield_write( - gpio_peri->INTRPT_FALL_EN0, BIT_MASK_1, pin, GPIO_INTR_DISABLE); + 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; } @@ -325,8 +372,9 @@ gpio_result_t gpio_intr_dis_lvl_high (gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - gpio_peri->INTRPT_LVL_HIGH_EN0 = bitfield_write( - gpio_peri->INTRPT_LVL_HIGH_EN0, BIT_MASK_1, pin, GPIO_INTR_DISABLE); + 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; } @@ -334,22 +382,24 @@ gpio_result_t gpio_intr_dis_lvl_low (gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - gpio_peri->INTRPT_LVL_LOW_EN0 = bitfield_write( - gpio_peri->INTRPT_LVL_LOW_EN0, BIT_MASK_1, pin, GPIO_INTR_DISABLE); + 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){ if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - gpio_peri->INTRPT_RISE_EN0 = bitfield_write( - gpio_peri->INTRPT_RISE_EN0, BIT_MASK_1, pin, GPIO_INTR_DISABLE); - gpio_peri->INTRPT_FALL_EN0 = bitfield_write( - gpio_peri->INTRPT_FALL_EN0, BIT_MASK_1, pin, GPIO_INTR_DISABLE); - gpio_peri->INTRPT_LVL_HIGH_EN0 = bitfield_write( - gpio_peri->INTRPT_LVL_HIGH_EN0, BIT_MASK_1, pin, GPIO_INTR_DISABLE); - gpio_peri->INTRPT_LVL_LOW_EN0 = bitfield_write( - gpio_peri->INTRPT_LVL_LOW_EN0, BIT_MASK_1, pin, GPIO_INTR_DISABLE); + 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( + gpio_perif->INTRPT_FALL_EN0, BIT_MASK_1, pin, GPIO_INTR_DISABLE); + gpio_perif->INTRPT_LVL_HIGH_EN0 = bitfield_write( + gpio_perif->INTRPT_LVL_HIGH_EN0, BIT_MASK_1, pin, GPIO_INTR_DISABLE); + gpio_perif->INTRPT_LVL_LOW_EN0 = bitfield_write( + gpio_perif->INTRPT_LVL_LOW_EN0, BIT_MASK_1, pin, GPIO_INTR_DISABLE); return GpioOk; } @@ -397,7 +447,8 @@ gpio_result_t gpio_intr_check_stat_rise (gpio_pin_number_t pin, bool *is_pending *is_pending = GPIO_INTR_IS_NOT_TRIGGERED; return GpioPinNotAcceptable; } - *is_pending = bitfield_read(gpio_peri->INTRPT_RISE_STATUS0, BIT_MASK_1, pin); + select_gpio_domain(pin); + *is_pending = bitfield_read(gpio_perif->INTRPT_RISE_STATUS0, BIT_MASK_1, pin); return GpioOk; } @@ -408,7 +459,8 @@ gpio_result_t gpio_intr_check_stat_fall (gpio_pin_number_t pin, bool *is_pending *is_pending = GPIO_INTR_IS_NOT_TRIGGERED; return GpioPinNotAcceptable; } - *is_pending = bitfield_read(gpio_peri->INTRPT_FALL_STATUS0, BIT_MASK_1, pin); + select_gpio_domain(pin); + *is_pending = bitfield_read(gpio_perif->INTRPT_FALL_STATUS0, BIT_MASK_1, pin); return GpioOk; } @@ -419,7 +471,8 @@ gpio_result_t gpio_intr_check_stat_lvl_low (gpio_pin_number_t pin, bool *is_pend *is_pending = GPIO_INTR_IS_NOT_TRIGGERED; return GpioPinNotAcceptable; } - *is_pending = bitfield_read(gpio_peri->INTRPT_LVL_LOW_STATUS0, BIT_MASK_1, pin); + select_gpio_domain(pin); + *is_pending = bitfield_read(gpio_perif->INTRPT_LVL_LOW_STATUS0, BIT_MASK_1, pin); return GpioOk; } @@ -430,7 +483,8 @@ gpio_result_t gpio_intr_check_stat_lvl_high (gpio_pin_number_t pin, bool *is_pen *is_pending = GPIO_INTR_IS_NOT_TRIGGERED; return GpioPinNotAcceptable; } - *is_pending = bitfield_read(gpio_peri->INTRPT_LVL_HIGH_STATUS0, BIT_MASK_1, pin); + select_gpio_domain(pin); + *is_pending = bitfield_read(gpio_perif->INTRPT_LVL_HIGH_STATUS0, BIT_MASK_1, pin); return GpioOk; } @@ -441,7 +495,7 @@ gpio_result_t gpio_intr_check_stat (gpio_pin_number_t pin, bool *is_pending) *is_pending = GPIO_INTR_IS_NOT_TRIGGERED; return GpioPinNotAcceptable; } - *is_pending = bitfield_read(gpio_peri->INTRPT_STATUS0, BIT_MASK_1, pin); + *is_pending = bitfield_read(gpio_perif->INTRPT_STATUS0, BIT_MASK_1, pin); return GpioOk; } @@ -449,8 +503,9 @@ gpio_result_t gpio_intr_clear_stat_rise (gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - gpio_peri->INTRPT_RISE_STATUS0 = bitfield_write( - gpio_peri->INTRPT_RISE_STATUS0, BIT_MASK_1, pin, GPIO_INTR_CLEAR); + 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; } @@ -459,8 +514,9 @@ gpio_result_t gpio_intr_clear_stat_fall (gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - gpio_peri->INTRPT_FALL_STATUS0 = bitfield_write( - gpio_peri->INTRPT_FALL_STATUS0, BIT_MASK_1, pin, GPIO_INTR_CLEAR); + 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; } @@ -468,8 +524,9 @@ gpio_result_t gpio_intr_clear_stat_lvl_low (gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - gpio_peri->INTRPT_LVL_LOW_STATUS0 = bitfield_write( - gpio_peri->INTRPT_LVL_LOW_STATUS0, BIT_MASK_1, pin, GPIO_INTR_CLEAR); + 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; } @@ -477,8 +534,9 @@ gpio_result_t gpio_intr_clear_stat_lvl_high (gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - gpio_peri->INTRPT_LVL_HIGH_STATUS0 = bitfield_write( - gpio_peri->INTRPT_LVL_HIGH_STATUS0, BIT_MASK_1, pin, GPIO_INTR_CLEAR); + 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; } @@ -486,15 +544,17 @@ gpio_result_t gpio_intr_clear_stat (gpio_pin_number_t pin) { if (pin > (MAX_PIN-1) || pin < 0) return GpioPinNotAcceptable; - gpio_peri->INTRPT_STATUS0 = bitfield_write( - gpio_peri->INTRPT_STATUS0, BIT_MASK_1, pin, GPIO_INTR_CLEAR); + 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_intr_general_mode_t mode) +void gpio_intr_set_mode (gpio_pin_number_t pin, gpio_intr_general_mode_t mode) { - gpio_peri->CFG = bitfield_write( - gpio_peri->CFG, BIT_MASK_1, GPIO_CFG_INTR_MODE_INDEX, 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 b3cba09cd..069d3a781 100644 --- a/sw/device/lib/drivers/gpio/gpio.h +++ b/sw/device/lib/drivers/gpio/gpio.h @@ -347,7 +347,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_intr_general_mode_t mode); +void gpio_intr_set_mode (gpio_pin_number_t pin, gpio_intr_general_mode_t mode); #endif // _GPIO_H_ /****************************************************************************/ diff --git a/sw/device/lib/drivers/iffifo/iffifo.h b/sw/device/lib/drivers/iffifo/iffifo.h new file mode 100644 index 000000000..03ec588aa --- /dev/null +++ b/sw/device/lib/drivers/iffifo/iffifo.h @@ -0,0 +1,56 @@ +/* + ******************* +******************************* C SOURCE FILE ******************************* +** ******************* ** +** ** +** project : x-heep ** +** filename : i2s.h ** +** date : 28/10/2023 ** +** ** +***************************************************************************** +** ** +** Copyright (c) EPFL contributors. ** +** All rights reserved. ** +** ** +***************************************************************************** + +*/ + +/***************************************************************************/ +/***************************************************************************/ + +/** +* @file iffifo.h +* @date 28/10/2023 +* @author Pierre Guillod +* @brief HAL of the IFFIFO peripheral +* +*/ + +#ifndef _DRIVERS_IFFIFO_H_ +#define _DRIVERS_IFFIFO_H_ + +/****************************************************************************/ +/** **/ +/* MODULES USED */ +/** **/ +/****************************************************************************/ + + +#ifdef __cplusplus +extern "C" { +#endif + +__attribute__((weak)) void handler_irq_iffifo(uint32_t id); + +#ifdef __cplusplus +} +#endif + +#endif // _DRIVERS_IFFIFO_H_ + +/****************************************************************************/ +/** **/ +/* EOF */ +/** **/ +/****************************************************************************/ diff --git a/sw/device/lib/drivers/iffifo/iffifo_regs.h b/sw/device/lib/drivers/iffifo/iffifo_regs.h new file mode 100644 index 000000000..6acd3aa8e --- /dev/null +++ b/sw/device/lib/drivers/iffifo/iffifo_regs.h @@ -0,0 +1,47 @@ +// Generated register defines for iffifo + +// Copyright information found in source file: +// Copyright EPFL contributors. + +// Licensing information found in source file: +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef _IFFIFO_REG_DEFS_ +#define _IFFIFO_REG_DEFS_ + +#ifdef __cplusplus +extern "C" { +#endif +// Register width +#define IFFIFO_PARAM_REG_WIDTH 32 + +// Data coming from the FIFO (Fifo Output/Software RX) +#define IFFIFO_FIFO_OUT_REG_OFFSET 0x0 + +// Data sent to the FIFO (Fifo Input/Software TX) +#define IFFIFO_FIFO_IN_REG_OFFSET 0x4 + +// General purpose status register +#define IFFIFO_STATUS_REG_OFFSET 0x8 +#define IFFIFO_STATUS_EMPTY_BIT 0 +#define IFFIFO_STATUS_AVAILABLE_BIT 1 +#define IFFIFO_STATUS_REACHED_BIT 2 +#define IFFIFO_STATUS_FULL_BIT 3 + +// Current number of occupied FIFO slots +#define IFFIFO_OCCUPANCY_REG_OFFSET 0xc + +// FIFO occupancy at which the STATUS:REACHED bit is asserted +#define IFFIFO_WATERMARK_REG_OFFSET 0x10 + +// Write any value to assert an interrupt. Write 0 or 1 to disable or enable +// an interrupt. +#define IFFIFO_INTERRUPTS_REG_OFFSET 0x14 +#define IFFIFO_INTERRUPTS_REACHED_BIT 0 + +#ifdef __cplusplus +} // extern "C" +#endif +#endif // _IFFIFO_REG_DEFS_ +// End generated register defines for iffifo \ No newline at end of file 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 0dc114f5f..1491a6edf 100644 --- a/sw/device/lib/runtime/core_v_mini_mcu.h.tpl +++ b/sw/device/lib/runtime/core_v_mini_mcu.h.tpl @@ -65,6 +65,8 @@ extern "C" { % endfor % endif +#define GPIO_AO_DOMAIN_LIMIT 8 + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/sw/device/target/pynq-z2/x-heep.h b/sw/device/target/pynq-z2/x-heep.h index 844aed03c..43cef0d47 100644 --- a/sw/device/target/pynq-z2/x-heep.h +++ b/sw/device/target/pynq-z2/x-heep.h @@ -12,8 +12,8 @@ extern "C" { #endif // __cplusplus -#define REFERENCE_CLOCK_Hz 20*1000*1000 -#define UART_BAUDRATE 115200 +#define REFERENCE_CLOCK_Hz 15*1000*1000 +#define UART_BAUDRATE 9600 #define TARGET_PYNQ_Z2 1 /** diff --git a/sw/linker/link.ld.tpl b/sw/linker/link.ld.tpl index f05c107b6..6bc0e2731 100644 --- a/sw/linker/link.ld.tpl +++ b/sw/linker/link.ld.tpl @@ -38,9 +38,9 @@ SECTIONS PROVIDE(__boot_address = 0x180); /* stack and heap related settings */ - __stack_size = DEFINED(__stack_size) ? __stack_size : 0x800; + __stack_size = DEFINED(__stack_size) ? __stack_size : 0x${stack_size}; PROVIDE(__stack_size = __stack_size); - __heap_size = DEFINED(__heap_size) ? __heap_size : 0x800; + __heap_size = DEFINED(__heap_size) ? __heap_size : 0x${heap_size}; /* Read-only sections, merged into text segment: */ PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x10000)); . = SEGMENT_START("text-segment", 0x10000) + SIZEOF_HEADERS; diff --git a/sw/linker/link_flash_exec.ld.tpl b/sw/linker/link_flash_exec.ld.tpl index f8e0f83f0..2c052f571 100644 --- a/sw/linker/link_flash_exec.ld.tpl +++ b/sw/linker/link_flash_exec.ld.tpl @@ -17,9 +17,9 @@ SECTIONS { PROVIDE(__boot_address = 0x40000180); /* stack and heap related settings */ - __stack_size = DEFINED(__stack_size) ? __stack_size : 0x1000; + __stack_size = DEFINED(__stack_size) ? __stack_size : 0x${stack_size}; PROVIDE(__stack_size = __stack_size); - __heap_size = DEFINED(__heap_size) ? __heap_size : 0x1000; + __heap_size = DEFINED(__heap_size) ? __heap_size : 0x${heap_size}; /* interrupt vectors */ .vectors (ORIGIN(FLASH)): diff --git a/sw/linker/link_flash_load.ld.tpl b/sw/linker/link_flash_load.ld.tpl index a33ca3dd0..bc6d9884a 100644 --- a/sw/linker/link_flash_load.ld.tpl +++ b/sw/linker/link_flash_load.ld.tpl @@ -17,9 +17,9 @@ SECTIONS { PROVIDE(__boot_address = 0x180); /* stack and heap related settings */ - __stack_size = DEFINED(__stack_size) ? __stack_size : 0x1000; + __stack_size = DEFINED(__stack_size) ? __stack_size : 0x${stack_size}; PROVIDE(__stack_size = __stack_size); - __heap_size = DEFINED(__heap_size) ? __heap_size : 0x1000; + __heap_size = DEFINED(__heap_size) ? __heap_size : 0x${heap_size}; /* interrupt vectors */ .vectors (ORIGIN(RAM)): diff --git a/tb/testharness.sv b/tb/testharness.sv index fc216e7bc..74f666430 100644 --- a/tb/testharness.sv +++ b/tb/testharness.sv @@ -74,6 +74,9 @@ module testharness #( logic [EXT_PERIPHERALS_PORT_SEL_WIDTH-1:0] ext_periph_select; + logic iffifo_in_ready, iffifo_out_valid; + logic iffifo_int_o; + // External xbar master/slave and peripheral ports obi_req_t [EXT_XBAR_NMASTER_RND-1:0] ext_master_req; obi_req_t [EXT_XBAR_NMASTER_RND-1:0] heep_slave_req; @@ -132,6 +135,7 @@ module testharness #( end // Re-assign the interrupt lines used here intr_vector_ext[0] = memcopy_intr; + intr_vector_ext[1] = iffifo_int_o; end //log parameters @@ -249,7 +253,9 @@ module testharness #( .external_subsystem_powergate_iso_no(external_subsystem_powergate_iso_n), .external_subsystem_rst_no(external_subsystem_rst_n), .external_ram_banks_set_retentive_no(external_ram_banks_set_retentive_n), - .external_subsystem_clkgate_en_no(external_subsystem_clkgate_en_n) + .external_subsystem_clkgate_en_no(external_subsystem_clkgate_en_n), + .ext_dma_slot_tx_i(iffifo_in_ready), + .ext_dma_slot_rx_i(iffifo_out_valid) ); // Testbench external bus @@ -441,6 +447,22 @@ module testharness #( .reg_rsp_o(ext_periph_slv_rsp[testharness_pkg::AMS_IDX]) ); + // InterFaced FIFO (IFFIFO) external peripheral + iffifo #( + .reg_req_t(reg_pkg::reg_req_t), + .reg_rsp_t(reg_pkg::reg_rsp_t) + ) iffifo_i ( + .clk_i, + .rst_ni, + .reg_req_i(ext_periph_slv_req[testharness_pkg::IFFIFO_IDX]), + .reg_rsp_o(ext_periph_slv_rsp[testharness_pkg::IFFIFO_IDX]), + // DMA slots + .iffifo_in_ready_o(iffifo_in_ready), + .iffifo_out_valid_o(iffifo_out_valid), + // Interrupt lines + .iffifo_int_o(iffifo_int_o) + ); + addr_decode #( .NoIndices(testharness_pkg::EXT_NPERIPHERALS), .NoRules(testharness_pkg::EXT_NPERIPHERALS), @@ -557,6 +579,7 @@ module testharness #( assign ext_master_req[testharness_pkg::EXT_MASTER0_IDX].wdata = '0; assign memcopy_intr = '0; + assign iffifo_int_o = '0; assign periph_slave_rsp = '0; end diff --git a/tb/testharness_pkg.sv b/tb/testharness_pkg.sv index 58e202ceb..a383293d1 100644 --- a/tb/testharness_pkg.sv +++ b/tb/testharness_pkg.sv @@ -29,7 +29,7 @@ package testharness_pkg; }; //slave encoder - localparam EXT_NPERIPHERALS = 2; + localparam EXT_NPERIPHERALS = 3; // Memcopy controller (external peripheral example) localparam logic [31:0] MEMCOPY_CTRL_START_ADDRESS = core_v_mini_mcu_pkg::EXT_PERIPHERAL_START_ADDRESS + 32'h0; @@ -43,6 +43,12 @@ package testharness_pkg; localparam logic [31:0] AMS_END_ADDRESS = AMS_START_ADDRESS + AMS_SIZE; localparam logic [31:0] AMS_IDX = 32'd1; + // External InterFaced FIFO (IFFIFO) Peripheral + localparam logic [31:0] IFFIFO_START_ADDRESS = core_v_mini_mcu_pkg::EXT_PERIPHERAL_START_ADDRESS + 32'h002000; + localparam logic [31:0] IFFIFO_SIZE = 32'h100; + localparam logic [31:0] IFFIFO_END_ADDRESS = IFFIFO_START_ADDRESS + IFFIFO_SIZE; + localparam logic [31:0] IFFIFO_IDX = 32'd2; + localparam addr_map_rule_t [EXT_NPERIPHERALS-1:0] EXT_PERIPHERALS_ADDR_RULES = '{ '{ @@ -50,7 +56,8 @@ package testharness_pkg; start_addr: MEMCOPY_CTRL_START_ADDRESS, end_addr: MEMCOPY_CTRL_END_ADDRESS }, - '{idx: AMS_IDX, start_addr: AMS_START_ADDRESS, end_addr: AMS_END_ADDRESS} + '{idx: AMS_IDX, start_addr: AMS_START_ADDRESS, end_addr: AMS_END_ADDRESS}, + '{idx: IFFIFO_IDX, start_addr: IFFIFO_START_ADDRESS, end_addr: IFFIFO_END_ADDRESS} }; localparam int unsigned EXT_PERIPHERALS_PORT_SEL_WIDTH = EXT_NPERIPHERALS > 1 ? $clog2( diff --git a/util/mcu_gen.py b/util/mcu_gen.py index e8c012f8b..4e5472af5 100755 --- a/util/mcu_gen.py +++ b/util/mcu_gen.py @@ -540,8 +540,15 @@ def len_extracted_peripherals(peripherals): linker_onchip_il_start_address = str('{:08X}'.format(int(linker_onchip_data_start_address,16) + int(linker_onchip_data_size_address,16))) linker_onchip_il_size_address = str('{:08X}'.format(ram_numbanks_il*32*1024)) + stack_size = string2int(obj['linker_script']['stack_size']) + heap_size = string2int(obj['linker_script']['heap_size']) + if ((int(linker_onchip_data_size_address,16) + int(linker_onchip_code_size_address,16)) > int(ram_size_address,16)): exit("The code and data section must fit in the RAM size, instead they takes " + str(linker_onchip_data_size_address + linker_onchip_code_size_address)) + + if ((int(stack_size,16) + int(heap_size,16)) > int(ram_size_address,16)): + 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'] @@ -847,6 +854,8 @@ def len_extracted_peripherals(peripherals): "linker_onchip_data_size_address" : linker_onchip_data_size_address, "linker_onchip_il_start_address" : linker_onchip_il_start_address, "linker_onchip_il_size_address" : linker_onchip_il_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, diff --git a/x-heep-tb-utils.core b/x-heep-tb-utils.core index 05b75ba51..4206721ba 100644 --- a/x-heep-tb-utils.core +++ b/x-heep-tb-utils.core @@ -14,6 +14,7 @@ filesets: - example:ip:gpio_cnt - example:ip:pdm2pcm_dummy - example:ip:ams + - example:ip:iffifo - example:ip:i2s_microphone files: file_type: systemVerilogSource @@ -22,6 +23,7 @@ filesets: files: - hw/ip_examples/slow_memory/slow_memory.vlt - hw/ip_examples/ams/ams.vlt + - hw/ip_examples/iffifo/iffifo.vlt - tb/tb.vlt file_type: vlt