scc 2025.09
SystemC components library
dmi_mgr.h
1/*
2 * dmi_mgr.h
3 *
4 * Created on: Jun 22, 2025
5 * Author: eyck
6 */
7
8#ifndef SCC_SRC_COMPONENTS_SCC_DMI_MGR_H_
9#define SCC_SRC_COMPONENTS_SCC_DMI_MGR_H_
10
11#include <scc/report.h>
12#include <scv-tr/scv_tr.h>
13#include <sysc/communication/sc_port.h>
14#include <tlm>
15#include <tlm_core/tlm_2/tlm_2_interfaces/tlm_dmi.h>
16#include <tlm_utils/tlm_quantumkeeper.h>
17#include <util/range_lut.h>
18
19namespace tlm {
20inline bool operator==(tlm_dmi const& o1, tlm_dmi const& o2) {
21 return o1.get_granted_access() == o2.get_granted_access() && o1.get_start_address() == o2.get_start_address() &&
22 o1.get_end_address() == o2.get_end_address();
23}
24inline bool operator!=(tlm_dmi const& o1, tlm_dmi const& o2) { return !operator==(o1, o2); }
25} // namespace tlm
26
27namespace scc {
36enum dmi_status { ERROR = 0, OK = 1, DMI_RD = 2, DMI_WR = 4, DMI_ALL = 6 };
37inline dmi_status operator|=(dmi_status s1, dmi_status s2) { return static_cast<dmi_status>(s1 | s2); }
48template <typename TYPES = tlm::tlm_base_protocol_types> struct dmi_mgr : public sc_core::sc_object {
55 cci::cci_param<bool> disable_dmi{"disable_dmi", false};
62 cci::cci_param<sc_core::sc_time> clk_period{"clk_period", sc_core::SC_ZERO_TIME};
69
70 dmi_mgr(std::string const& name, sc_core::sc_port_b<tlm::tlm_fw_transport_if<TYPES>>& fw_if)
71 : sc_core::sc_object(name.c_str())
72 , fw_if(fw_if) {}
73
76 virtual ~dmi_mgr() = default;
86 dmi_status read(uint64_t addr, unsigned length, uint8_t* const data) {
87 auto lut_entry = read_lut.getEntry(addr);
88 if(lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && addr + length <= lut_entry.get_end_address() + 1) {
89 auto offset = addr - lut_entry.get_start_address();
90 std::copy(lut_entry.get_dmi_ptr() + offset, lut_entry.get_dmi_ptr() + offset + length, data);
91 bus_clk_sycles += lut_entry.get_read_latency() / clk_period.get_value();
92 return DMI_RD;
93 } else {
94 tlm::tlm_generic_payload gp;
95 gp.set_command(tlm::TLM_READ_COMMAND);
96 gp.set_address(addr);
97 gp.set_data_ptr(data);
98 gp.set_data_length(length);
99 gp.set_streaming_width(length);
100 sc_core::sc_time delay = quantum_keeper.get_local_time();
101 auto pre_delay = delay;
102 fw_if->b_transport(gp, delay);
103 if(pre_delay > delay) {
104 quantum_keeper.reset();
105 } else {
106 auto incr = (delay - quantum_keeper.get_local_time()) / clk_period.get_value();
107 bus_clk_sycles += incr;
108 }
109 SCCTRACE(this->name()) << "[local time: " << delay << "]: finish read(0x" << std::hex << addr << ") : 0x"
110 << (length == 4 ? *(uint32_t*)data
111 : length == 2 ? *(uint16_t*)data
112 : (unsigned)*data);
113 if(gp.get_response_status() != tlm::TLM_OK_RESPONSE) {
114 return ERROR;
115 }
116 if(gp.is_dmi_allowed() && !disable_dmi.get_value()) {
117 gp.set_command(tlm::TLM_READ_COMMAND);
118 gp.set_address(addr);
119 tlm::tlm_dmi dmi_data;
120 if(fw_if->get_direct_mem_ptr(gp, dmi_data)) {
121 dmi_status res = ERROR;
122 if(dmi_data.is_read_allowed()) {
123 read_lut.addEntry(dmi_data, dmi_data.get_start_address(),
124 dmi_data.get_end_address() - dmi_data.get_start_address() + 1);
125 res |= DMI_RD;
126 }
127 if(dmi_data.is_write_allowed()) {
128 write_lut.addEntry(dmi_data, dmi_data.get_start_address(),
129 dmi_data.get_end_address() - dmi_data.get_start_address() + 1);
130 res |= DMI_WR;
131 }
132 return res;
133 }
134 }
135 return OK;
136 }
137 }
138
147 dmi_status write(uint64_t addr, unsigned length, const uint8_t* const data) {
148 auto lut_entry = write_lut.getEntry(addr);
149 if(lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && addr + length <= lut_entry.get_end_address() + 1) {
150 auto offset = addr - lut_entry.get_start_address();
151 std::copy(data, data + length, lut_entry.get_dmi_ptr() + offset);
152 bus_clk_sycles += lut_entry.get_write_latency() / clk_period.get_value();
153 return DMI_WR;
154 } else {
155 write_buf.resize(length);
156 std::copy(data, data + length, write_buf.begin()); // need to copy as TLM does not guarantee data integrity
157 tlm::tlm_generic_payload gp;
158 gp.set_command(tlm::TLM_WRITE_COMMAND);
159 gp.set_address(addr);
160 gp.set_data_ptr(write_buf.data());
161 gp.set_data_length(length);
162 gp.set_streaming_width(length);
163 sc_core::sc_time delay = quantum_keeper.get_local_time();
164 auto pre_delay = delay;
165 fw_if->b_transport(gp, delay);
166 if(pre_delay > delay)
167 quantum_keeper.reset();
168 else
169 bus_clk_sycles += (delay - quantum_keeper.get_local_time()) / clk_period.get_value();
170 SCCTRACE() << "[local time: " << delay << "]: finish write(0x" << std::hex << addr << ") : 0x"
171 << (length == 4 ? *(uint32_t*)data
172 : length == 2 ? *(uint16_t*)data
173 : (unsigned)*data);
174 if(gp.get_response_status() != tlm::TLM_OK_RESPONSE) {
175 return ERROR;
176 }
177 if(gp.is_dmi_allowed() && !disable_dmi.get_value()) {
178 gp.set_command(tlm::TLM_WRITE_COMMAND);
179 gp.set_address(addr);
180 tlm::tlm_dmi dmi_data;
181 if(fw_if->get_direct_mem_ptr(gp, dmi_data)) {
182 dmi_status res = ERROR;
183 if(dmi_data.is_write_allowed()) {
184 write_lut.addEntry(dmi_data, dmi_data.get_start_address(),
185 dmi_data.get_end_address() - dmi_data.get_start_address() + 1);
186 res |= DMI_WR;
187 }
188 if(dmi_data.is_read_allowed()) {
189 read_lut.addEntry(dmi_data, dmi_data.get_start_address(),
190 dmi_data.get_end_address() - dmi_data.get_start_address() + 1);
191 res |= DMI_RD;
192 }
193 return res;
194 }
195 }
196 return OK;
197 }
198 }
199
200private:
201 sc_core::sc_port_b<tlm::tlm_fw_transport_if<TYPES>>& fw_if;
202 util::range_lut<tlm::tlm_dmi> read_lut{tlm::tlm_dmi{}}, write_lut{tlm::tlm_dmi{}};
203 std::vector<uint8_t> write_buf;
204 tlm_utils::tlm_quantumkeeper quantum_keeper;
205 uint64_t bus_clk_sycles{0};
206};
207
208} /* namespace scc */
209
210#endif /* SCC_SRC_COMPONENTS_SCC_DMI_MGR_H_ */
range based lookup table
Definition range_lut.h:37
SCC TLM utilities.
dmi_status
The dmi_status enum represents the status of DMI transactions.
Definition dmi_mgr.h:36
SystemC TLM.
Definition dmi_mgr.h:19
dmi_status read(uint64_t addr, unsigned length, uint8_t *const data)
Performs a read operation on the DMI interface.
Definition dmi_mgr.h:86
dmi_status write(uint64_t addr, unsigned length, const uint8_t *const data)
Performs a write operation on the DMI interface.
Definition dmi_mgr.h:147
cci::cci_param< sc_core::sc_time > clk_period
A CCI parameter to specify the clock period for delay calculations.
Definition dmi_mgr.h:62
dmi_mgr(std::string const &name, sc_core::sc_port_b< tlm::tlm_fw_transport_if< TYPES > > &fw_if)
Constructor for the dmi_mgr class.
Definition dmi_mgr.h:70
cci::cci_param< bool > disable_dmi
A CCI parameter to disable DMI transactions.
Definition dmi_mgr.h:55
virtual ~dmi_mgr()=default
Virtual destructor for the dmi_mgr class.