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 additional SPI and SDI interrupt conditions #870

Merged
merged 8 commits into from
Apr 4, 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 @@ -29,6 +29,7 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12

| Date | Version | Comment | Link |
|:----:|:-------:|:--------|:----:|
| 04.04.2024 | 1.9.7.10 | extend SPI and SDI interrupt conditions | [#870](https://github.com/stnolting/neorv32/pull/870) |
| 04.04.2024 | 1.9.7.9 | RISC-V `B` ISA extension (bit-manipulation) only contains sub-extensions `Zba+Zbb+Zbs`; :warning: remove support for `Zbc` ISA extension | [#869](https://github.com/stnolting/neorv32/pull/869) |
| 03.04.2024 | 1.9.7.8 | split SLINK interrupt into two individual FIRQs (SLINK RX and SLINK TX) | [#868](https://github.com/stnolting/neorv32/pull/868) |
| 01.04.2024 | 1.9.7.7 | add back TWI clock stretching option | [#867](https://github.com/stnolting/neorv32/pull/867) |
Expand Down
35 changes: 20 additions & 15 deletions docs/datasheet/soc_sdi.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@
[cols="<3,<3,<4"]
[frame="topbot",grid="none"]
|=======================
| Hardware source file(s): | neorv32_sdi.vhd |
| Software driver file(s): | neorv32_sdi.c |
| | neorv32_sdi.h |
| Top entity port: | `sdi_clk_i` | 1-bit serial clock input
| | `sdi_dat_o` | 1-bit serial data output
| | `sdi_dat_i` | 1-bit serial data input
| | `sdi_csn_i` | 1-bit chip-select input (low-active)
| Configuration generics: | `IO_SDI_EN` | implement SDI controller when `true`
| | `IO_SDI_FIFO` | data FIFO size, has to a power of two, min 1
| CPU interrupts: | fast IRQ channel 11 | configurable SDI interrupt (see <<_processor_interrupts>>)
| Hardware source files: | neorv32_sdi.vhd |
| Software driver files: | neorv32_sdi.c |
| | neorv32_sdi.h |
| Top entity ports: | `sdi_clk_i` | 1-bit serial clock input
| | `sdi_dat_o` | 1-bit serial data output
| | `sdi_dat_i` | 1-bit serial data input
| | `sdi_csn_i` | 1-bit chip-select input (low-active)
| Configuration generics: | `IO_SDI_EN` | implement SDI controller when `true`
| | `IO_SDI_FIFO` | data FIFO size, has to a power of two, min 1
| CPU interrupts: | fast IRQ channel 11 | configurable SDI interrupt (see <<_processor_interrupts>>)
|=======================


Expand Down Expand Up @@ -45,6 +45,9 @@ data can be retrieved by reading the RX FIFO via the `DATA` register. The curren
via the control register's `SDI_CTRL_RX_*` and `SDI_CTRL_TX_*` flags. The RX FIFO can be manually cleared at any time
by setting the `SDI_CTRL_CLR_RX` bit.

If no data is available in the TX FIFO while an external device performs a transmission the external device will
read all-zero from the SDI controller.

.MSB-first Only
[NOTE]
The NEORV32 SDI module only supports MSB-first mode.
Expand All @@ -66,7 +69,7 @@ clock domain to simplify timing behavior. However, the clock synchronization req
**SDI Interrupt**

The SDI module provides a set of programmable interrupt conditions based on the level of the RX & TX FIFOs. The different
interrupt sources are enabled by setting the according control register's `SDI_CTRL_IRQ` bits. All enabled interrupt
interrupt sources are enabled by setting the according control register's `SDI_CTRL_IRQ_*` bits. All enabled interrupt
conditions are logically OR-ed so any enabled interrupt source will trigger the module's interrupt signal.

Once the SDI interrupt has fired it will remain active until the actual cause of the interrupt is resolved; for
Expand All @@ -80,7 +83,7 @@ example if just the `SDI_CTRL_IRQ_RX_AVAIL` bit is set, the interrupt will keep
[options="header",grid="all"]
|=======================
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
.16+<| `0xfffff700` .16+<| `CTRL` <|`0` `SDI_CTRL_EN` ^| r/w <| SDI module enable
.18+<| `0xfffff700` .18+<| `CTRL` <|`0` `SDI_CTRL_EN` ^| r/w <| SDI module enable
<|`1` `SDI_CTRL_CLR_RX` ^| -/w <| clear RX FIFO when set, bit auto-clears
<|`3:2` _reserved_ ^| r/- <| reserved, read as zero
<|`7:4` `SDI_CTRL_FIFO_MSB : SDI_CTRL_FIFO_LSB` ^| r/- <| FIFO depth; log2(_IO_SDI_FIFO_)
Expand All @@ -89,12 +92,14 @@ example if just the `SDI_CTRL_IRQ_RX_AVAIL` bit is set, the interrupt will keep
<|`16` `SDI_CTRL_IRQ_RX_HALF` ^| r/w <| fire interrupt if RX FIFO is at least half full
<|`17` `SDI_CTRL_IRQ_RX_FULL` ^| r/w <| fire interrupt if if RX FIFO is full
<|`18` `SDI_CTRL_IRQ_TX_EMPTY` ^| r/w <| fire interrupt if TX FIFO is empty
<|`22:19` _reserved_ ^| r/- <| reserved, read as zero
<|`19` `SDI_CTRL_IRQ_TX_NHALF` ^| r/w <| fire interrupt if TX FIFO is not at least half full
<|`22:20` _reserved_ ^| r/- <| reserved, read as zero
<|`23` `SDI_CTRL_RX_AVAIL` ^| r/- <| RX FIFO data available (RX FIFO not empty)
<|`24` `SDI_CTRL_RX_HALF` ^| r/- <| RX FIFO at least half full
<|`25` `SDI_CTRL_RX_FULL` ^| r/- <| RX FIFO full
<|`26` `SDI_CTRL_TX_EMPTY` ^| r/- <| TX FIFO empty
<|`27` `SDI_CTRL_TX_FULL` ^| r/- <| TX FIFO full
<|`31:28` _reserved_ ^| r/- <| reserved, read as zero
<|`27` `SDI_CTRL_TX_NHALF` ^| r/- <| TX FIFO not at least half full
<|`28` `SDI_CTRL_TX_FULL` ^| r/- <| TX FIFO full
<|`31:29` _reserved_ ^| r/- <| reserved, read as zero
| `0xfffff704` | `DATA` |`7:0` | r/w | receive/transmit data (FIFO)
|=======================
27 changes: 14 additions & 13 deletions docs/datasheet/soc_spi.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@
[cols="<3,<3,<4"]
[frame="topbot",grid="none"]
|=======================
| Hardware source file(s): | neorv32_spi.vhd |
| Software driver file(s): | neorv32_spi.c |
| | neorv32_spi.h |
| Top entity port: | `spi_clk_o` | 1-bit serial clock output
| | `spi_dat_o` | 1-bit serial data output
| | `spi_dat_i` | 1-bit serial data input
| | `spi_csn_o` | 8-bit dedicated chip select output (low-active)
| Configuration generics: | `IO_SPI_EN` | implement SPI controller when `true`
| | `IO_SPI_FIFO` | FIFO depth, has to be a power of two, min 1
| CPU interrupts: | fast IRQ channel 6 | configurable SPI interrupt (see <<_processor_interrupts>>)
| Hardware source files: | neorv32_spi.vhd |
| Software driver files: | neorv32_spi.c |
| | neorv32_spi.h |
| Top entity ports: | `spi_clk_o` | 1-bit serial clock output
| | `spi_dat_o` | 1-bit serial data output
| | `spi_dat_i` | 1-bit serial data input
| | `spi_csn_o` | 8-bit dedicated chip select output (low-active)
| Configuration generics: | `IO_SPI_EN` | implement SPI controller when `true`
| | `IO_SPI_FIFO` | FIFO depth, has to be a power of two, min 1
| CPU interrupts: | fast IRQ channel 6 | configurable SPI interrupt (see <<_processor_interrupts>>)
|=======================


Expand Down Expand Up @@ -114,7 +114,7 @@ example if just the `SPI_CTRL_IRQ_RX_AVAIL` bit is set, the interrupt will keep
[options="header",grid="all"]
|=======================
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
.19+<| `0xfffff800` .19+<| `CTRL` <|`0` `SPI_CTRL_EN` ^| r/w <| SPI module enable
.20+<| `0xfffff800` .20+<| `CTRL` <|`0` `SPI_CTRL_EN` ^| r/w <| SPI module enable
<|`1` `SPI_CTRL_CPHA` ^| r/w <| clock phase
<|`2` `SPI_CTRL_CPOL` ^| r/w <| clock polarity
<|`5:3` `SPI_CTRL_CS_SEL2 : SPI_CTRL_CS_SEL0` ^| r/w <| Direct chip-select 0..7
Expand All @@ -130,8 +130,9 @@ example if just the `SPI_CTRL_IRQ_RX_AVAIL` bit is set, the interrupt will keep
<|`20` `SPI_CTRL_IRQ_RX_AVAIL` ^| r/w <| Trigger IRQ if RX FIFO not empty
<|`21` `SPI_CTRL_IRQ_TX_EMPTY` ^| r/w <| Trigger IRQ if TX FIFO empty
<|`22` `SPI_CTRL_IRQ_TX_NHALF` ^| r/w <| Trigger IRQ if TX FIFO _not_ at least half full
<|`26:23` `SPI_CTRL_FIFO_MSB : SPI_CTRL_FIFO_LSB` ^| r/- <| FIFO depth; log2(_IO_SPI_FIFO_)
<|`30:27` _reserved_ ^| r/- <| reserved, read as zero
<|`23` `SPI_CTRL_IRQ_IDLE` ^| r/w <| Trigger IRQ if TX FIFO is empty and SPI bus engine is idle
<|`27:24` `SPI_CTRL_FIFO_MSB : SPI_CTRL_FIFO_LSB` ^| r/- <| FIFO depth; log2(_IO_SPI_FIFO_)
<|`30:28` _reserved_ ^| r/- <| reserved, read as zero
<|`31` `SPI_CTRL_BUSY` ^| r/- <| SPI module busy when set (serial engine operation in progress and TX FIFO not empty yet)
| `0xfffff804` | `DATA` |`7:0` | r/w | receive/transmit data (FIFO)
|=======================
2 changes: 1 addition & 1 deletion rtl/core/neorv32_package.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ package neorv32_package is

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

Expand Down
38 changes: 20 additions & 18 deletions rtl/core/neorv32_sdi.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,17 @@ architecture neorv32_sdi_rtl of neorv32_sdi is
constant ctrl_fifo_size2_c : natural := 6; -- r/-: log2(FIFO size), bit 2
constant ctrl_fifo_size3_c : natural := 7; -- r/-: log2(FIFO size), bit 3 (msb)
--
constant ctrl_irq_rx_avail_c : natural := 15; -- r/-: RX FIFO not empty
constant ctrl_irq_rx_half_c : natural := 16; -- r/-: RX FIFO at least half full
constant ctrl_irq_rx_full_c : natural := 17; -- r/-: RX FIFO full
constant ctrl_irq_tx_empty_c : natural := 18; -- r/-: TX FIFO empty
constant ctrl_irq_rx_avail_c : natural := 15; -- r/w: RX FIFO not empty
constant ctrl_irq_rx_half_c : natural := 16; -- r/w: RX FIFO at least half full
constant ctrl_irq_rx_full_c : natural := 17; -- r/w: RX FIFO full
constant ctrl_irq_tx_empty_c : natural := 18; -- r/w: TX FIFO empty
constant ctrl_irq_tx_nhalf_c : natural := 19; -- r/w: TX FIFO not at least half full
--
constant ctrl_rx_avail_c : natural := 23; -- r/-: RX FIFO not empty
constant ctrl_rx_half_c : natural := 24; -- r/-: RX FIFO at least half full
constant ctrl_rx_full_c : natural := 25; -- r/-: RX FIFO full
constant ctrl_tx_empty_c : natural := 26; -- r/-: TX FIFO empty
constant ctrl_tx_nhalf_c : natural := 27; -- r/-: TX FIFO not at least half-full
constant ctrl_tx_full_c : natural := 27; -- r/-: TX FIFO full

-- control register (see bit definitions above) --
Expand All @@ -89,6 +91,7 @@ architecture neorv32_sdi_rtl of neorv32_sdi is
irq_rx_half : std_ulogic;
irq_rx_full : std_ulogic;
irq_tx_empty : std_ulogic;
irq_tx_nhalf : std_ulogic;
end record;
signal ctrl : ctrl_t;

Expand Down Expand Up @@ -143,19 +146,17 @@ begin
ctrl.irq_rx_half <= '0';
ctrl.irq_rx_full <= '0';
ctrl.irq_tx_empty <= '0';
ctrl.irq_tx_nhalf <= '0';
elsif rising_edge(clk_i) then
-- bus handshake --
bus_rsp_o.ack <= bus_req_i.stb;
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');

-- defaults --
ctrl.clr_rx <= '0';

-- read/write access --
ctrl.clr_rx <= '0'; -- default
if (bus_req_i.stb = '1') then

-- write access --
if (bus_req_i.rw = '1') then
if (bus_req_i.rw = '1') then -- write access
if (bus_req_i.addr(2) = '0') then -- control register
ctrl.enable <= bus_req_i.data(ctrl_en_c);
ctrl.clr_rx <= bus_req_i.data(ctrl_clr_rx_c);
Expand All @@ -164,10 +165,9 @@ begin
ctrl.irq_rx_half <= bus_req_i.data(ctrl_irq_rx_half_c);
ctrl.irq_rx_full <= bus_req_i.data(ctrl_irq_rx_full_c);
ctrl.irq_tx_empty <= bus_req_i.data(ctrl_irq_tx_empty_c);
ctrl.irq_tx_nhalf <= bus_req_i.data(ctrl_irq_tx_nhalf_c);
end if;

-- read access --
else
else -- read access
if (bus_req_i.addr(2) = '0') then -- control register
bus_rsp_o.data(ctrl_en_c) <= ctrl.enable;
--
Expand All @@ -177,17 +177,18 @@ begin
bus_rsp_o.data(ctrl_irq_rx_half_c) <= ctrl.irq_rx_half;
bus_rsp_o.data(ctrl_irq_rx_full_c) <= ctrl.irq_rx_full;
bus_rsp_o.data(ctrl_irq_tx_empty_c) <= ctrl.irq_tx_empty;
bus_rsp_o.data(ctrl_irq_tx_nhalf_c) <= ctrl.irq_tx_nhalf;
--
bus_rsp_o.data(ctrl_rx_avail_c) <= rx_fifo.avail;
bus_rsp_o.data(ctrl_rx_half_c) <= rx_fifo.half;
bus_rsp_o.data(ctrl_rx_full_c) <= not rx_fifo.free;
bus_rsp_o.data(ctrl_tx_empty_c) <= not tx_fifo.avail;
bus_rsp_o.data(ctrl_tx_nhalf_c) <= not tx_fifo.half;
bus_rsp_o.data(ctrl_tx_full_c) <= not tx_fifo.free;
else -- data register
bus_rsp_o.data(7 downto 0) <= rx_fifo.rdata;
end if;
end if;

end if;
end if;
end process bus_access;
Expand Down Expand Up @@ -270,10 +271,11 @@ begin
irq_o <= '0';
elsif rising_edge(clk_i) then
irq_o <= ctrl.enable and (
(ctrl.irq_rx_avail and rx_fifo.avail) or -- RX FIFO not empty
(ctrl.irq_rx_half and rx_fifo.half) or -- RX FIFO at least half full
(ctrl.irq_rx_full and (not rx_fifo.free)) or -- RX FIFO full
(ctrl.irq_tx_empty and (not tx_fifo.avail))); -- TX FIFO empty
(ctrl.irq_rx_avail and rx_fifo.avail) or -- RX FIFO not empty
(ctrl.irq_rx_half and rx_fifo.half) or -- RX FIFO at least half full
(ctrl.irq_rx_full and (not rx_fifo.free)) or -- RX FIFO full
(ctrl.irq_tx_empty and (not tx_fifo.avail)) or -- TX FIFO empty
(ctrl.irq_tx_nhalf and (not tx_fifo.half))); -- TX FIFO not at least half full
end if;
end process irq_generator;

Expand Down
29 changes: 16 additions & 13 deletions rtl/core/neorv32_spi.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,11 @@ architecture neorv32_spi_rtl of neorv32_spi is
constant ctrl_irq_rx_avail_c : natural := 20; -- r/w: fire irq if rx fifo data available (fifo not empty)
constant ctrl_irq_tx_empty_c : natural := 21; -- r/w: fire irq if tx fifo empty
constant ctrl_irq_tx_nhalf_c : natural := 22; -- r/w: fire irq if tx fifo not at least half full
constant ctrl_fifo_size0_c : natural := 23; -- r/-: log2(fifo size), bit 0 (lsb)
constant ctrl_fifo_size1_c : natural := 24; -- r/-: log2(fifo size), bit 1
constant ctrl_fifo_size2_c : natural := 25; -- r/-: log2(fifo size), bit 2
constant ctrl_fifo_size3_c : natural := 26; -- r/-: log2(fifo size), bit 3 (msb)
constant ctrl_irq_idle_c : natural := 23; -- r/w: fire irq if tx fifo is empty and serial engine is idle
constant ctrl_fifo_size0_c : natural := 24; -- r/-: log2(fifo size), bit 0 (lsb)
constant ctrl_fifo_size1_c : natural := 25; -- r/-: log2(fifo size), bit 1
constant ctrl_fifo_size2_c : natural := 26; -- r/-: log2(fifo size), bit 2
constant ctrl_fifo_size3_c : natural := 27; -- r/-: log2(fifo size), bit 3 (msb)
--
constant ctrl_busy_c : natural := 31; -- r/-: spi phy busy or tx fifo not empty yet

Expand All @@ -103,14 +104,15 @@ architecture neorv32_spi_rtl of neorv32_spi is
irq_rx_avail : std_ulogic;
irq_tx_empty : std_ulogic;
irq_tx_nhalf : std_ulogic;
irq_idle : std_ulogic;
end record;
signal ctrl : ctrl_t;

-- clock generator --
signal cdiv_cnt : std_ulogic_vector(3 downto 0);
signal spi_clk_en : std_ulogic;

-- spi transceiver --
-- SPI engine --
type rtx_engine_t is record
state : std_ulogic_vector(2 downto 0);
busy : std_ulogic;
Expand Down Expand Up @@ -156,15 +158,16 @@ begin
ctrl.irq_rx_avail <= '0';
ctrl.irq_tx_empty <= '0';
ctrl.irq_tx_nhalf <= '0';
ctrl.irq_idle <= '0';
elsif rising_edge(clk_i) then
-- bus handshake --
bus_rsp_o.ack <= bus_req_i.stb;
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
if (bus_req_i.stb = '1') then

-- write access --
if (bus_req_i.rw = '1') then
-- read/write access --
if (bus_req_i.stb = '1') then
if (bus_req_i.rw = '1') then -- write access
if (bus_req_i.addr(2) = '0') then -- control register
ctrl.enable <= bus_req_i.data(ctrl_en_c);
ctrl.cpha <= bus_req_i.data(ctrl_cpha_c);
Expand All @@ -177,10 +180,9 @@ begin
ctrl.irq_rx_avail <= bus_req_i.data(ctrl_irq_rx_avail_c);
ctrl.irq_tx_empty <= bus_req_i.data(ctrl_irq_tx_empty_c);
ctrl.irq_tx_nhalf <= bus_req_i.data(ctrl_irq_tx_nhalf_c);
ctrl.irq_idle <= bus_req_i.data(ctrl_irq_idle_c);
end if;

-- read access --
else
else -- read access
if (bus_req_i.addr(2) = '0') then -- control register
bus_rsp_o.data(ctrl_en_c) <= ctrl.enable;
bus_rsp_o.data(ctrl_cpha_c) <= ctrl.cpha;
Expand All @@ -198,6 +200,7 @@ begin
bus_rsp_o.data(ctrl_irq_rx_avail_c) <= ctrl.irq_rx_avail;
bus_rsp_o.data(ctrl_irq_tx_empty_c) <= ctrl.irq_tx_empty;
bus_rsp_o.data(ctrl_irq_tx_nhalf_c) <= ctrl.irq_tx_nhalf;
bus_rsp_o.data(ctrl_irq_idle_c) <= ctrl.irq_idle;
--
bus_rsp_o.data(ctrl_fifo_size3_c downto ctrl_fifo_size0_c) <= std_ulogic_vector(to_unsigned(index_size_f(IO_SPI_FIFO), 4));
--
Expand All @@ -206,7 +209,6 @@ begin
bus_rsp_o.data(7 downto 0) <= rx_fifo.rdata;
end if;
end if;

end if;
end if;
end process bus_access;
Expand Down Expand Up @@ -299,7 +301,8 @@ begin
irq_o <= ctrl.enable and (
(ctrl.irq_rx_avail and rx_fifo.avail) or -- IRQ if RX FIFO is not empty
(ctrl.irq_tx_empty and (not tx_fifo.avail)) or -- IRQ if TX FIFO is empty
(ctrl.irq_tx_nhalf and (not tx_fifo.half))); -- IRQ if TX buffer is not half full
(ctrl.irq_tx_nhalf and (not tx_fifo.half)) or -- IRQ if TX buffer is not half full
(ctrl.irq_idle and (not tx_fifo.avail) and (not rtx_engine.busy))); -- IRQ if TX FIFO is empty and serial engine is idle
end if;
end process irq_generator;

Expand Down
Loading