Skip to content

Commit

Permalink
Add DMA fence operation (#807)
Browse files Browse the repository at this point in the history
  • Loading branch information
stnolting committed Feb 15, 2024
2 parents b7b845e + 8a667e7 commit 676f0fb
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 16 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12

| Date | Version | Comment | Link |
|:----:|:-------:|:--------|:----:|
| 15.01.2023 | 1.9.4.13 | allow the DMA to issue a FENCE operation | [#807](https://github.com/stnolting/neorv32/pull/807) |
| 14.02.2024 | 1.9.4.12 | :bug: close another illegal compressed instruction encoding loophole | [#806](https://github.com/stnolting/neorv32/pull/806) |
| 11.02.2024 | 1.9.4.11 | :bug: fix several FPU bugs and design flaws | [#794](https://github.com/stnolting/neorv32/pull/794) |
| 11.02.2024 | 1.9.4.10 | minor additions to previous version (1.9.4.9): fix HPM configuration read-back | [#804](https://github.com/stnolting/neorv32/pull/804) |
Expand Down
26 changes: 17 additions & 9 deletions docs/datasheet/soc_dma.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,13 @@ sources are logically OR-ed).
The DMA transfer will start if a **rising edge** is detected on _any_ of the enabled FIRQ source channels.


**Memory Barrier / Fence Operation**

Optionally, the DMA can issue a FENCE request to the downstream memory system when a transfer has been completed
without errors. This can be used to re-sync caches (flush and reload) and buffers to maintain data coherency.
This automatic fencing is enabled by the setting the control register's `DMA_CTRL_FENCE` bit.


**DMA Interrupt**

The DMA features a single CPU interrupt that is triggered when the programmed transfer has completed. This
Expand All @@ -127,15 +134,16 @@ explicitly cleared again by writing zero to the according <<_mip>> CSR bit.
[options="header",grid="all"]
|=======================
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
.9+<| `0xffffed00` .9+<| `CTRL` <|`0` `DMA_CTRL_EN` ^| r/w <| DMA module enable
<|`1` `DMA_CTRL_AUTO` ^| r/w <| Enable automatic mode (FIRQ-triggered)
<|`7:2` _reserved_ ^| r/- <| reserved, read as zero
<|`8` `DMA_CTRL_ERROR_RD` ^| r/- <| Error during read access, clears when starting a new transfer
<|`9` `DMA_CTRL_ERROR_WR` ^| r/- <| Error during write access, clears when starting a new transfer
<|`10` `DMA_CTRL_BUSY` ^| r/- <| DMA transfer in progress
<|`11` `DMA_CTRL_DONE` ^| r/c <| Set if a transfer was executed; auto-clears on write-access
<|`15:12` _reserved_ ^| r/- <| reserved, read as zero
<|`31:16` `DMA_CTRL_FIRQ_MASK_MSB : DMA_CTRL_FIRQ_MASK_LSB` ^| r/w <| FIRQ trigger mask (same bits as in <<_mip>>)
.10+<| `0xffffed00` .10+<| `CTRL` <|`0` `DMA_CTRL_EN` ^| r/w <| DMA module enable
<|`1` `DMA_CTRL_AUTO` ^| r/w <| Enable automatic mode (FIRQ-triggered)
<|`2` `DMA_CTRL_FENCE` ^| r/w <| Issue a downstream FENCE operation when DMA transfer completes (without errors)
<|`7:3` _reserved_ ^| r/- <| reserved, read as zero
<|`8` `DMA_CTRL_ERROR_RD` ^| r/- <| Error during read access, clears when starting a new transfer
<|`9` `DMA_CTRL_ERROR_WR` ^| r/- <| Error during write access, clears when starting a new transfer
<|`10` `DMA_CTRL_BUSY` ^| r/- <| DMA transfer in progress
<|`11` `DMA_CTRL_DONE` ^| r/c <| Set if a transfer was executed; auto-clears on write-access
<|`15:12` _reserved_ ^| r/- <| reserved, read as zero
<|`31:16` `DMA_CTRL_FIRQ_MASK_MSB : DMA_CTRL_FIRQ_MASK_LSB` ^| r/w <| FIRQ trigger mask (same bits as in <<_mip>>)
| `0xffffed04` | `SRC_BASE` |`31:0` | r/w | Source base address (shows the last-accessed source address when read)
| `0xffffed08` | `DST_BASE` |`31:0` | r/w | Destination base address (shows the last-accessed destination address when read)
.6+<| `0xffffed0c` .6+<| `TTYPE` <|`23:0` `DMA_TTYPE_NUM_MSB : DMA_TTYPE_NUM_LSB` ^| r/w <| Number of elements to transfer (shows the last-transferred element index when read)
Expand Down
7 changes: 6 additions & 1 deletion rtl/core/neorv32_dma.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ architecture neorv32_dma_rtl of neorv32_dma is
-- control and status register bits --
constant ctrl_en_c : natural := 0; -- r/w: DMA enable
constant ctrl_auto_c : natural := 1; -- r/w: enable FIRQ-triggered transfer
constant ctrl_fence_c : natural := 3; -- r/w: issue FENCE operation when DMA is done
--
constant ctrl_error_rd_c : natural := 8; -- r/-: error during read transfer
constant ctrl_error_wr_c : natural := 9; -- r/-: error during write transfer
Expand All @@ -88,6 +89,7 @@ architecture neorv32_dma_rtl of neorv32_dma is
type config_t is record
enable : std_ulogic; -- DMA enabled when set
auto : std_ulogic; -- FIRQ-driven auto transfer
fence : std_ulogic; -- issue FENCE operation when DMA is done
firq_mask : std_ulogic_vector(15 downto 0); -- FIRQ trigger mask
src_base : std_ulogic_vector(31 downto 0); -- source base address
dst_base : std_ulogic_vector(31 downto 0); -- destination base address
Expand Down Expand Up @@ -139,6 +141,7 @@ begin
bus_rsp_o.data <= (others => '0');
config.enable <= '0';
config.auto <= '0';
config.fence <= '0';
config.firq_mask <= (others => '0');
config.src_base <= (others => '0');
config.dst_base <= (others => '0');
Expand Down Expand Up @@ -166,6 +169,7 @@ begin
if (bus_req_i.addr(3 downto 2) = "00") then -- control and status register
config.enable <= bus_req_i.data(ctrl_en_c);
config.auto <= bus_req_i.data(ctrl_auto_c);
config.fence <= bus_req_i.data(ctrl_fence_c);
config.done <= '0'; -- clear on write access
config.firq_mask <= bus_req_i.data(ctrl_firq_mask_msb_c downto ctrl_firq_mask_lsb_c);
end if;
Expand All @@ -190,6 +194,7 @@ begin
when "00" => -- control and status register
bus_rsp_o.data(ctrl_en_c) <= config.enable;
bus_rsp_o.data(ctrl_auto_c) <= config.auto;
bus_rsp_o.data(ctrl_fence_c) <= config.fence;
bus_rsp_o.data(ctrl_error_rd_c) <= engine.err_rd;
bus_rsp_o.data(ctrl_error_wr_c) <= engine.err_wr;
bus_rsp_o.data(ctrl_busy_c) <= engine.busy;
Expand Down Expand Up @@ -328,7 +333,7 @@ begin
dma_req_o.src <= '0'; -- source = data access
dma_req_o.addr <= engine.src_addr when (engine.state = S_READ) else engine.dst_addr;
dma_req_o.rvso <= '0'; -- no reservation set operation possible
dma_req_o.fence <= '0'; -- DMA cannot trigger a fence
dma_req_o.fence <= config.enable and config.fence and engine.done; -- issue FENCE operation when transfer is done

-- address increment --
address_inc: process(config.qsel)
Expand Down
2 changes: 1 addition & 1 deletion rtl/core/neorv32_package.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ package neorv32_package is

-- Architecture Constants -----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01090412"; -- hardware version
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01090413"; -- hardware version
constant archid_c : natural := 19; -- official RISC-V architecture ID
constant XLEN : natural := 32; -- native data path width

Expand Down
8 changes: 6 additions & 2 deletions sw/example/demo_dma/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ int main() {
// enable DMA
neorv32_dma_enable();

// issue a FENCE operation when the DMA transfer completes (without errors); this
// will re-sync /flush and reload) all downstream caches
neorv32_dma_fence_enable();

// initialize and data arrays
dma_src[0] = 0x66778899UL;
dma_src[1] = 0x22334455UL;
Expand All @@ -107,7 +111,7 @@ int main() {
dma_dst[2] = 0;
dma_dst[3] = 0;

asm volatile ("fence"); // make sure main memory is sync with d-cache
asm volatile ("fence"); // re-sync caches


// ----------------------------------------------------------
Expand Down Expand Up @@ -264,7 +268,7 @@ int main() {
**************************************************************************/
void show_arrays(void) {

asm volatile ("fence"); // make sure main memory is sync with d-cache
asm volatile ("fence"); // re-sync caches
neorv32_uart0_printf("---------------------------\n");
neorv32_uart0_printf(" SRC DST\n");
neorv32_uart0_printf("[0] 0x%x 0x%x\n", dma_src[0], dma_dst[0]);
Expand Down
3 changes: 2 additions & 1 deletion sw/example/processor_check/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1470,8 +1470,9 @@ int main() {
if (NEORV32_SYSINFO->SOC & (1 << SYSINFO_SOC_IO_DMA)) {
cnt_test++;

// enable DMA and according FIRQ channel
// enable DMA, auto-fencing and according FIRQ channel
neorv32_dma_enable();
neorv32_dma_fence_enable();
neorv32_cpu_irq_enable(DMA_FIRQ_ENABLE);

// setup source data
Expand Down
5 changes: 4 additions & 1 deletion sw/lib/include/neorv32_dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// # ********************************************************************************************* #
// # BSD 3-Clause License #
// # #
// # Copyright (c) 2023, Stephan Nolting. All rights reserved. #
// # Copyright (c) 2024, Stephan Nolting. All rights reserved. #
// # #
// # Redistribution and use in source and binary forms, with or without modification, are #
// # permitted provided that the following conditions are met: #
Expand Down Expand Up @@ -62,6 +62,7 @@ typedef volatile struct __attribute__((packed,aligned(4))) {
enum NEORV32_DMA_CTRL_enum {
DMA_CTRL_EN = 0, /**< DMA control register(0) (r/w): DMA enable */
DMA_CTRL_AUTO = 1, /**< DMA control register(1) (r/w): Automatic trigger mode enable */
DMA_CTRL_FENCE = 2, /**< DMA control register(2) (r/w): Issue FENCE downstream operation when DMA transfer is completed */

DMA_CTRL_ERROR_RD = 8, /**< DMA control register(8) (r/-): Error during read access; SRC_BASE shows the faulting address */
DMA_CTRL_ERROR_WR = 9, /**< DMA control register(9) (r/-): Error during write access; DST_BASE shows the faulting address */
Expand Down Expand Up @@ -123,6 +124,8 @@ enum NEORV32_DMA_STATUS_enum {
int neorv32_dma_available(void);
void neorv32_dma_enable(void);
void neorv32_dma_disable(void);
void neorv32_dma_fence_enable(void);
void neorv32_dma_fence_disable(void);
void neorv32_dma_transfer(uint32_t base_src, uint32_t base_dst, uint32_t num, uint32_t config);
void neorv32_dma_transfer_auto(uint32_t base_src, uint32_t base_dst, uint32_t num, uint32_t config, uint32_t firq_mask);
int neorv32_dma_status(void);
Expand Down
21 changes: 20 additions & 1 deletion sw/lib/source/neorv32_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// # ********************************************************************************************* #
// # BSD 3-Clause License #
// # #
// # Copyright (c) 2023, Stephan Nolting. All rights reserved. #
// # Copyright (c) 2024, Stephan Nolting. All rights reserved. #
// # #
// # Redistribution and use in source and binary forms, with or without modification, are #
// # permitted provided that the following conditions are met: #
Expand Down Expand Up @@ -78,6 +78,25 @@ void neorv32_dma_disable(void) {
}


/**********************************************************************//**
* Enable memory barrier (fence): issue a FENCE operation when DMA transfer
* completes without errors.
**************************************************************************/
void neorv32_dma_fence_enable(void) {

NEORV32_DMA->CTRL |= (uint32_t)(1 << DMA_CTRL_FENCE);
}


/**********************************************************************//**
* Disable memory barrier (fence).
**************************************************************************/
void neorv32_dma_fence_disable(void) {

NEORV32_DMA->CTRL &= ~((uint32_t)(1 << DMA_CTRL_FENCE));
}


/**********************************************************************//**
* Trigger manual DMA transfer.
*
Expand Down
5 changes: 5 additions & 0 deletions sw/svd/neorv32.svd
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,11 @@
<bitRange>[1:1]</bitRange>
<description>Enable automatic transfer trigger (FIRQ-triggered)</description>
</field>
<field>
<name>DMA_CTRL_FENCE</name>
<bitRange>[2:2]</bitRange>
<description>Issue a downstream FENCE operation when DMA transfer completes (without errors)</description>
</field>
<field>
<name>DMA_CTRL_ERROR_RD</name>
<bitRange>[8:8]</bitRange>
Expand Down

0 comments on commit 676f0fb

Please sign in to comment.