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
2 changes: 2 additions & 0 deletions umi/sumi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from .umi_pipeline.umi_pipeline import Pipeline
from .umi_ram.umi_ram import RAM
from .umi_regif.umi_regif import Regif
from .umi_stream.umi_stream import Stream
from .umi_switch.umi_switch import Switch
from .umi_tester.umi_tester import Tester
from .umi_unpack.umi_unpack import Unpack
Expand All @@ -34,6 +35,7 @@
'Pipeline',
'RAM',
'Regif',
'Stream',
'Switch',
'Tester',
'Unpack',
Expand Down
3 changes: 3 additions & 0 deletions umi/sumi/include/umi_messages.vh
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
localparam UMI_OPCODE_LSB = 0;
localparam UMI_OPCODE_MSB = 4;

localparam UMI_OPTIONS_LSB = 5;
localparam UMI_OPTIONS_MSB = 31;

localparam UMI_SIZE_LSB = 5;
localparam UMI_SIZE_MSB = 7;

Expand Down
294 changes: 294 additions & 0 deletions umi/sumi/umi_stream/rtl/umi_stream.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,294 @@
/*******************************************************************************
* Copyright 2026 Zero ASIC Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************
*
* This module converts between UMI memory mapped transactions and streaming
* transactions dynamically via the devicemode signal
*
* When configured as a device, posted writes go through a fifo unmodified
* from the umi domain to the streaming domain. Write requests have acks
* sent back immediately, ie the write to the fifo indicates completion.
* Read requests pull data from the fifo whenever not empty.
*
* When configure as a non-device full duplex channel, only posted writes
* are allowed.
*
******************************************************************************/

module umi_stream
#(parameter AW = 64, // UMI data width
parameter CW = 32, // UMI command width
parameter DW = 256, // UMI data width
parameter S2MM_DEPTH = 4, // S2MM FIFO depth
parameter MM2S_DEPTH = 4 // MM2S FIFO depth
)
(// operating mode
input devicemode, // 1 = device endpoint, 0=full duplex link
// S2MM addresses (from external controller)
input [AW-1:0] s2mm_dstaddr,
input [AW-1:0] s2mm_srcaddr,
input [CW-1:0] s2mm_cmd,
// UMI memory mapped interface
input umi_nreset,
input umi_clk,
input umi_in_valid,
input [CW-1:0] umi_in_cmd,
input [AW-1:0] umi_in_dstaddr,
Comment thread
RiceShelley marked this conversation as resolved.
input [AW-1:0] umi_in_srcaddr,
input [DW-1:0] umi_in_data,
output umi_in_ready,
output umi_out_valid,
output [CW-1:0] umi_out_cmd,
output [AW-1:0] umi_out_dstaddr,
output [AW-1:0] umi_out_srcaddr,
output [DW-1:0] umi_out_data,
input umi_out_ready,
// USI streaming interface
input usi_clk,
input usi_nreset,
output usi_out_valid,
output usi_out_last,
output [DW-1:0] usi_out_data,
input usi_out_ready,
input usi_in_valid,
input usi_in_last,
input [DW-1:0] usi_in_data,
output usi_in_ready
);

