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

[DMA] use FIRQ select instead of FIRQ mask #877

Merged
merged 6 commits into from
Apr 17, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12

| Date | Version | Comment | Link |
|:----:|:-------:|:--------|:----:|
| 16.04.2024 | 1.9.8.4 | :warning: use a 4-bit FIRQ select instead of a 16-bit FIRQ mask for DMA auto-trigger configuration | [#877](https://github.com/stnolting/neorv32/pull/877) |
| 15.04.2024 | 1.9.8.3 | :warning: simplify XBUS gateway logic and configuration generics; only "pipelined Wishbone" protocol is supported now | [#876](https://github.com/stnolting/neorv32/pull/876) |
| 14.04.2024 | 1.9.8.2 | :warning: rename SLINK data interface registers; minor CPU control logic/area optimizations | [#874](https://github.com/stnolting/neorv32/pull/874) |
| 13.04.2024 | 1.9.8.1 | minor rtl code cleanups and optimizations | [#872](https://github.com/stnolting/neorv32/pull/872) |
Expand Down
2 changes: 1 addition & 1 deletion docs/datasheet/soc.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,12 @@ Some interfaces (like the TWI and the 1-Wire bus) require tri-state drivers in t
| `jtag_tms_i` | 1 | in | `'L'` | mode select
5+^| **<<_processor_external_bus_interface_xbus>>**
| `xbus_adr_o` | 32 | out | - | destination address
| `xbus_dat_i` | 32 | in | `'L'` | write data
| `xbus_dat_o` | 32 | out | - | read data
| `xbus_we_o` | 1 | out | - | write enable ('0' = read transfer)
| `xbus_sel_o` | 4 | out | - | byte enable
| `xbus_stb_o` | 1 | out | - | strobe
| `xbus_cyc_o` | 1 | out | - | valid cycle
| `xbus_dat_i` | 32 | in | `'L'` | write data
| `xbus_ack_i` | 1 | in | `'L'` | transfer acknowledge
| `xbus_err_i` | 1 | in | `'L'` | transfer error
5+^| **<<_stream_link_interface_slink>>**
Expand Down
46 changes: 23 additions & 23 deletions docs/datasheet/soc_dma.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
[cols="<3,<3,<4"]
[frame="topbot",grid="none"]
|=======================
| Hardware source file(s): | neorv32_dma.vhd |
| Software driver file(s): | neorv32_dma.c |
| | neorv32_dma.h |
| Top entity port: | none |
| Configuration generics: | `IO_DMA_EN` | implement DMA when `true`
| CPU interrupts: | fast IRQ channel 10 | DMA transfer done (see <<_processor_interrupts>>)
| Hardware source files: | neorv32_dma.vhd |
| Software driver files: | neorv32_dma.c |
| | neorv32_dma.h |
| Top entity ports: | none |
| Configuration generics: | `IO_DMA_EN` | implement DMA when `true`
| CPU interrupts: | fast IRQ channel 10 | DMA transfer done (see <<_processor_interrupts>>)
|=======================


Expand Down Expand Up @@ -98,19 +98,18 @@ data quantity has to be set to **word** (32-bit) since all IO registers can only
**Automatic Trigger**

As an alternative to the manual trigger mode, the DMA can be configured to **automatic trigger mode** starting a pre-configured
transfer if a specific processor-internal peripheral issues an interrupt request. The automatic trigger mode is enabled by
transfer if a specific processor-internal peripheral issues a FIRQ interrupt request. The automatic trigger mode is enabled by
setting the `CTRL` register's `DMA_CTRL_AUTO` bit. In this configuration _no_ transfer is started when writing to the DMA's
`TTYPE` register.

The actual trigger is configured via the control register `DMA_CTRL_FIRQ_MASK`. These bits reflect the state of the CPU's
<<_mip>> CSR showing any pending fast interrupt requests (for a full list see <<_neorv32_specific_fast_interrupt_requests>>).
The same bit definitions/locations as for the <<_mip>> and <<_mie>> CPU CSRs are used.
If any of the enabled sources issues an interrupt the DMA will start the pre-configured transfer (note that all enabled
sources are logically OR-ed).
The actually triggering FIRQ channel is configured via the control register's `DMA_CTRL_FIRQ_SEL` bits. Writing a 0 will
select FIRQ channel 0, writing a 1 will select FIRQ channel 1, and so on. See section <<_processor_interrupts>>
for a list of all FIRQ channels and their according sources.

.FIRQ Trigger
[NOTE]
The DMA transfer will start if a **rising edge** is detected on _any_ of the enabled FIRQ source channels.
The DMA transfer will start if a **rising edge** is detected on the configured FIRQ channel. Hence, the DMA is triggered only
once even if the selected FIRQ channel keeps pending.


**Memory Barrier / Fence Operation**
Expand All @@ -135,16 +134,17 @@ register).
[options="header",grid="all"]
|=======================
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
.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>>)
.11+<| `0xffffed00` .11+<| `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
<|`19:16` `DMA_CTRL_FIRQ_SEL_MSB : DMA_CTRL_FIRQ_SEL_LSB` ^| r/w <| FIRQ trigger select (FIRQ0=0 ... FIRQ15=15)
<|`31:20` _reserved_ ^| r/- <| reserved, read as zero
| `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
16 changes: 8 additions & 8 deletions rtl/core/neorv32_dma.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ architecture neorv32_dma_rtl of neorv32_dma is
constant ctrl_busy_c : natural := 10; -- r/-: DMA transfer in progress
constant ctrl_done_c : natural := 11; -- r/c: a DMA transfer was executed/attempted
--
constant ctrl_firq_mask_lsb_c : natural := 16; -- r/w: FIRQ trigger mask LSB
constant ctrl_firq_mask_msb_c : natural := 31; -- r/w: FIRQ trigger mask MSB
constant ctrl_firq_sel_lsb_c : natural := 16; -- r/w: FIRQ trigger select LSB
constant ctrl_firq_sel_msb_c : natural := 19; -- r/w: FIRQ trigger select MSB

-- transfer quantities --
constant qsel_b2b_c : std_ulogic_vector(1 downto 0) := "00"; -- byte to byte
Expand All @@ -64,7 +64,7 @@ architecture neorv32_dma_rtl of neorv32_dma is
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
firq_sel : std_ulogic_vector(03 downto 0); -- FIRQ trigger select
src_base : std_ulogic_vector(31 downto 0); -- source base address
dst_base : std_ulogic_vector(31 downto 0); -- destination base address
num : std_ulogic_vector(23 downto 0); -- number of elements
Expand Down Expand Up @@ -116,7 +116,7 @@ begin
config.enable <= '0';
config.auto <= '0';
config.fence <= '0';
config.firq_mask <= (others => '0');
config.firq_sel <= (others => '0');
config.src_base <= (others => '0');
config.dst_base <= (others => '0');
config.num <= (others => '0');
Expand All @@ -143,7 +143,7 @@ begin
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);
config.firq_sel <= bus_req_i.data(ctrl_firq_sel_msb_c downto ctrl_firq_sel_lsb_c);
end if;
if (bus_req_i.addr(3 downto 2) = "01") then -- source base address
config.src_base <= bus_req_i.data;
Expand All @@ -169,7 +169,7 @@ begin
bus_rsp_o.data(ctrl_error_wr_c) <= engine.err_wr;
bus_rsp_o.data(ctrl_busy_c) <= engine.busy;
bus_rsp_o.data(ctrl_done_c) <= config.done;
bus_rsp_o.data(ctrl_firq_mask_msb_c downto ctrl_firq_mask_lsb_c) <= config.firq_mask;
bus_rsp_o.data(ctrl_firq_sel_msb_c downto ctrl_firq_sel_lsb_c) <= config.firq_sel;
when "01" => -- address of last read access
bus_rsp_o.data <= engine.src_addr;
when "10" => -- address of last write access
Expand Down Expand Up @@ -205,8 +205,8 @@ begin
end if;
end process automatic_trigger;

-- logical OR of all enabled trigger FIRQs --
match <= or_reduce_f(firq_buf and config.firq_mask);
-- select a single FIRQ --
match <= firq_buf(to_integer(unsigned(config.firq_sel)));


-- Bus Access Engine ----------------------------------------------------------------------
Expand Down
4 changes: 2 additions & 2 deletions rtl/core/neorv32_package.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ package neorv32_package is

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

Expand Down Expand Up @@ -816,12 +816,12 @@ package neorv32_package is
jtag_tms_i : in std_ulogic := 'L';
-- External bus interface (available if XBUS_EN = true) --
xbus_adr_o : out std_ulogic_vector(31 downto 0);
xbus_dat_i : in std_ulogic_vector(31 downto 0) := (others => 'L');
xbus_dat_o : out std_ulogic_vector(31 downto 0);
xbus_we_o : out std_ulogic;
xbus_sel_o : out std_ulogic_vector(03 downto 0);
xbus_stb_o : out std_ulogic;
xbus_cyc_o : out std_ulogic;
xbus_dat_i : in std_ulogic_vector(31 downto 0) := (others => 'L');
xbus_ack_i : in std_ulogic := 'L';
xbus_err_i : in std_ulogic := 'L';
-- Stream Link Interface (available if IO_SLINK_EN = true) --
Expand Down
2 changes: 1 addition & 1 deletion rtl/core/neorv32_top.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,12 @@ entity neorv32_top is

-- External bus interface (available if XBUS_EN = true) --
xbus_adr_o : out std_ulogic_vector(31 downto 0); -- address
xbus_dat_i : in std_ulogic_vector(31 downto 0) := (others => 'L'); -- read data
xbus_dat_o : out std_ulogic_vector(31 downto 0); -- write data
xbus_we_o : out std_ulogic; -- read/write
xbus_sel_o : out std_ulogic_vector(03 downto 0); -- byte enable
xbus_stb_o : out std_ulogic; -- strobe
xbus_cyc_o : out std_ulogic; -- valid cycle
xbus_dat_i : in std_ulogic_vector(31 downto 0) := (others => 'L'); -- read data
xbus_ack_i : in std_ulogic := 'L'; -- transfer acknowledge
xbus_err_i : in std_ulogic := 'L'; -- transfer error

Expand Down
2 changes: 1 addition & 1 deletion rtl/system_integration/neorv32_litex_core_complex.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -161,12 +161,12 @@ begin
jtag_tms_i => jtag_tms_i, -- mode select
-- External bus interface --
xbus_adr_o => wb_adr_o, -- address
xbus_dat_i => wb_dat_i, -- read data
xbus_dat_o => wb_dat_o, -- write data
xbus_we_o => wb_we_o, -- read/write
xbus_sel_o => wb_sel_o, -- byte enable
xbus_stb_o => open, -- strobe
xbus_cyc_o => wb_cyc, -- valid cycle
xbus_dat_i => wb_dat_i, -- read data
xbus_ack_i => wb_ack_i, -- transfer acknowledge
xbus_err_i => wb_err_i, -- transfer error
-- CPU Interrupts --
Expand Down
2 changes: 1 addition & 1 deletion sim/neorv32_tb.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -295,12 +295,12 @@ begin
jtag_tms_i => '0', -- mode select
-- External bus interface (available if XBUS_EN = true) --
xbus_adr_o => wb_cpu.addr, -- address
xbus_dat_i => wb_cpu.rdata, -- read data
xbus_dat_o => wb_cpu.wdata, -- write data
xbus_we_o => wb_cpu.we, -- read/write
xbus_sel_o => wb_cpu.sel, -- byte enable
xbus_stb_o => wb_cpu.stb, -- strobe
xbus_cyc_o => wb_cpu.cyc, -- valid cycle
xbus_dat_i => wb_cpu.rdata, -- read data
xbus_ack_i => wb_cpu.ack, -- transfer acknowledge
xbus_err_i => wb_cpu.err, -- transfer error
-- Stream Link Interface (available if IO_SLINK_EN = true) --
Expand Down
2 changes: 1 addition & 1 deletion sim/simple/neorv32_tb.simple.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -271,12 +271,12 @@ begin
jtag_tms_i => '0', -- mode select
-- External bus interface (available if XBUS_EN = true) --
xbus_adr_o => wb_cpu.addr, -- address
xbus_dat_i => wb_cpu.rdata, -- read data
xbus_dat_o => wb_cpu.wdata, -- write data
xbus_we_o => wb_cpu.we, -- read/write
xbus_sel_o => wb_cpu.sel, -- byte enable
xbus_stb_o => wb_cpu.stb, -- strobe
xbus_cyc_o => wb_cpu.cyc, -- valid cycle
xbus_dat_i => wb_cpu.rdata, -- read data
xbus_ack_i => wb_cpu.ack, -- transfer acknowledge
xbus_err_i => wb_cpu.err, -- transfer error
-- Stream Link Interface (available if IO_SLINK_EN = true) --
Expand Down
22 changes: 17 additions & 5 deletions sw/example/demo_dma/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,9 @@ int main() {
(dma_dst[3] != 0xffee1100)) {
neorv32_uart0_printf("Incorrect DST data!\n");
}
else {
neorv32_uart0_printf("Transfer succeeded!\n");
}

show_arrays();

Expand Down Expand Up @@ -199,6 +202,9 @@ int main() {
(dma_dst[3] != 0x66778899)) {
neorv32_uart0_printf("Incorrect DST data!\n");
}
else {
neorv32_uart0_printf("Transfer succeeded!\n");
}

show_arrays();

Expand Down Expand Up @@ -236,6 +242,9 @@ int main() {
(dma_dst[3] != 0x00000066)) {
neorv32_uart0_printf("Transfer failed!\n");
}
else {
neorv32_uart0_printf("Transfer succeeded!\n");
}

show_arrays();

Expand All @@ -262,11 +271,11 @@ int main() {
DMA_CMD_DST_INC; // auto-increment destination address

// configure automatic DMA transfer
neorv32_dma_transfer_auto((uint32_t)(&dma_src[3]), // source array base address (data = 0xff)
(uint32_t)(&dma_dst[0]), // destination array base address
16, // number of elements to transfer: 16
cmd, // transfer type configuration
1 << GPTMR_FIRQ_PENDING); // trigger transfer on pending GPTMR interrupt
neorv32_dma_transfer_auto((uint32_t)(&dma_src[3]), // source array base address (data = 0xff)
(uint32_t)(&dma_dst[0]), // destination array base address
16, // number of elements to transfer: 16
cmd, // transfer type configuration
GPTMR_FIRQ_PENDING); // trigger transfer on pending GPTMR interrupt

// sleep until interrupt (from DMA)
neorv32_cpu_sleep();
Expand All @@ -281,6 +290,9 @@ int main() {
(dma_dst[3] != 0xffffffff)) {
neorv32_uart0_printf("Transfer failed!\n");
}
else {
neorv32_uart0_printf("Transfer succeeded!\n");
}

show_arrays();
}
Expand Down
20 changes: 10 additions & 10 deletions sw/lib/include/neorv32_dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,17 @@ typedef volatile struct __attribute__((packed,aligned(4))) {

/** DMA control and status register bits */
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_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 */
DMA_CTRL_BUSY = 10, /**< DMA control register(10) (r/-): DMA busy / transfer in progress */
DMA_CTRL_DONE = 11, /**< DMA control register(11) (r/c): A transfer was executed when set */
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 */
DMA_CTRL_BUSY = 10, /**< DMA control register(10) (r/-): DMA busy / transfer in progress */
DMA_CTRL_DONE = 11, /**< DMA control register(11) (r/c): A transfer was executed when set */

DMA_CTRL_FIRQ_MASK_LSB = 16, /**< DMA control register(16) (r/w): FIRQ trigger mask LSB */
DMA_CTRL_FIRQ_MASK_MSB = 31 /**< DMA control register(31) (r/w): FIRQ trigger mask MSB */
DMA_CTRL_FIRQ_SEL_LSB = 16, /**< DMA control register(16) (r/w): FIRQ trigger select LSB */
DMA_CTRL_FIRQ_SEL_MSB = 19 /**< DMA control register(19) (r/w): FIRQ trigger select MSB */
};

/** DMA transfer type bits */
Expand Down Expand Up @@ -127,7 +127,7 @@ 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);
void neorv32_dma_transfer_auto(uint32_t base_src, uint32_t base_dst, uint32_t num, uint32_t config, int firq_sel);
int neorv32_dma_status(void);
int neorv32_dma_done(void);
/**@}*/
Expand Down