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

Add DMA fence operation #807

Merged
merged 4 commits into from
Feb 15, 2024
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
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
Loading