From 15a627996e678b7c93ecd983959477813edfc789 Mon Sep 17 00:00:00 2001 From: Davide Schiavone Date: Mon, 16 Oct 2023 09:26:22 +0200 Subject: [PATCH 01/11] fix GPIO HAL by adding selection of GPIO domain (#385) --- sw/device/lib/drivers/gpio/gpio.c | 190 +++++++++++++------- sw/device/lib/drivers/gpio/gpio.h | 2 +- sw/device/lib/runtime/core_v_mini_mcu.h.tpl | 2 + 3 files changed, 128 insertions(+), 66 deletions(-) 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/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 From 5cabf4a11f40b3579b57472106b3ab2923f25306 Mon Sep 17 00:00:00 2001 From: Davide Schiavone Date: Mon, 16 Oct 2023 20:24:05 +0200 Subject: [PATCH 02/11] fix cv32e4 verilator waivers (#402) * update cv32e40p verilator waiver * update cv32e40px verilator waiver --- hw/vendor/waiver/lint/cv32e40p.vlt | 3 +++ hw/vendor/waiver/lint/cv32e40px.vlt | 3 +++ 2 files changed, 6 insertions(+) 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*" From 27fb6ad7cf75f0c12bad915ec64201153a18f86b Mon Sep 17 00:00:00 2001 From: Davide Schiavone Date: Tue, 17 Oct 2023 12:04:56 +0200 Subject: [PATCH 03/11] reduce FPGA frequencz to 15MHz to accomodate FPU (#404) * reduce FPGA frequency to 15MHz to accomodate FPU * reduced baudrate uart fpga * update README --- README.md | 13 ++++++++++++- docs/source/How_to/ExecuteFromFlash.md | 2 ++ hw/fpga/scripts/xilinx_generate_clk_wizard.tcl | 4 ++-- sw/device/target/pynq-z2/x-heep.h | 4 ++-- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e63003cfc..0e0130b7c 100644 --- a/README.md +++ b/README.md @@ -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) 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/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/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 /** From df569a88fc7eaa447645262f0d3a76dd22c519f7 Mon Sep 17 00:00:00 2001 From: Davide Schiavone Date: Thu, 19 Oct 2023 10:11:49 +0200 Subject: [PATCH 04/11] enable mcycle in matadd examples (#413) --- sw/applications/example_matadd/main.c | 9 +++++---- sw/applications/example_matfadd/main.c | 5 ++++- 2 files changed, 9 insertions(+), 5 deletions(-) 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 From 86b72f533de658119edd023d245a42589748b78d Mon Sep 17 00:00:00 2001 From: Luigi Giuffrida <32927727+Luigi2898@users.noreply.github.com> Date: Wed, 25 Oct 2023 13:06:13 +0200 Subject: [PATCH 05/11] add stack and heap size as parameters to mcu-gen (#419) * add stack and heap size to linker script template * Add heap and stack parameter to mcu-gen * Set the default stack and heap size to 0x800 * Add parameter to all the linker scripts --------- Co-authored-by: luigi.giuffrida --- mcu_cfg.hjson | 2 ++ sw/linker/link.ld.tpl | 4 ++-- sw/linker/link_flash_exec.ld.tpl | 4 ++-- sw/linker/link_flash_load.ld.tpl | 4 ++-- util/mcu_gen.py | 9 +++++++++ 5 files changed, 17 insertions(+), 6 deletions(-) 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/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/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, From 176369c8d634c2263f828cb6a265aeb391434f1b Mon Sep 17 00:00:00 2001 From: jmiranda Date: Tue, 31 Oct 2023 15:41:37 +0100 Subject: [PATCH 06/11] Compilation fix (#422) * Compilation Fix: we were not exporting properly the ENV variables to sub-makefiles, i.e. to children makefiles, and so the SOURCE was not propagated properly. This led to problems when executing from scratch, i.e. not having still nothing into the CMake cache. This is now fixed. --- Makefile | 6 +++++- sw/Makefile | 7 +++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index fa6e81ef5..8d7c75b84 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 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 From 0b8d3c63328dab7f09a6ca0e7b3e23ef3426588e Mon Sep 17 00:00:00 2001 From: jmiranda Date: Tue, 31 Oct 2023 15:52:17 +0100 Subject: [PATCH 07/11] Fix run-blinky-freertos command (#424) * Fix run-blinkyfreertos command --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8d7c75b84..0220b7c30 100644 --- a/Makefile +++ b/Makefile @@ -179,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; \ From 10cc6ce3c5e5f50d6ff50e47815d27a2e85ff899 Mon Sep 17 00:00:00 2001 From: Davide Schiavone Date: Thu, 9 Nov 2023 14:16:16 +0100 Subject: [PATCH 08/11] add citation in readme --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 0e0130b7c..47066b4f6 100644 --- a/README.md +++ b/README.md @@ -558,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) + + + + From 4093c32cfb8d655e68ad33cc3529fa048e8356f8 Mon Sep 17 00:00:00 2001 From: Juan-n-only Date: Tue, 21 Nov 2023 12:45:33 +0100 Subject: [PATCH 09/11] Updated the documentation on how to add external interrupts (#427) --- docs/source/How_to/ExternalDevices.md | 52 +++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) 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 From 0caa3072bdcc483789204dca35172eda3d055839 Mon Sep 17 00:00:00 2001 From: grinningmosfet <95435436+grinningmosfet@users.noreply.github.com> Date: Wed, 22 Nov 2023 12:36:12 +0100 Subject: [PATCH 10/11] expose DMA slots externally + external FIFO example (#417) --- hw/core-v-mini-mcu/ao_peripheral_subsystem.sv | 9 +- hw/core-v-mini-mcu/core_v_mini_mcu.sv | 9 +- hw/core-v-mini-mcu/core_v_mini_mcu.sv.tpl | 9 +- hw/fpga/xilinx_core_v_mini_mcu_wrapper.sv | 4 +- hw/ip_examples/iffifo/data/iffifo.hjson | 76 +++ hw/ip_examples/iffifo/iffifo.core | 26 + hw/ip_examples/iffifo/iffifo.vlt | 15 + hw/ip_examples/iffifo/iffifo_gen.sh | 8 + hw/ip_examples/iffifo/rtl/iffifo.sv | 115 +++++ hw/ip_examples/iffifo/rtl/iffifo_reg_pkg.sv | 106 ++++ hw/ip_examples/iffifo/rtl/iffifo_reg_top.sv | 451 ++++++++++++++++++ hw/system/x_heep_system.sv.tpl | 7 +- sw/applications/example_iffifo/main.c | 206 ++++++++ sw/device/lib/drivers/dma/dma.h | 4 +- sw/device/lib/drivers/iffifo/iffifo.h | 56 +++ sw/device/lib/drivers/iffifo/iffifo_regs.h | 47 ++ tb/testharness.sv | 25 +- tb/testharness_pkg.sv | 11 +- x-heep-tb-utils.core | 2 + 19 files changed, 1174 insertions(+), 12 deletions(-) create mode 100644 hw/ip_examples/iffifo/data/iffifo.hjson create mode 100644 hw/ip_examples/iffifo/iffifo.core create mode 100644 hw/ip_examples/iffifo/iffifo.vlt create mode 100755 hw/ip_examples/iffifo/iffifo_gen.sh create mode 100644 hw/ip_examples/iffifo/rtl/iffifo.sv create mode 100644 hw/ip_examples/iffifo/rtl/iffifo_reg_pkg.sv create mode 100644 hw/ip_examples/iffifo/rtl/iffifo_reg_top.sv create mode 100644 sw/applications/example_iffifo/main.c create mode 100644 sw/device/lib/drivers/iffifo/iffifo.h create mode 100644 sw/device/lib/drivers/iffifo/iffifo_regs.h 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/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/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/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/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/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/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 From 61a071908bc978e3986a0d0ea3be66cf202a27ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Mallas=C3=A9n=20Quintana?= Date: Wed, 22 Nov 2023 20:36:53 +0100 Subject: [PATCH 11/11] Update verible url (#428) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 47066b4f6..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: