Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merge origin into dma-broadcast via main #2

Merged
merged 10 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -49,14 +50,17 @@ 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

# Timeout for simulation, default 120
TIMEOUT ?= 120

# Export variables to sub-makefiles
export

## @section Conda
conda: environment.yml
conda env create -f environment.yml
Expand Down Expand Up @@ -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; \
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)




52 changes: 52 additions & 0 deletions docs/source/How_to/ExternalDevices.md
Original file line number Diff line number Diff line change
Expand Up @@ -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);

. . .
}
```
4 changes: 2 additions & 2 deletions hw/fpga/xilinx_core_v_mini_mcu_wrapper.sv
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,8 @@ module xilinx_core_v_mini_mcu_wrapper
.i2s_sck_io(i2s_sck_io),
.i2s_ws_io(i2s_ws_io),
.i2s_sd_io(i2s_sd_io),
.ext_dma_slot_tx_i,
.ext_dma_slot_rx_i,
.ext_dma_slot_tx_i('0),
.ext_dma_slot_rx_i('0)
);

assign exit_value_o = exit_value[0];
Expand Down
7 changes: 5 additions & 2 deletions sw/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -70,6 +70,9 @@ else
CMAKE=cmake3
endif

# Export variables to sub-makefiles
export

# Let's CMake!
include cmake/targets.mak

Expand Down
47 changes: 37 additions & 10 deletions sw/applications/example_iffifo/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,17 @@
#include "fast_intr_ctrl.h"


#define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
/* 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;

Expand All @@ -38,16 +48,20 @@ void dma_intr_handler_trans_done()
{
dma_intr_flag = 1;
}

void protected_wait_for_dma_interrupt(void)
{
enable_all_fast_interrupts(false);
while (dma_intr_flag == 0) { wait_for_interrupt(); }
dma_intr_flag = 0;
enable_all_fast_interrupts(true);
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;
void handler_irq_iffifo(uint32_t id)
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);
Expand Down Expand Up @@ -76,13 +90,20 @@ 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 ? "E" : "-"); // FIFO empty
PRINTF(status & 2 ? "A" : "-"); // Data available in FIFO
PRINTF(status & 4 ? "R" : "-"); // Watermark reached
PRINTF(status & 8 ? "F" : "-"); // FIFO full
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);
Expand All @@ -98,6 +119,8 @@ int main(int argc, char *argv[]) {
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);

Expand Down Expand Up @@ -131,9 +154,13 @@ int main(int argc, char *argv[]) {
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();
Expand Down
6 changes: 3 additions & 3 deletions sw/device/lib/drivers/dma/dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +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_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;
Expand Down Expand Up @@ -465,4 +465,4 @@ uint8_t dma_window_ratio_warning_threshold(void);
/** **/
/** EOF **/
/** **/
/****************************************************************************/
/****************************************************************************/
5 changes: 0 additions & 5 deletions sw/device/lib/drivers/rv_plic/rv_plic.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@
#include "i2s.h"
#include "dma.h"
#include "spi_host.h"
#include "iffifo.h"

/****************************************************************************/
/** **/
Expand Down Expand Up @@ -408,10 +407,6 @@ void plic_reset_handlers_list(void)
{
handlers[i] = &handler_irq_dma;
}
else if ( i == EXT_INTR_1)
{
handlers[i] = &handler_irq_iffifo;
}
else
{
handlers[i] = &handler_irq_dummy;
Expand Down
Loading