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
4 changes: 2 additions & 2 deletions docs/doc-src/ip-blocks/apb_event_cntrl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ Each input event is allocated an ID. The below table shows the mapping of the ev
+-------------------------------------+----------------------------+------------+--------------------------------------+
| | per_events_i[18] | 18 | Always 0 in current implementation |
+-------------------------------------+----------------------------+------------+--------------------------------------+
| | per_events_i[19] | 19 | Always 0 in current implementation |
| uDMA I2C 0's status event | per_events_i[19] | 19 | BUSY or arbitration-lost event |
+-------------------------------------+----------------------------+------------+--------------------------------------+
| uDMA Core's rx_lin_events_o[5] | per_events_i[20] | 20 | RX channel event for I2C Master 1 |
| | | | generated by uDMA Core |
Expand All @@ -133,7 +133,7 @@ Each input event is allocated an ID. The below table shows the mapping of the ev
+-------------------------------------+----------------------------+------------+--------------------------------------+
| | per_events_i[22] | 22 | Always 0 in current implementation |
+-------------------------------------+----------------------------+------------+--------------------------------------+
| | per_events_i[23] | 23 | Always 0 in current implementation |
| uDMA I2C 1's status event | per_events_i[23] | 23 | BUSY or arbitration-lost event |
+-------------------------------------+----------------------------+------------+--------------------------------------+
| uDMA Core's rx_lin_events_o[6] | per_events_i[24] | 24 | RX channel event for uDMA SDIO |
| | | | generated by uDMA Core |
Expand Down
33 changes: 20 additions & 13 deletions docs/doc-src/ip-blocks/udma_i2cm.rst
Original file line number Diff line number Diff line change
Expand Up @@ -454,15 +454,17 @@ STATUS
- Offset: 0x20
- Type : Volatile

+------------+-------+------+------------+-------------------------------------------------------------+
| Field | Bits | Type | Default | Description |
+============+=======+======+============+=============================================================+
| AL | 1:1 | RO | 0x0 | Always returns 0 |
+------------+-------+------+------------+-------------------------------------------------------------+
| BUSY | 0:0 | RO | 0x0 | Always returns 0 |
+------------+-------+------+------------+-------------------------------------------------------------+

**NOTE:** No functionality is implemented in RTL and always returns 0x0.
+------------+-------+------+------------+------------------------------------------------------------------------------------------+
| Field | Bits | Type | Default | Description |
+============+=======+======+============+==========================================================================================+
| AL | 1:1 | RO | 0x0 | Sticky arbitration-lost indication. Set when arbitration loss is detected. |
+------------+-------+------+------------+------------------------------------------------------------------------------------------+
| BUSY | 0:0 | RO | 0x0 | Sticky bus-start indication. Set when BUSY changes from 0 to 1 after a START condition. |
+------------+-------+------+------------+------------------------------------------------------------------------------------------+

Reading STATUS returns and clears both bits. A condition detected in the same cycle as the
read remains set, so software cannot lose a new status indication. BUSY records the rising
edge of the internal bus-busy state; it is not the current level of that state.

SETUP
~~~~~
Expand Down Expand Up @@ -610,8 +612,13 @@ uDMA core triggers these events based on specific conditions. The I2C will only

- ``ext_events_i [3:0]``: Input external events.

uDMA I2C interface to generate error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- err_o
uDMA I2C status event interface
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ``err_o``: One ``sys_clk_i`` cycle pulse when BUSY or AL becomes set. The legacy signal
name is retained for interface compatibility, although a normal START condition can
generate the event through BUSY. Read STATUS to determine the cause.

``**Note**:: As of commit #30e3c8b, the err_o signal is left unconnected.``
For I2C 0 and I2C 1, ``err_o`` is routed to peripheral event IDs 19 and 23 respectively.
These event IDs were previously reserved. Existing RX and TX event IDs are unchanged, and
all event-controller masks reset to 1 (masked). Software must explicitly unmask the new
event ID before it can reach an event-controller destination.
2 changes: 1 addition & 1 deletion rtl/core-v-mcu/udma_subsystem/udma_subsystem.sv
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,7 @@ module udma_subsystem #(
assign s_events[4*(PER_ID_I2C+g_i2c)+0] = s_rx_ch_events[CH_ID_RX_I2C+g_i2c];
assign s_events[4*(PER_ID_I2C+g_i2c)+1] = s_tx_ch_events[CH_ID_TX_I2C+g_i2c];
assign s_events[4*(PER_ID_I2C+g_i2c)+2] = 1'b0;
assign s_events[4*(PER_ID_I2C+g_i2c)+3] = 1'b0;
assign s_events[4*(PER_ID_I2C+g_i2c)+3] = s_i2c_evt[g_i2c];

assign s_rx_cfg_stream[CH_ID_RX_I2C+g_i2c] = 'h0;
assign s_rx_cfg_stream_id[CH_ID_RX_I2C+g_i2c] = 'h0;
Expand Down
4 changes: 4 additions & 0 deletions rtl/udma/udma_i2c/rtl/udma_i2c_control.sv
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ module udma_i2c_control

input logic sw_rst_i,

output logic busy_o,
output logic al_o,
output logic err_o,

// I2C signals
Expand Down Expand Up @@ -145,6 +147,8 @@ module udma_i2c_control
assign s_busy_rise = ~r_busy & s_busy;
assign s_al_rise = ~r_al & s_al;

assign busy_o = s_busy_rise;
assign al_o = s_al_rise;
assign err_o = s_busy_rise | s_al_rise;

