Skip to content

Commit 676f0fb

Browse files
authored
Add DMA fence operation (#807)
2 parents b7b845e + 8a667e7 commit 676f0fb

File tree

9 files changed

+62
-16
lines changed

9 files changed

+62
-16
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12
3030

3131
| Date | Version | Comment | Link |
3232
|:----:|:-------:|:--------|:----:|
33+
| 15.01.2023 | 1.9.4.13 | allow the DMA to issue a FENCE operation | [#807](https://github.com/stnolting/neorv32/pull/807) |
3334
| 14.02.2024 | 1.9.4.12 | :bug: close another illegal compressed instruction encoding loophole | [#806](https://github.com/stnolting/neorv32/pull/806) |
3435
| 11.02.2024 | 1.9.4.11 | :bug: fix several FPU bugs and design flaws | [#794](https://github.com/stnolting/neorv32/pull/794) |
3536
| 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) |

docs/datasheet/soc_dma.adoc

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,13 @@ sources are logically OR-ed).
113113
The DMA transfer will start if a **rising edge** is detected on _any_ of the enabled FIRQ source channels.
114114

115115

116+
**Memory Barrier / Fence Operation**
117+
118+
Optionally, the DMA can issue a FENCE request to the downstream memory system when a transfer has been completed
119+
without errors. This can be used to re-sync caches (flush and reload) and buffers to maintain data coherency.
120+
This automatic fencing is enabled by the setting the control register's `DMA_CTRL_FENCE` bit.
121+
122+
116123
**DMA Interrupt**
117124

118125
The DMA features a single CPU interrupt that is triggered when the programmed transfer has completed. This
@@ -127,15 +134,16 @@ explicitly cleared again by writing zero to the according <<_mip>> CSR bit.
127134
[options="header",grid="all"]
128135
|=======================
129136
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
130-
.9+<| `0xffffed00` .9+<| `CTRL` <|`0` `DMA_CTRL_EN` ^| r/w <| DMA module enable
131-
<|`1` `DMA_CTRL_AUTO` ^| r/w <| Enable automatic mode (FIRQ-triggered)
132-
<|`7:2` _reserved_ ^| r/- <| reserved, read as zero
133-
<|`8` `DMA_CTRL_ERROR_RD` ^| r/- <| Error during read access, clears when starting a new transfer
134-
<|`9` `DMA_CTRL_ERROR_WR` ^| r/- <| Error during write access, clears when starting a new transfer
135-
<|`10` `DMA_CTRL_BUSY` ^| r/- <| DMA transfer in progress
136-
<|`11` `DMA_CTRL_DONE` ^| r/c <| Set if a transfer was executed; auto-clears on write-access
137-
<|`15:12` _reserved_ ^| r/- <| reserved, read as zero
138-
<|`31:16` `DMA_CTRL_FIRQ_MASK_MSB : DMA_CTRL_FIRQ_MASK_LSB` ^| r/w <| FIRQ trigger mask (same bits as in <<_mip>>)
137+
.10+<| `0xffffed00` .10+<| `CTRL` <|`0` `DMA_CTRL_EN` ^| r/w <| DMA module enable
138+
<|`1` `DMA_CTRL_AUTO` ^| r/w <| Enable automatic mode (FIRQ-triggered)
139+
<|`2` `DMA_CTRL_FENCE` ^| r/w <| Issue a downstream FENCE operation when DMA transfer completes (without errors)
140+
<|`7:3` _reserved_ ^| r/- <| reserved, read as zero
141+
<|`8` `DMA_CTRL_ERROR_RD` ^| r/- <| Error during read access, clears when starting a new transfer
142+
<|`9` `DMA_CTRL_ERROR_WR` ^| r/- <| Error during write access, clears when starting a new transfer
143+
<|`10` `DMA_CTRL_BUSY` ^| r/- <| DMA transfer in progress
144+
<|`11` `DMA_CTRL_DONE` ^| r/c <| Set if a transfer was executed; auto-clears on write-access
145+
<|`15:12` _reserved_ ^| r/- <| reserved, read as zero
146+
<|`31:16` `DMA_CTRL_FIRQ_MASK_MSB : DMA_CTRL_FIRQ_MASK_LSB` ^| r/w <| FIRQ trigger mask (same bits as in <<_mip>>)
139147
| `0xffffed04` | `SRC_BASE` |`31:0` | r/w | Source base address (shows the last-accessed source address when read)
140148
| `0xffffed08` | `DST_BASE` |`31:0` | r/w | Destination base address (shows the last-accessed destination address when read)
141149
.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)

rtl/core/neorv32_dma.vhd

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ architecture neorv32_dma_rtl of neorv32_dma is
6969
-- control and status register bits --
7070
constant ctrl_en_c : natural := 0; -- r/w: DMA enable
7171
constant ctrl_auto_c : natural := 1; -- r/w: enable FIRQ-triggered transfer
72+
constant ctrl_fence_c : natural := 3; -- r/w: issue FENCE operation when DMA is done
7273
--
7374
constant ctrl_error_rd_c : natural := 8; -- r/-: error during read transfer
7475
constant ctrl_error_wr_c : natural := 9; -- r/-: error during write transfer
@@ -88,6 +89,7 @@ architecture neorv32_dma_rtl of neorv32_dma is
8889
type config_t is record
8990
enable : std_ulogic; -- DMA enabled when set
9091
auto : std_ulogic; -- FIRQ-driven auto transfer
92+
fence : std_ulogic; -- issue FENCE operation when DMA is done
9193
firq_mask : std_ulogic_vector(15 downto 0); -- FIRQ trigger mask
9294
src_base : std_ulogic_vector(31 downto 0); -- source base address
9395
dst_base : std_ulogic_vector(31 downto 0); -- destination base address
@@ -139,6 +141,7 @@ begin
139141
bus_rsp_o.data <= (others => '0');
140142
config.enable <= '0';
141143
config.auto <= '0';
144+
config.fence <= '0';
142145
config.firq_mask <= (others => '0');
143146
config.src_base <= (others => '0');
144147
config.dst_base <= (others => '0');
@@ -166,6 +169,7 @@ begin
166169
if (bus_req_i.addr(3 downto 2) = "00") then -- control and status register
167170
config.enable <= bus_req_i.data(ctrl_en_c);
168171
config.auto <= bus_req_i.data(ctrl_auto_c);
172+
config.fence <= bus_req_i.data(ctrl_fence_c);
169173
config.done <= '0'; -- clear on write access
170174
config.firq_mask <= bus_req_i.data(ctrl_firq_mask_msb_c downto ctrl_firq_mask_lsb_c);
171175
end if;
@@ -190,6 +194,7 @@ begin
190194
when "00" => -- control and status register
191195
bus_rsp_o.data(ctrl_en_c) <= config.enable;
192196
bus_rsp_o.data(ctrl_auto_c) <= config.auto;
197+
bus_rsp_o.data(ctrl_fence_c) <= config.fence;
193198
bus_rsp_o.data(ctrl_error_rd_c) <= engine.err_rd;
194199
bus_rsp_o.data(ctrl_error_wr_c) <= engine.err_wr;
195200
bus_rsp_o.data(ctrl_busy_c) <= engine.busy;
@@ -328,7 +333,7 @@ begin
328333
dma_req_o.src <= '0'; -- source = data access
329334
dma_req_o.addr <= engine.src_addr when (engine.state = S_READ) else engine.dst_addr;
330335
dma_req_o.rvso <= '0'; -- no reservation set operation possible
331-
dma_req_o.fence <= '0'; -- DMA cannot trigger a fence
336+
dma_req_o.fence <= config.enable and config.fence and engine.done; -- issue FENCE operation when transfer is done
332337

333338
-- address increment --
334339
address_inc: process(config.qsel)

rtl/core/neorv32_package.vhd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ package neorv32_package is
5353

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

sw/example/demo_dma/main.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ int main() {
9696
// enable DMA
9797
neorv32_dma_enable();
9898

99+
// issue a FENCE operation when the DMA transfer completes (without errors); this
100+
// will re-sync /flush and reload) all downstream caches
101+
neorv32_dma_fence_enable();
102+
99103
// initialize and data arrays
100104
dma_src[0] = 0x66778899UL;
101105
dma_src[1] = 0x22334455UL;
@@ -107,7 +111,7 @@ int main() {
107111
dma_dst[2] = 0;
108112
dma_dst[3] = 0;
109113

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

112116

113117
// ----------------------------------------------------------
@@ -264,7 +268,7 @@ int main() {
264268
**************************************************************************/
265269
void show_arrays(void) {
266270

267-
asm volatile ("fence"); // make sure main memory is sync with d-cache
271+
asm volatile ("fence"); // re-sync caches
268272
neorv32_uart0_printf("---------------------------\n");
269273
neorv32_uart0_printf(" SRC DST\n");
270274
neorv32_uart0_printf("[0] 0x%x 0x%x\n", dma_src[0], dma_dst[0]);

sw/example/processor_check/main.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1470,8 +1470,9 @@ int main() {
14701470
if (NEORV32_SYSINFO->SOC & (1 << SYSINFO_SOC_IO_DMA)) {
14711471
cnt_test++;
14721472

1473-
// enable DMA and according FIRQ channel
1473+
// enable DMA, auto-fencing and according FIRQ channel
14741474
neorv32_dma_enable();
1475+
neorv32_dma_fence_enable();
14751476
neorv32_cpu_irq_enable(DMA_FIRQ_ENABLE);
14761477

14771478
// setup source data

sw/lib/include/neorv32_dma.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// # ********************************************************************************************* #
44
// # BSD 3-Clause License #
55
// # #
6-
// # Copyright (c) 2023, Stephan Nolting. All rights reserved. #
6+
// # Copyright (c) 2024, Stephan Nolting. All rights reserved. #
77
// # #
88
// # Redistribution and use in source and binary forms, with or without modification, are #
99
// # permitted provided that the following conditions are met: #
@@ -62,6 +62,7 @@ typedef volatile struct __attribute__((packed,aligned(4))) {
6262
enum NEORV32_DMA_CTRL_enum {
6363
DMA_CTRL_EN = 0, /**< DMA control register(0) (r/w): DMA enable */
6464
DMA_CTRL_AUTO = 1, /**< DMA control register(1) (r/w): Automatic trigger mode enable */
65+
DMA_CTRL_FENCE = 2, /**< DMA control register(2) (r/w): Issue FENCE downstream operation when DMA transfer is completed */
6566

6667
DMA_CTRL_ERROR_RD = 8, /**< DMA control register(8) (r/-): Error during read access; SRC_BASE shows the faulting address */
6768
DMA_CTRL_ERROR_WR = 9, /**< DMA control register(9) (r/-): Error during write access; DST_BASE shows the faulting address */
@@ -123,6 +124,8 @@ enum NEORV32_DMA_STATUS_enum {
123124
int neorv32_dma_available(void);
124125
void neorv32_dma_enable(void);
125126
void neorv32_dma_disable(void);
127+
void neorv32_dma_fence_enable(void);
128+
void neorv32_dma_fence_disable(void);
126129
void neorv32_dma_transfer(uint32_t base_src, uint32_t base_dst, uint32_t num, uint32_t config);
127130
void neorv32_dma_transfer_auto(uint32_t base_src, uint32_t base_dst, uint32_t num, uint32_t config, uint32_t firq_mask);
128131
int neorv32_dma_status(void);

sw/lib/source/neorv32_dma.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// # ********************************************************************************************* #
44
// # BSD 3-Clause License #
55
// # #
6-
// # Copyright (c) 2023, Stephan Nolting. All rights reserved. #
6+
// # Copyright (c) 2024, Stephan Nolting. All rights reserved. #
77
// # #
88
// # Redistribution and use in source and binary forms, with or without modification, are #
99
// # permitted provided that the following conditions are met: #
@@ -78,6 +78,25 @@ void neorv32_dma_disable(void) {
7878
}
7979

8080

81+
/**********************************************************************//**
82+
* Enable memory barrier (fence): issue a FENCE operation when DMA transfer
83+
* completes without errors.
84+
**************************************************************************/
85+
void neorv32_dma_fence_enable(void) {
86+
87+
NEORV32_DMA->CTRL |= (uint32_t)(1 << DMA_CTRL_FENCE);
88+
}
89+
90+
91+
/**********************************************************************//**
92+
* Disable memory barrier (fence).
93+
**************************************************************************/
94+
void neorv32_dma_fence_disable(void) {
95+
96+
NEORV32_DMA->CTRL &= ~((uint32_t)(1 << DMA_CTRL_FENCE));
97+
}
98+
99+
81100
/**********************************************************************//**
82101
* Trigger manual DMA transfer.
83102
*

sw/svd/neorv32.svd

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,11 @@
371371
<bitRange>[1:1]</bitRange>
372372
<description>Enable automatic transfer trigger (FIRQ-triggered)</description>
373373
</field>
374+
<field>
375+
<name>DMA_CTRL_FENCE</name>
376+
<bitRange>[2:2]</bitRange>
377+
<description>Issue a downstream FENCE operation when DMA transfer completes (without errors)</description>
378+
</field>
374379
<field>
375380
<name>DMA_CTRL_ERROR_RD</name>
376381
<bitRange>[8:8]</bitRange>

0 commit comments

Comments
 (0)