Skip to content
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 | Ticket |
|:----:|:-------:|:--------|:------:|
| 24.03.2025 | 1.11.2.2 | TWD: add separate RX/TX FIFO configuration; add dummy response (if TX FIFO is empty); add optional no-ACK on read access if TX FIFO is empty | [#1210](https://github.com/stnolting/neorv32/pull/1210) |
| 21.03.2025 | 1.11.2.1 | :warning: remove clock gating option | [#1214](https://github.com/stnolting/neorv32/pull/1214) |
| 15.03.2025 | [**:rocket:1.11.2**](https://github.com/stnolting/neorv32/releases/tag/v1.11.2) | **New release** | |
| 14.03.2025 | 1.11.1.9 | :bug: fix broken shift instructions of `Zbb` ISA extension (when `Zbkc` and `CPU_FAST_SHIFT_EN` are both disabled) | [#1206](https://github.com/stnolting/neorv32/pull/1206) |
Expand Down
3 changes: 2 additions & 1 deletion docs/datasheet/soc.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,8 @@ The generic type "`suv(x:y)`" is an abbreviation for "`std_ulogic_vector(x downt
| `IO_TWI_EN` | boolean | false | Implement the <<_two_wire_serial_interface_controller_twi>>.
| `IO_TWI_FIFO` | natural | 1 | Depth of the <<_two_wire_serial_interface_controller_twi>> FIFO. Has to be a power of two, min 1, max 32768.
| `IO_TWD_EN` | boolean | false | Implement the <<_two_wire_serial_device_controller_twd>>.
| `IO_TWD_FIFO` | natural | 1 | Depth of the <<_two_wire_serial_device_controller_twd>> FIFO. Has to be a power of two, min 1, max 32768.
| `IO_TWD_RX_FIFO` | natural | 1 | Depth of the <<_two_wire_serial_device_controller_twd>> RX FIFO. Has to be a power of two, min 1, max 32768.
| `IO_TWD_TX_FIFO` | natural | 1 | Depth of the <<_two_wire_serial_device_controller_twd>> TX FIFO. Has to be a power of two, min 1, max 32768.
| `IO_PWM_NUM_CH` | natural | 0 | Number of channels of the <<_pulse_width_modulation_controller_pwm>> to implement (0..16).
| `IO_WDT_EN` | boolean | false | Implement the <<_watchdog_timer_wdt>>.
| `IO_TRNG_EN` | boolean | false | Implement the <<_true_random_number_generator_trng>>.
Expand Down
71 changes: 41 additions & 30 deletions docs/datasheet/soc_twd.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
| | `twd_scl_i` | 1-bit serial clock line sense input
| | `twd_scl_o` | 1-bit serial clock line output (pull low only)
| Configuration generics: | `IO_TWD_EN` | implement TWD controller when `true`
| | `IO_TWD_FIFO` | RX/TX FIFO depth, has to be a power of two, min 1
| | `IO_TWD_RX_FIFO` | RX FIFO depth, has to be a power of two, min 1
| | `IO_TWD_TX_FIFO` | TX FIFO depth, has to be a power of two, min 1
| CPU interrupts: | fast IRQ channel 0 | FIFO status interrupt (see <<_processor_interrupts>>)
|=======================

Expand All @@ -29,6 +30,7 @@ Key features:
* Programmable 7-bit device address
* Programmable interrupt conditions
* Configurable RX/TX data FIFO to "program" large TWD sequences without further involvement of the CPU
* Optional dummy TX byte which gets send to the bus if the TX FIFO is drained

.Device-Mode Only
[NOTE]
Expand All @@ -41,8 +43,9 @@ check out the <<_two_wire_serial_interface_controller_twi>>.

The TWD module provides two memory-mapped registers that are used for configuration & status check (`CTRL`) and
for accessing transmission data (`DATA`). The `DATA` register is transparently buffered by separate RX and TX FIFOs.
The size of those FIFOs can be configured by the `IO_TWD_FIFO` generic. Software can determine the FIFO size via the
control register's `TWD_CTRL_FIFO_*` bits.
The size of those FIFOs can be configured by the `IO_TWD_RX_FIFO` and `IO_TWD_TX_FIFO` generics. Software can determine
the FIFO size via the control register's `TWD_CTRL_FIFO_*` bits. The current status of the RX and TX FIFO can be polled
by software via the `TWD_CTRL_RX_*` and `TWD_CTRL_TX_*` flags.

The module is globally enabled by setting the control register's `TWD_CTRL_EN` bit. Clearing this bit will disable
and reset the entire module also clearing the internal RX and TX FIFOs. Each FIFO can also be cleared individually at
Expand All @@ -63,11 +66,14 @@ addresses are not supported.

Depending on the transaction type, data is either read from the RX FIFO and transferred to the host ("read operation")
or data is received from the host and written to the TX FIFO ("write operation"). Hence, data sequences can be
programmed to the TX FIFO to be fetched from the host. If the TX FIFO is empty and the host keeps performing read
transaction, the transferred data byte is automatically set to all-one.
programmed to the TX FIFO to be fetched from the host.

The current status of the RX and TX FIFO can be polled by software via the `TWD_CTRL_RX_*` and `TWD_CTRL_TX_*`
flags.
If the TX FIFO is empty or drained and the host keeps performing read transactions, one out of three behaviors can
be selected:

* send all-one to the bus (default)
* send the last byte that was taken from the TX FIFO to the bus if `TWD_CTRL_TX_DUMMY_EN` is set
* send nothing and respond with no ACK (i.e. the TWD "disappears" from the bus) if `TWD_CTRL_HIDE_READ` is set


**TWD Interrupt**
Expand Down Expand Up @@ -138,17 +144,20 @@ to idle state.

For a **write transaction** (upper timing diagram) the host can now transfer an arbitrary number of bytes (blue signals
`D7` to `D0`, MSB-first) to the TWD module. Each byte is acknowledged by the TWD by pulling SDA low during the 9th SCL
clock pules (**ACK**). Each received data byte is pushed to the internal RX FIFO. Data will be lost if the FIFO overflows.
clock pules (**ACK**), if moved into the FIFO. When the FIFO is full, the transfer gets not acknowledged (**NACK**).
Each received data byte is pushed to the internal RX FIFO. Data will be lost if the FIFO overflows.
The transaction is terminated when the host issues a **STOP** condition after the TWD has acknowledged the last data
transfer.

For a **read transaction** (lower timing diagram) the host keeps the SDA line at high state while sending the clock
pulse. The TWD will read a byte from the internal TX FIFO and will transmit it MSB-first to the host (blue signals `D7`
to `D0)`. During the 9th clock pulse the host has to acknowledged the transfer (**ACK**) by pulling SDA low. If no ACK
is received by the TWD no data is taken from the TX FIFO and the same byte can be transmitted in the next data phase.
If the TX FIFO becomes empty while the host keeps reading data, all-one bytes are transmitted. To terminate the
If the TX FIFO becomes empty while the host keeps reading data, all-one bytes are transmitted (if `TWD_CTRL_TX_DUMMY_EN = 0`)
or the last value taken from the TX FIFO (before it got empty is sent again (`TWD_CTRL_TX_DUMMY_EN = 1`). To terminate the
transmission the host hast so send a **NACK** after receiving the last data byte by keeping SDA high. After that, the
host has to issue a **STOP** condition.
host has to issue a **STOP** condition. If the `TWD_CTRL_HIDE_READ` bit is set, the access will not get acknowledged
at all if the TX FIFO is empty.

A **repeated-START** condition can be issued at any time (but after the complete transaction of a data byte and there
according ACK/NACK) bringing the TWD back to the start of the address/command transmission phase. The control register's
Expand Down Expand Up @@ -183,24 +192,26 @@ twd_scl_i <= std_ulogic(scl_io); -- sense
[options="header",grid="all"]
|=======================
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
.18+<| `0xffea0000` .18+<| `CTRL` <|`0` `TWD_CTRL_EN` ^| r/w <| TWD enable, reset if cleared
<|`1` `TWD_CTRL_CLR_RX` ^| -/w <| Clear RX FIFO, flag auto-clears
<|`2` `TWD_CTRL_CLR_TX` ^| -/w <| Clear TX FIFO, flag auto-clears
<|`3` `TWD_CTRL_FSEL` ^| r/w <| Bus sample clock / filter select
<|`10:4` `TWD_CTRL_DEV_ADDR6 : TWD_CTRL_DEV_ADDR0` ^| r/w <| Device address (7-bit)
<|`11` `TWD_CTRL_IRQ_RX_AVAIL` ^| r/w <| IRQ if RX FIFO data available
<|`12` `TWD_CTRL_IRQ_RX_FULL` ^| r/w <| IRQ if RX FIFO full
<|`13` `TWD_CTRL_IRQ_TX_EMPTY` ^| r/w <| IRQ if TX FIFO empty
<|`14:9` - ^| r/- <| _reserved_, read as zero
<|`18:15` `TWD_CTRL_FIFO_MSB : TWD_CTRL_FIFO_LSB` ^| r/- <| FIFO depth; log2(`IO_TWD_FIFO`)
<|`24:12` - ^| r/- <| _reserved_, read as zero
<|`25` `TWD_CTRL_RX_AVAIL` ^| r/- <| RX FIFO data available
<|`26` `TWD_CTRL_RX_FULL` ^| r/- <| RX FIFO full
<|`27` `TWD_CTRL_TX_EMPTY` ^| r/- <| TX FIFO empty
<|`28` `TWD_CTRL_TX_FULL` ^| r/- <| TX FIFO full
<|`29` `TWD_CTRL_SENSE_SCL` ^| r/- <| current state of the SCL bus line
<|`30` `TWD_CTRL_SENSE_SDA` ^| r/- <| current state of the SDA bus line
<|`31` `TWD_CTRL_BUSY` ^| r/- <| bus engine is busy (transaction in progress)
.2+<| `0xffea0004` .2+<| `DATA` <|`7:0` `TWD_DATA_MSB : TWD_DATA_LSB` ^| r/w <| RX/TX data FIFO access
<|`31:8` - ^| r/- <| _reserved_, read as zero
.20+<| `0xffea0000` .20+<| `CTRL` <|`0` `TWD_CTRL_EN` ^| r/w <| TWD enable, reset if cleared
<|`1` `TWD_CTRL_CLR_RX` ^| -/w <| Clear RX FIFO, flag auto-clears
<|`2` `TWD_CTRL_CLR_TX` ^| -/w <| Clear TX FIFO, flag auto-clears
<|`3` `TWD_CTRL_FSEL` ^| r/w <| Bus sample clock / filter select
<|`10:4` `TWD_CTRL_DEV_ADDR6 : TWD_CTRL_DEV_ADDR0` ^| r/w <| Device address (7-bit)
<|`11` `TWD_CTRL_IRQ_RX_AVAIL` ^| r/w <| IRQ if RX FIFO data available
<|`12` `TWD_CTRL_IRQ_RX_FULL` ^| r/w <| IRQ if RX FIFO full
<|`13` `TWD_CTRL_IRQ_TX_EMPTY` ^| r/w <| IRQ if TX FIFO empty
<|`14` `TWD_CTRL_TX_DUMMY_EN` ^| r/w <| enable sending tx_dummy (last sent byte) when fifo is empty
<|`15` `TWD_CTRL_HIDE_READ` ^| r/w <| Generate NACK ony READ-access when TX FIFO is empty
<|`19:16` `TWD_CTRL_RX_FIFO_MSB : TWD_CTRL_RX_FIFO_LSB` ^| r/- <| FIFO depth; log2(`IO_TWD_RX_FIFO`)
<|`23:20` `TWD_CTRL_TX_FIFO_MSB : TWD_CTRL_TX_FIFO_LSB` ^| r/- <| FIFO depth; log2(`IO_TWD_TX_FIFO`)
<|`24` - ^| r/- <| _reserved_, read as zero
<|`25` `TWD_CTRL_RX_AVAIL` ^| r/- <| RX FIFO data available
<|`26` `TWD_CTRL_RX_FULL` ^| r/- <| RX FIFO full
<|`27` `TWD_CTRL_TX_EMPTY` ^| r/- <| TX FIFO empty
<|`28` `TWD_CTRL_TX_FULL` ^| r/- <| TX FIFO full
<|`29` `TWD_CTRL_SENSE_SCL` ^| r/- <| current state of the SCL bus line
<|`30` `TWD_CTRL_SENSE_SDA` ^| r/- <| current state of the SDA bus line
<|`31` `TWD_CTRL_BUSY` ^| r/- <| bus engine is busy (transaction in progress)
.2+<| `0xffea0004` .2+<| `DATA` <|`7:0` `TWD_DATA_MSB : TWD_DATA_LSB` ^| r/w <| RX/TX data FIFO access
<|`31:8` - ^| r/- <| _reserved_, read as zero
|=======================
5 changes: 3 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"01110201"; -- hardware version
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01110202"; -- hardware version
constant archid_c : natural := 19; -- official RISC-V architecture ID
constant XLEN : natural := 32; -- native data path width

Expand Down Expand Up @@ -872,7 +872,8 @@ package neorv32_package is
IO_TWI_EN : boolean := false;
IO_TWI_FIFO : natural range 1 to 2**15 := 1;
IO_TWD_EN : boolean := false;
IO_TWD_FIFO : natural range 1 to 2**15 := 1;
IO_TWD_RX_FIFO : natural range 1 to 2**15 := 1;
IO_TWD_TX_FIFO : natural range 1 to 2**15 := 1;
IO_PWM_NUM_CH : natural range 0 to 16 := 0;
IO_WDT_EN : boolean := false;
IO_TRNG_EN : boolean := false;
Expand Down
6 changes: 4 additions & 2 deletions rtl/core/neorv32_top.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ entity neorv32_top is
IO_TWI_EN : boolean := false; -- implement two-wire interface (TWI)?
IO_TWI_FIFO : natural range 1 to 2**15 := 1; -- RTX FIFO depth, has to be zero or a power of two, min 1
IO_TWD_EN : boolean := false; -- implement two-wire device (TWD)?
IO_TWD_FIFO : natural range 1 to 2**15 := 1; -- RTX FIFO depth, has to be zero or a power of two, min 1
IO_TWD_RX_FIFO : natural range 1 to 2**15 := 1; -- TX FIFO depth, has to be zero or a power of two, min 1
IO_TWD_TX_FIFO : natural range 1 to 2**15 := 1; -- RX FIFO depth, has to be zero or a power of two, min 1
IO_PWM_NUM_CH : natural range 0 to 16 := 0; -- number of PWM channels to implement (0..16)
IO_WDT_EN : boolean := false; -- implement watch dog timer (WDT)?
IO_TRNG_EN : boolean := false; -- implement true random number generator (TRNG)?
Expand Down Expand Up @@ -1348,7 +1349,8 @@ begin
if IO_TWD_EN generate
neorv32_twd_inst: entity neorv32.neorv32_twd
generic map (
TWD_FIFO => IO_TWD_FIFO
TWD_RX_FIFO => IO_TWD_RX_FIFO,
TWD_TX_FIFO => IO_TWD_TX_FIFO
)
port map (
clk_i => clk_i,
Expand Down
Loading