Skip to content

Commit df200f4

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

File tree

1 file changed

+134
-0
lines changed

1 file changed

+134
-0
lines changed

tlm-bridges/tlm2umi-bridge.h

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/*
2+
* TLM-2 to UMI bridge.
3+
*
4+
* Copyright (c) 2023 Zero ASIC
5+
* Written by Edgar E. Iglesias.
6+
*
7+
* SPDX-License-Identifier: MIT
8+
*/
9+
10+
#ifndef TLM2UMI_BRIDGE_H__
11+
#define TLM2UMI_BRIDGE_H__
12+
#define SC_INCLUDE_DYNAMIC_PROCESSES
13+
14+
#include "tlm-extensions/genattr.h"
15+
#include "tlm-bridges/umi.h"
16+
#include "utils/bitops.h"
17+
18+
#undef D
19+
#define D(x)
20+
21+
template <unsigned int DATA_WIDTH>
22+
class tlm2umi_bridge
23+
: public sc_core::sc_module
24+
{
25+
public:
26+
tlm_utils::simple_target_socket<tlm2umi_bridge> socket;
27+
28+
SC_HAS_PROCESS(tlm2umi_bridge);
29+
30+
sc_in<bool> clk;
31+
sc_in<bool> rst;
32+
33+
UMI_TX_PORT(req, DATA_WIDTH);
34+
UMI_RX_PORT(resp, DATA_WIDTH);
35+
36+
tlm2umi_bridge(sc_core::sc_module_name name) :
37+
sc_module(name),
38+
socket("socket"),
39+
clk("clk"),
40+
rst("rst"),
41+
UMI_PORT_NAME(req),
42+
UMI_PORT_NAME(resp)
43+
{
44+
socket.register_b_transport(this, &tlm2umi_bridge::b_transport);
45+
}
46+
47+
private:
48+
sc_mutex m_mutex;
49+
50+
virtual void b_transport(tlm::tlm_generic_payload& trans,
51+
sc_time& delay)
52+
{
53+
unsigned int len = trans.get_data_length();
54+
uint64_t addr = trans.get_address();
55+
uint8_t *buf = trans.get_data_ptr();
56+
genattr_extension *genattr;
57+
sc_bv<DATA_WIDTH> data = 0;
58+
unsigned int pos = 0;
59+
uint64_t srcaddr = 0;
60+
bool is_write = !trans.is_read();
61+
62+
trans.get_extension(genattr);
63+
if (genattr) {
64+
srcaddr = genattr->get_master_id();
65+
}
66+
67+
D(printf("TLM2UMI: we=%d addr=%lx len=%d\n", !trans.is_read(), addr, len));
68+
// Since we're going to do waits in order to wiggle the
69+
// UMI signals, we need to eliminate the accumulated
70+
// TLM delay.
71+
wait(delay);
72+
delay = SC_ZERO_TIME;
73+
wait(clk.posedge_event());
74+
resp_ready.write(1);
75+
76+
m_mutex.lock();
77+
do {
78+
unsigned int tlen = std::min(DATA_WIDTH/8, len - pos);
79+
umi_fields f;
80+
uint32_t cmd;
81+
82+
if (is_write) {
83+
sc_bv<DATA_WIDTH> tmp;
84+
sc_buf2bv(buf+pos, tmp, tlen * 8);
85+
data = tmp;
86+
}
87+
88+
f.size = 0;
89+
f.len = 0;
90+
switch (tlen) {
91+
case 2: f.size = 1; break;
92+
case 4: f.size = 2; break;
93+
case 8: f.size = 3; break;
94+
case 16: f.size = 4; break;
95+
case 32: f.size = 5; break;
96+
case 64: f.size = 6; break;
97+
case 128: f.size = 7; break;
98+
default: f.len = tlen - 1;
99+
};
100+
101+
f.opc = trans.is_read() ? UMI_REQ_READ : UMI_REQ_WRITE;
102+
f.eof = 1;
103+
cmd = f.pack();
104+
105+
req_cmd.write(cmd);
106+
req_srcaddr.write(srcaddr + pos);
107+
req_dstaddr.write(addr + pos);
108+
req_data.write(data);
109+
req_valid.write(1);
110+
resp_ready.write(1);
111+
112+
do {
113+
wait(clk.posedge_event());
114+
} while(!req_ready.read());
115+
req_valid.write(0);
116+
117+
do {
118+
wait(clk.posedge_event());
119+
} while(!resp_valid.read());
120+
121+
if (!is_write) {
122+
sc_bv2buf(buf + pos, resp_data.read(), tlen * 8);
123+
}
124+
pos += tlen;
125+
} while (pos < len);
126+
resp_ready.write(0);
127+
wait(clk.posedge_event());
128+
129+
trans.set_response_status(tlm::TLM_OK_RESPONSE);
130+
m_mutex.unlock();
131+
}
132+
};
133+
#undef D
134+
#endif

0 commit comments

Comments
 (0)