assign s_do_rst = sw_rst_i;
Expand Down
14 changes: 7 additions & 7 deletions rtl/udma/udma_i2c/rtl/udma_i2c_reg_if.sv
Original file line number Diff line number Diff line change
Expand Up @@ -176,13 +176,13 @@ module udma_i2c_reg_if #(
r_busy <= 0;
r_al <= 0;
end
else
begin
if (status_busy_i)
r_busy <= 1'b1;
if (status_al_i)
r_al <= 1'b1;
end

// A new condition must not be lost when STATUS is read in the
// same cycle. Set therefore has priority over clear-on-read.
if (status_busy_i)
r_busy <= 1'b1;
if (status_al_i)
r_al <= 1'b1;
end
end //always

Expand Down
56 changes: 56 additions & 0 deletions rtl/udma/udma_i2c/rtl/udma_i2c_status_ep.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright 2026 Shivam Tiwari
// Solderpad Hardware License, Version 2.1, see LICENSE.md for details.
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1

// The I2C controller generates one-cycle BUSY-rise, arbitration-lost, and
// combined status-event pulses in the periph_clk_i domain. The register
// interface and err_o consume those pulses in the asynchronous sys_clk_i
// domain. This module uses acknowledged edge propagators so short source
// pulses are transferred safely without being missed. BUSY and AL remain
// separate for the STATUS fields, while event_i preserves the legacy
// combined-event behavior when both causes occur together.
module udma_i2c_status_ep (
input logic periph_clk_i,
input logic sys_clk_i,
input logic rstn_i,

input logic busy_i,
input logic al_i,
input logic event_i,

output logic busy_o,
output logic al_o,
output logic event_o
);

// The source pulses can be shorter than a sys_clk_i period. The
// acknowledged edge propagators hold each pulse until it is observed in
// the system-clock domain.
edge_propagator i_busy_sync (
.clk_tx_i (periph_clk_i),
.rstn_tx_i (rstn_i),
.edge_i (busy_i),
.clk_rx_i (sys_clk_i),
.rstn_rx_i (rstn_i),
.edge_o (busy_o)
);

edge_propagator i_al_sync (
.clk_tx_i (periph_clk_i),
.rstn_tx_i (rstn_i),
.edge_i (al_i),
.clk_rx_i (sys_clk_i),
.rstn_rx_i (rstn_i),
.edge_o (al_o)
);

edge_propagator i_event_sync (
.clk_tx_i (periph_clk_i),
.rstn_tx_i (rstn_i),
.edge_i (event_i),
.clk_rx_i (sys_clk_i),
.rstn_rx_i (rstn_i),
.edge_o (event_o)
);

endmodule
26 changes: 23 additions & 3 deletions rtl/udma/udma_i2c/rtl/udma_i2c_top.sv
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,27 @@ module udma_i2c_top #(

logic s_do_rst;

logic s_i2c_busy_periph;
logic s_i2c_al_periph;
logic s_i2c_event_periph;
logic s_i2c_busy_sys;
logic s_i2c_al_sys;

assign data_tx_datasize_o = 2'b00;
assign data_rx_datasize_o = 2'b00;

udma_i2c_status_ep i_status_ep (
.periph_clk_i ( periph_clk_i ),
.sys_clk_i ( sys_clk_i ),
.rstn_i ( rstn_i ),
.busy_i ( s_i2c_busy_periph ),
.al_i ( s_i2c_al_periph ),
.event_i ( s_i2c_event_periph ),
.busy_o ( s_i2c_busy_sys ),
.al_o ( s_i2c_al_sys ),
.event_o ( err_o )
);

udma_i2c_reg_if #(
.L2_AWIDTH_NOAL(L2_AWIDTH_NOAL),
.TRANS_SIZE(TRANS_SIZE)
Expand Down Expand Up @@ -125,8 +143,8 @@ module udma_i2c_top #(

.cfg_do_rst_o ( s_do_rst ),

.status_busy_i ( 1'b0 ),
.status_al_i ( 1'b0 )
.status_busy_i ( s_i2c_busy_sys ),
.status_al_i ( s_i2c_al_sys )
);

io_tx_fifo #(
Expand Down Expand Up @@ -192,7 +210,9 @@ module udma_i2c_top #(

.sw_rst_i ( s_do_rst ),

.err_o ( ),
.busy_o ( s_i2c_busy_periph ),
.al_o ( s_i2c_al_periph ),
.err_o ( s_i2c_event_periph ),

.scl_i ( scl_i ),
.scl_o ( scl_o ),
Expand Down
1 change: 1 addition & 0 deletions rtl/udma/udma_i2c/src_files.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ udma_i2c:
rtl/udma_i2c_reg_if.sv,
rtl/udma_i2c_bus_ctrl.sv,
rtl/udma_i2c_control.sv,
rtl/udma_i2c_status_ep.sv,
rtl/udma_i2c_top.sv,
]

21 changes: 21 additions & 0 deletions rtl/udma/udma_i2c/tb/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# uDMA I2C status tests

The focused tests for the uDMA I2C status path use Icarus Verilog through
FuseSoC. From the repository root, register this checkout once and run both
targets:

```sh
fusesoc library add core-v-mcu .
fusesoc run --target=control-status-test openhwgroup.org:ip:udma_i2c
fusesoc run --target=status-test openhwgroup.org:ip:udma_i2c
```

`control-status-test` generates I2C START and STOP conditions on a resolved
open-drain bus. It checks the BUSY rising-edge event, verifies that a normal
STOP produces no event, and creates an unexpected STOP during an active command
to check the arbitration-lost event.

`status-test` uses asynchronous system and peripheral clocks. It checks pulse
transfer, the composite event, sticky BUSY and arbitration-lost STATUS bits,
clear-on-read behavior, and set priority when a condition and STATUS read occur
in the same cycle.
Loading