Skip to content

Commit 6ac9794

Browse files
committed
tlm-bridges: Add a UMI2TLM bridge
Signed-off-by: Edgar E. Iglesias <edgar@zeroasic.com>
1 parent df200f4 commit 6ac9794

File tree

1 file changed

+182
-0
lines changed

1 file changed

+182
-0
lines changed

tlm-bridges/umi2tlm-bridge.h

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
/*
2+
* UMI to TLM-2 bridge.
3+
*
4+
* Copyright (c) 2024 Zero ASIC.
5+
* Written by Edgar E. Iglesias.
6+
*
7+
* SPDX-License-Identifier: MIT
8+
*/
9+
10+
#ifndef UMI2TLM_BRIDGE_H__
11+
#define UMI2TLM_BRIDGE_H__
12+
#define SC_INCLUDE_DYNAMIC_PROCESSES
13+
14+
#include "tlm-extensions/genattr.h"
15+
#include "tlm-bridges/umi.h"
16+
17+
#undef D
18+
#define D(x)
19+
20+
template <unsigned int DATA_WIDTH>
21+
class umi2tlm_bridge
22+
: public sc_core::sc_module
23+
{
24+
public:
25+
tlm_utils::simple_initiator_socket<umi2tlm_bridge> socket;
26+
27+
SC_HAS_PROCESS(umi2tlm_bridge);
28+
29+
sc_in<bool> clk;
30+
sc_in<bool> rst;
31+
32+
UMI_RX_PORT(req, DATA_WIDTH);
33+
UMI_TX_PORT(resp, DATA_WIDTH);
34+
35+
umi2tlm_bridge(sc_core::sc_module_name name) :
36+
sc_module(name),
37+
socket("socket"),
38+
39+
clk("clk"),
40+
rst("rst"),
41+
42+
UMI_PORT_NAME(req),
43+
UMI_PORT_NAME(resp)
44+
{
45+
SC_THREAD(umi_thread);
46+
}
47+
48+
private:
49+
uint8_t data[1024];
50+
umi_fields f_tx;
51+
52+
void send_resp(uint64_t sa, uint64_t da) {
53+
resp_cmd.write(f_tx.pack());
54+
resp_srcaddr.write(sa);
55+
resp_dstaddr.write(da);
56+
57+
resp_valid.write(1);
58+
do {
59+
wait(clk.posedge_event());
60+
} while (!resp_ready.read());
61+
resp_valid.write(0);
62+
wait(clk.posedge_event());
63+
}
64+
65+
void umi_thread()
66+
{
67+
genattr_extension *genattr = new genattr_extension();
68+
tlm::tlm_generic_payload gp;
69+
sc_time delay(SC_ZERO_TIME);
70+
unsigned int pos;
71+
72+
gp.set_data_ptr(reinterpret_cast<unsigned char*>(data));
73+
gp.set_byte_enable_length(0);
74+
req_ready.write(1);
75+
76+
while (true) {
77+
tlm::tlm_command gp_cmd;
78+
uint64_t sa, da;
79+
uint32_t cmd;
80+
unsigned int nbytes;
81+
unsigned int tlen;
82+
umi_fields f;
83+
sc_bv<DATA_WIDTH> data_bv;
84+
unsigned int i;
85+
86+
wait(clk.posedge_event());
87+
if (!req_valid.read()) {
88+
continue;
89+
}
90+
91+
// Got a transaction.
92+
sa = req_srcaddr.read().to_uint64();
93+
da = req_dstaddr.read().to_uint64();
94+
cmd = req_cmd.read().to_uint64();
95+
96+
f.unpack(cmd);
97+
nbytes = (f.len + 1) << f.size;
98+
99+
D(printf("UMI2TLM: %s addr=%lx -> %lx cmd=%x opc=%d size=%d len=%d %dB\n",
100+
umi_opc_str(f.opc),
101+
sa, da, cmd, f.opc, f.size, f.len, nbytes));
102+
103+
genattr->set_master_id(sa);
104+
gp.set_extension(genattr);
105+
gp.set_address(da);
106+
switch (f.opc) {
107+
case UMI_REQ_READ: gp_cmd = tlm::TLM_READ_COMMAND; break;
108+
case UMI_REQ_POSTED: /* Fall through. */
109+
case UMI_REQ_WRITE: gp_cmd = tlm::TLM_WRITE_COMMAND; break;
110+
default: assert(0);
111+
};
112+
gp.set_command(gp_cmd);
113+
gp.set_data_length(nbytes);
114+
gp.set_streaming_width(nbytes);
115+
assert(nbytes <= sizeof data);
116+
117+
// Copy data.
118+
data_bv = req_data.read();
119+
if (gp_cmd == tlm::TLM_WRITE_COMMAND) {
120+
for (i = 0; i < nbytes; i++) {
121+
data[i] = data_bv.range(i * 8 + 8 - 1, i * 8).to_uint();
122+
}
123+
}
124+
socket->b_transport(gp, delay);
125+
126+
// back-pressure until we're done.
127+
req_ready.write(0);
128+
wait(clk.posedge_event());
129+
130+
// Response.
131+
if (gp_cmd == tlm::TLM_READ_COMMAND) {
132+
// Write response is needed.
133+
f_tx = f;
134+
f_tx.opc = UMI_RESP_READ;
135+
f_tx.size = 0;
136+
137+
/* Send multiple responses. */
138+
pos = 0;
139+
do {
140+
tlen = std::min(DATA_WIDTH/8, nbytes - pos);
141+
f_tx.len = tlen - 1;
142+
143+
for (i = 0; i < tlen; i++) {
144+
data_bv.range(i * 8 + 8 - 1, i * 8) = data[pos + i];
145+
}
146+
resp_data.write(data_bv);
147+
148+
f_tx.eof = 1;
149+
f_tx.eom = (pos + tlen) == nbytes;
150+
send_resp(da, sa);
151+
152+
D(printf("UMI: %s %lx -> %lx pos=%d nbytes=%d eom=%d\n",
153+
umi_opc_str(f_tx.opc),
154+
da, sa,
155+
pos, nbytes, f_tx.eom));
156+
157+
// Advance state.
158+
pos += tlen;
159+
sa += tlen;
160+
da += tlen;
161+
} while (pos < nbytes);
162+
} else {
163+
pos = nbytes;
164+
if (f.opc == UMI_REQ_POSTED) {
165+
// No ACK should be sent.
166+
} else {
167+
assert(f.opc == UMI_REQ_WRITE);
168+
169+
// Write response is needed.
170+
f_tx = f;
171+
f_tx.opc = UMI_RESP_WRITE;
172+
f_tx.eom = 1;
173+
send_resp(da, sa);
174+
// done
175+
}
176+
}
177+
req_ready.write(1);
178+
}
179+
}
180+
};
181+
#undef D
182+
#endif

0 commit comments

Comments
 (0)