`include "umi_messages.vh"

// M2SS signals
wire mm2s_fifo_full;
wire mm2s_fifo_almost_full;
wire mm2s_fifo_empty;
wire mm2s_fifo_write;
wire mm2s_fifo_read;
wire [DW:0] mm2s_fifo_din;
wire [DW:0] mm2s_fifo_dout;

// S2MM signals
wire s2mm_fifo_full;
wire s2mm_fifo_almost_full;
wire s2mm_fifo_empty;
wire s2mm_fifo_write;
wire s2mm_fifo_read;
wire [DW:0] s2mm_fifo_din;
wire [DW:0] s2mm_fifo_dout;

// Command decode signals (direct decode from umi_in_cmd)
wire cmd_read;
wire cmd_write;
wire cmd_write_posted;

// Transaction control signals
wire umi_resp;
wire request_stall;
wire resp_vld_out;

// Response packet signals
wire [CW-1:0] resp_cmd;

// Response pipeline registers (following umi_endpoint pattern)
reg resp_vld_r;
reg resp_vld_keep;
reg [CW-1:0] resp_cmd_r;
reg [AW-1:0] resp_dstaddr_r;
reg [AW-1:0] resp_srcaddr_r;
reg [DW-1:0] resp_data_r;
reg [DW-1:0] resp_data_keep;
wire [DW-1:0] resp_data_out;

//###################################################
// UMI Command Decode (direct decode using umi_messages.vh)
//###################################################

assign cmd_read = (umi_in_cmd[4:0] == UMI_REQ_READ);
Comment thread
aolofsson marked this conversation as resolved.
assign cmd_write = (umi_in_cmd[4:0] == UMI_REQ_WRITE);
assign cmd_write_posted = (umi_in_cmd[4:0] == UMI_REQ_POSTED);

//###################################################
// UMI Transaction Decode
//###################################################

// Stall when there's a pending response and consumer not ready
assign resp_vld_out = resp_vld_r | resp_vld_keep;
assign request_stall = resp_vld_out & ~umi_out_ready;

// Ready to accept new UMI transactions (device mode only for response-generating ops)
// Posted writes: only needs FIFO not full (works in both modes)
// Write with ack: need FIFO not full AND no stall (device mode only)
// Read: need s2mm not empty AND no stall (device mode only)
assign umi_in_ready = (cmd_write_posted & ~mm2s_fifo_full) |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ready being combinationaly dependent on UMI CMD feels like an extension of the spec rule ready shall not be combinationaly dependent on valid. I think an easy fix would be have a buffer on UMI input and ready is driven high when the buffer is empty.

umi/README.md

Line 462 in e57520f

5. However, it is legal for the READY assertion to be dependent on the VALID assertion (as long as this dependence is not combinational).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added issue, will fix in next PR

(cmd_write & devicemode & ~mm2s_fifo_full & ~request_stall) |
(cmd_read & devicemode & ~s2mm_fifo_empty & ~request_stall);

// Transaction accepted that generates a response (device mode only)
// Write with ack (cmd_write) generates response, posted write does NOT
// Read generates response
assign umi_resp = umi_in_valid & umi_in_ready & devicemode &
(cmd_write | cmd_read);

//###################################################
// MM2S FIFO Write Control
//###################################################

// Write to mm2s fifo on any write transaction (posted or with ack)
assign mm2s_fifo_write = umi_in_valid & umi_in_ready &
(cmd_write | cmd_write_posted);

assign mm2s_fifo_din[DW-1:0] = umi_in_data[DW-1:0];

assign mm2s_fifo_din[DW] = umi_in_cmd[UMI_EOM_BIT];

//###################################################
// S2MM FIFO Read Control (for read responses)
//###################################################

// In device mode: read when servicing a read request
// In non-device mode, auto drain when umi_out is ready
assign s2mm_fifo_read = devicemode ? (umi_in_valid & umi_in_ready & cmd_read):
(~s2mm_fifo_empty & umi_out_ready);

//###################################################
// Response Generation
//###################################################

assign resp_cmd[31:0] = {umi_in_cmd[31:5],
cmd_read ? UMI_RESP_READ : UMI_RESP_WRITE};

// Response valid register
always @(posedge umi_clk or negedge umi_nreset)
if (!umi_nreset)
resp_vld_r <= 1'b0;
else
resp_vld_r <= umi_resp;

// Response (capture when response is generated)
always @(posedge umi_clk or negedge umi_nreset)
if (!umi_nreset)
begin
resp_cmd_r[CW-1:0] <= {CW{1'b0}};
resp_dstaddr_r[AW-1:0] <= {AW{1'b0}};
resp_srcaddr_r[AW-1:0] <= {AW{1'b0}};
end
else if (umi_resp)
begin
resp_cmd_r[CW-1:0] <= resp_cmd[CW-1:0];
resp_dstaddr_r[AW-1:0] <= umi_in_srcaddr[AW-1:0];
resp_srcaddr_r[AW-1:0] <= {AW{1'b0}};
Comment thread
aolofsson marked this conversation as resolved.
end

// Data storage in case ready is low
always @(posedge umi_clk or negedge umi_nreset)
if (!umi_nreset)
resp_data_keep[DW-1:0] <= {DW{1'b0}};
else if (resp_vld_r)
resp_data_keep[DW-1:0] <= resp_data_r[DW-1:0];

// Response data register (for reads, capture from s2mm fifo)
always @(posedge umi_clk or negedge umi_nreset)
if (!umi_nreset)
resp_data_r[DW-1:0] <= {DW{1'b0}};
else if (umi_resp)
resp_data_r[DW-1:0] <= cmd_read ? s2mm_fifo_dout[DW-1:0] :
Comment thread
RiceShelley marked this conversation as resolved.
{DW{1'b0}};

// Valid keep - holds response when consumer not ready
always @(posedge umi_clk or negedge umi_nreset)
if (!umi_nreset)
resp_vld_keep <= 1'b0;
else if (resp_vld_r & ~umi_out_ready)
resp_vld_keep <= 1'b1;
else if (umi_out_ready)
resp_vld_keep <= 1'b0;

// Output data mux
assign resp_data_out[DW-1:0] = resp_vld_r ? resp_data_r[DW-1:0] :
resp_data_keep[DW-1:0];

//###################################################
// UMI Output Mux
//###################################################

assign umi_out_valid = devicemode ? resp_vld_out : ~s2mm_fifo_empty;
assign umi_out_cmd = devicemode ? resp_cmd_r : s2mm_cmd;
assign umi_out_dstaddr = devicemode ? resp_dstaddr_r : s2mm_dstaddr;
assign umi_out_srcaddr = devicemode ? resp_srcaddr_r : s2mm_srcaddr;
assign umi_out_data = devicemode ? resp_data_out : s2mm_fifo_dout[DW-1:0];

//###################################################
// Memory Mapped to Stream (MM2S)
//###################################################

assign mm2s_fifo_read = ~mm2s_fifo_empty & usi_out_ready;
assign usi_out_valid = ~mm2s_fifo_empty;
assign usi_out_data = mm2s_fifo_dout[DW-1:0];
assign usi_out_last = mm2s_fifo_dout[DW];

la_asyncfifo #(.DW(DW+1),
.DEPTH(MM2S_DEPTH))
ififo_mm2s (// write side
.wr_clk (umi_clk),
.wr_nreset (umi_nreset),
.wr_full (mm2s_fifo_full),
.wr_almost_full (mm2s_fifo_almost_full),
.wr_din (mm2s_fifo_din[DW:0]),
.wr_en (mm2s_fifo_write),
.wr_chaosmode (1'b0),
// read side
.rd_clk (usi_clk),
.rd_nreset (usi_nreset),
.rd_dout (mm2s_fifo_dout[DW:0]),
.rd_empty (mm2s_fifo_empty),
.rd_en (mm2s_fifo_read),
// misc
.vss (1'b0),
.vdd (1'b1),
.ctrl (1'b0),
.test (1'b0));

//######################################################
// Stream to Memory Mapped (S2MM)
//######################################################

assign s2mm_fifo_write = usi_in_valid & ~s2mm_fifo_full;
assign s2mm_fifo_din[DW-1:0] = usi_in_data[DW-1:0];
assign s2mm_fifo_din[DW] = usi_in_last;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

usi_in_last is clocked into ififo_s2mm but never used on the umi_clk side of the fifo. The umi_out_cmd is driven only by s2mm_cmd when device mode is 0. I would expect that the syncronized usi_in_last would replace the EOM or EOF bit given by s2mm_cmd.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added issue, will fix in next PR.

assign usi_in_ready = ~s2mm_fifo_full;

la_asyncfifo #(.DW(DW+1),
.DEPTH(S2MM_DEPTH))
ififo_s2mm (// write side (stream domain)
.wr_clk (usi_clk),
.wr_nreset (usi_nreset),
.wr_full (s2mm_fifo_full),
.wr_almost_full (s2mm_fifo_almost_full),
.wr_din (s2mm_fifo_din[DW:0]),
.wr_en (s2mm_fifo_write),
.wr_chaosmode (1'b0),
// read side (umi domain)
.rd_clk (umi_clk),
.rd_nreset (umi_nreset),
.rd_dout (s2mm_fifo_dout[DW:0]),
.rd_empty (s2mm_fifo_empty),
.rd_en (s2mm_fifo_read),
// misc
.vss (1'b0),
.vdd (1'b1),
.ctrl (1'b0),
.test (1'b0));

endmodule
Loading
Loading