quic/qbox
Loading...
Searching...
No Matches
biflow-socket.h
1/*
2 * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
35#ifndef GS_BIFLOW_SOCKET_H
36#define GS_BIFLOW_SOCKET_H
37#include <systemc>
38#include <cci_configuration>
39#include <scp/report.h>
40#include <tlm>
41#include <tlm_utils/simple_target_socket.h>
42#include <tlm_utils/simple_initiator_socket.h>
43#include <tlm_sockets_buswidth.h>
44#include <async_event.h>
45#include <memory>
46
47namespace gs {
48
49/*
50 * Binding is asymmetrical in nature, one side called bind, the other side is 'bound to' using the get_....
51 * interfaces. The result is a symmetrical complete bind.
52 * To control the binding process, before the get_... interfaces are called, and sockets bound, new_bind must be called,
53 * and on completion bind_done must be called.
54 */
56 virtual void bind(biflow_bindable& other) = 0;
57
58 virtual void new_bind(biflow_bindable& other) = 0;
59
60 virtual tlm::tlm_target_socket<DEFAULT_TLM_BUSWIDTH>& get_input_socket() = 0;
61 virtual tlm::tlm_initiator_socket<DEFAULT_TLM_BUSWIDTH>& get_output_socket() = 0;
62 virtual tlm::tlm_initiator_socket<DEFAULT_TLM_BUSWIDTH>& get_input_control_socket() = 0;
63 virtual tlm::tlm_target_socket<DEFAULT_TLM_BUSWIDTH>& get_output_control_socket() = 0;
64 virtual void bind_done(void) = 0;
65
66 virtual const char* name(void) = 0;
67};
70
71template <class MODULE, class T = uint8_t>
72class biflow_socket : public sc_core::sc_module, public biflow_bindable
73{
74 SCP_LOGGER();
75
76 uint32_t m_can_send = 0;
77 bool m_infinite = false;
78 std::vector<T> m_queue;
79 gs::async_event m_send_event;
80 std::mutex m_mutex;
81 std::unique_ptr<tlm::tlm_generic_payload> m_txn;
82
83 struct ctrl {
84 enum { DELTA_CHANGE, ABSOLUTE_VALUE, INFINITE_VALUE } cmd;
85 uint32_t can_send;
86 };
87
88 void sendall()
89 {
90 std::lock_guard<std::mutex> guard(m_mutex);
91 tlm::tlm_generic_payload txn;
92
93 uint64_t sending = (m_infinite || (m_can_send > m_queue.size())) ? m_queue.size() : m_can_send;
94 if (sending > 0) {
95 if (m_txn)
96 txn.deep_copy_from(*m_txn);
97 else
98 txn.set_data_length(sending);
99 txn.set_streaming_width(sending);
100 txn.set_data_ptr(&(m_queue[0]));
101 sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
102 output_socket->b_transport(txn, delay);
103 m_queue.erase(m_queue.begin(), m_queue.begin() + sending);
104 m_can_send -= sending;
105 }
106 }
107 void initiator_ctrl(tlm::tlm_generic_payload& txn, sc_core::sc_time& t)
108 {
109 std::lock_guard<std::mutex> guard(m_mutex);
110 sc_assert(txn.get_data_length() == sizeof(ctrl));
111 ctrl* c = (ctrl*)(txn.get_data_ptr());
112 switch (c->cmd) {
113 case ctrl::ABSOLUTE_VALUE:
114 m_can_send = c->can_send;
115 m_infinite = false;
116 SCP_TRACE(())("Can send {}", m_can_send);
117 // If the other side signals a specific number, then it must be waiting on interrupts
118 // etc to drive this, so lets interpret that as a 'signal' that we should keep the
119 // suspending flag. If this is set to 0, then the other side stopped listening
120 if (m_can_send)
121 m_send_event.async_attach_suspending();
122 else
123 m_send_event.async_detach_suspending();
124 break;
125 case ctrl::DELTA_CHANGE:
126 sc_assert(m_infinite == false);
127 m_can_send += c->can_send;
128 m_infinite = false;
129 SCP_TRACE(())("Can send {}", m_can_send);
130 break;
131 case ctrl::INFINITE_VALUE:
132 m_infinite = true;
133 SCP_TRACE(())("Can send any");
134 break;
135 default:
136 SCP_FATAL(())("Unkown command");
137 }
138 m_send_event.notify(sc_core::SC_ZERO_TIME);
139 }
140 void send_ctrl(ctrl& c)
141 {
142 tlm::tlm_generic_payload txn;
143 txn.set_data_length(sizeof(ctrl));
144 txn.set_data_ptr(((uint8_t*)&c));
145 txn.set_command(tlm::TLM_IGNORE_COMMAND);
146 sc_core::sc_time t;
147 input_control_socket->b_transport(txn, t);
148 }
149
150 bool m_bound = false;
151
152public:
153 void new_bind(biflow_bindable& other)
154 {
155 if (m_bound) SCP_ERR(())("Socket already bound, may only be bound once");
156 }
157 void bind_done(void)
158 {
159 if (m_bound) SCP_ERR(())("Socket already bound, may only be bound once");
160 m_bound = true;
161 }
162
163 const char* name() { return sc_module::name(); }
164
165 tlm_utils::simple_target_socket<MODULE, DEFAULT_TLM_BUSWIDTH> input_socket;
166 tlm_utils::simple_initiator_socket<biflow_socket, DEFAULT_TLM_BUSWIDTH> input_control_socket;
167
168 tlm_utils::simple_initiator_socket<biflow_socket, DEFAULT_TLM_BUSWIDTH> output_socket;
169 tlm_utils::simple_target_socket<biflow_socket, DEFAULT_TLM_BUSWIDTH> output_control_socket;
170
176 biflow_socket(sc_core::sc_module_name name)
177 : sc_core::sc_module(name)
178 , input_socket((std::string(name) + "_input_socket").c_str())
179 , output_socket((std::string(name) + "_output_socket").c_str())
180 , input_control_socket((std::string(name) + "_input_socket_control").c_str())
181 , output_control_socket((std::string(name) + "_output_socket_control").c_str())
182 , m_txn(nullptr)
183 {
184 SCP_TRACE(()) << "constructor";
185
186 SC_METHOD(sendall);
187 sensitive << m_send_event;
189 output_control_socket.register_b_transport(this, &biflow_socket::initiator_ctrl);
190 m_send_event.async_detach_suspending();
191 }
192
193 tlm::tlm_target_socket<DEFAULT_TLM_BUSWIDTH>& get_input_socket() { return input_socket; }
194 tlm::tlm_initiator_socket<DEFAULT_TLM_BUSWIDTH>& get_output_socket() { return output_socket; };
195 tlm::tlm_initiator_socket<DEFAULT_TLM_BUSWIDTH>& get_input_control_socket() { return input_control_socket; };
196 tlm::tlm_target_socket<DEFAULT_TLM_BUSWIDTH>& get_output_control_socket() { return output_control_socket; };
204 {
205 SCP_TRACE(())("Binding {} to {}", name(), other.name());
206 m_bound = true;
207 other.new_bind(*this);
208 output_socket.bind(other.get_input_socket());
209 input_control_socket.bind(other.get_output_control_socket());
210 other.get_output_socket().bind(input_socket);
211 other.get_input_control_socket().bind(output_control_socket);
212 other.bind_done();
213 }
214
215 /* target socket handlng */
216
226 void register_b_transport(MODULE* mod, void (MODULE::*cb)(tlm::tlm_generic_payload&, sc_core::sc_time&))
227 {
228 input_socket.register_b_transport(mod, cb);
229 }
230
237 {
238 ctrl c;
239 c.cmd = ctrl::DELTA_CHANGE;
240 c.can_send = i;
241 send_ctrl(c);
242 }
253 {
254 ctrl c;
255 c.cmd = ctrl::ABSOLUTE_VALUE;
256 c.can_send = i;
257 send_ctrl(c);
258 }
264 {
265 ctrl c;
266 c.cmd = ctrl::INFINITE_VALUE;
267 send_ctrl(c);
268 }
269
276 void enqueue(T data)
277 {
278 SCP_TRACE(())("Sending {}", data);
279 std::lock_guard<std::mutex> guard(m_mutex);
280 m_queue.push_back(data);
281 m_send_event.notify();
282 }
283
289 void set_default_txn(tlm::tlm_generic_payload& txn)
290 {
291 if (!m_txn) m_txn = std::make_unique<tlm::tlm_generic_payload>();
292 m_txn->deep_copy_from(txn);
293 }
294
300 void force_send(tlm::tlm_generic_payload& txn)
301 {
302 sc_core::sc_time delay;
303 output_socket->b_transport(txn, delay);
304 }
305
311 void reset()
312 {
313 std::lock_guard<std::mutex> guard(m_mutex);
314 m_queue.clear();
315 }
316};
317
318/*
319 * @class biflow_router_socket
320 * Connect any number of biflow sockets together, routing data from any of them to all the others.
321 * The router can always accept data (can_receive_any) since it will, itself,
322 * pass the data onto another biflow socket, which will handle the control flow.
323 */
324
325template <class T = uint8_t>
326class biflow_router_socket : public sc_core::sc_module, public biflow_multibindable
327{
328 SCP_LOGGER();
329
330 /* Capture the socket ID by using a class */
331 class remote : public sc_core::sc_object
332 {
333 sc_core::sc_vector<remote>& m_remotes;
334 SCP_LOGGER();
335
336 public:
338 remote* m_sendto = nullptr;
339
340 void route_data(tlm::tlm_generic_payload& txn, sc_core::sc_time& t)
341 {
342 T* ptr = (T*)txn.get_data_ptr();
343 bool sent = false;
344 for (auto& remote : m_remotes) {
345 if (&remote != this && (!m_sendto || m_sendto == &remote)) {
346 sent = true;
347 remote.socket.set_default_txn(txn);
348 for (int i = 0; i < txn.get_data_length(); i++) {
349 T data;
350 memcpy(&data, &(ptr[i]), sizeof(T));
351 remote.socket.enqueue(data);
352 }
353 }
354 }
355 if (!sent) {
356 SCP_WARN(())("Should have been sent - sendto {}", m_sendto->name());
357 }
358 }
359
360 remote(sc_core::sc_module_name name, sc_core::sc_vector<struct remote>& r): socket(name), m_remotes(r)
361 {
362 socket.register_b_transport(this, &remote::route_data);
363 }
364
365 void set_sendto(remote* s) { m_sendto = s; }
366 };
367
368 sc_core::sc_vector<remote> m_remotes;
369
370 biflow_socket<remote, T>* binding = nullptr;
371
372 cci::cci_param<std::string> p_sendto;
373 remote* m_sendto = nullptr;
374
375 void sendto_setup(biflow_bindable& other, remote& remote)
376 {
377 if (!p_sendto.get_value().empty()) {
378 if (m_sendto) {
379 SCP_WARN(())("{} sendto {}", remote.name(), m_sendto->name());
380 remote.set_sendto(m_sendto);
381 } else if (std::string(other.name()).find(p_sendto) == 0) {
382 m_sendto = &remote;
383 SCP_WARN(())("found sendto {}", m_sendto->name());
384 for (auto& r : m_remotes) {
385 if (&remote != &r) {
386 SCP_WARN(())("{} sendto {}", r.name(), m_sendto->name());
387 r.set_sendto(m_sendto);
388 }
389 }
390 } else {
391 SCP_WARN(())("{} is not sendto {}", other.name(), p_sendto.get_value());
392 }
393 }
394 }
395
396public:
397 void new_bind(biflow_bindable& other)
398 {
399 m_remotes.emplace_back(m_remotes);
400 auto& remote = m_remotes[m_remotes.size() - 1];
401 binding = &(remote.socket);
402 binding->new_bind(other);
403 sendto_setup(other, remote);
404 }
405 void bind_done(void)
406 {
407 sc_assert(binding != nullptr);
408 binding->bind_done();
409 binding->can_receive_any();
410 binding = nullptr;
411 }
412
413 void bind(biflow_bindable& other)
414 {
415 SCP_TRACE(())("Biflow Router {} binding to {}", name(), other.name());
416 m_remotes.emplace_back(m_remotes);
417
418 auto& remote = m_remotes[m_remotes.size() - 1];
419 binding = &(remote.socket);
420
421 binding->bind(other); // This will call new_bind etc...
422 binding->can_receive_any();
423 binding = nullptr;
424
425 sendto_setup(other, remote);
426 }
427
428 tlm::tlm_target_socket<DEFAULT_TLM_BUSWIDTH>& get_input_socket()
429 {
430 sc_assert(binding != nullptr);
431 return binding->get_input_socket();
432 }
433 tlm::tlm_initiator_socket<DEFAULT_TLM_BUSWIDTH>& get_output_socket()
434 {
435 sc_assert(binding != nullptr);
436 return binding->get_output_socket();
437 };
438 tlm::tlm_initiator_socket<DEFAULT_TLM_BUSWIDTH>& get_input_control_socket()
439 {
440 sc_assert(binding != nullptr);
441 return binding->get_input_control_socket();
442 };
443 tlm::tlm_target_socket<DEFAULT_TLM_BUSWIDTH>& get_output_control_socket()
444 {
445 sc_assert(binding != nullptr);
446 return binding->get_output_control_socket();
447 };
448
454 struct ctrl {
455 enum { DELTA_CHANGE, ABSOLUTE_VALUE, INFINITE_VALUE } cmd;
456 uint32_t can_send;
457 };
458 biflow_router_socket(sc_core::sc_module_name name, std::string sendto = "")
459 : sc_core::sc_module(name)
460 , m_remotes("remote_sockets")
461 , p_sendto("sendto", sendto, "Router all sent data to this port")
462 {
463 SCP_TRACE(()) << "constructor";
464 }
465
466 const char* name() { return sc_module::name(); }
467};
468
469template <class MODULE, class T = uint8_t>
470class biflow_socket_multi : public sc_core::sc_module, public biflow_bindable
471{
472 SCP_LOGGER();
473 biflow_socket<MODULE, T> main_socket;
475
476public:
477 tlm::tlm_target_socket<DEFAULT_TLM_BUSWIDTH>& get_input_socket() { return router.get_input_socket(); }
478 tlm::tlm_initiator_socket<DEFAULT_TLM_BUSWIDTH>& get_output_socket() { return router.get_output_socket(); }
479 tlm::tlm_initiator_socket<DEFAULT_TLM_BUSWIDTH>& get_input_control_socket()
480 {
481 return router.get_input_control_socket();
482 }
483 tlm::tlm_target_socket<DEFAULT_TLM_BUSWIDTH>& get_output_control_socket()
484 {
485 return router.get_output_control_socket();
486 }
487 void new_bind(biflow_bindable& other) { router.new_bind(other); }
488 void bind_done() { router.bind_done(); }
489 void bind(biflow_bindable& other) { router.bind(other); }
490
491 void register_b_transport(MODULE* mod, void (MODULE::*cb)(tlm::tlm_generic_payload&, sc_core::sc_time&))
492 {
493 main_socket.register_b_transport(mod, cb);
494 }
495 void can_receive_more(int i) { main_socket.can_receive_more(i); }
496 void can_receive_set(int i) { main_socket.can_receive_set(i); }
497 void can_receive_any() { main_socket.can_receive_any(); }
498
499 void enqueue(T data) { main_socket.enqueue(data); }
500
501 void set_default_txn(tlm::tlm_generic_payload& txn) { main_socket.set_default_txn(txn); }
502
503 void force_send(tlm::tlm_generic_payload& txn) { main_socket.force_send(txn); }
504
505 void reset() { main_socket.reset(); }
506
507 biflow_socket_multi(sc_core::sc_module_name name)
508 : sc_core::sc_module(name)
509 , main_socket((std::string(name) + "_main").c_str())
510 , router((std::string(name) + "_router").c_str(), main_socket.name())
511 {
512 router.bind(main_socket);
513 }
514
515 const char* name() { return sc_module::name(); }
516};
517
518} // namespace gs
519
520#endif
Definition target.h:160
Definition async_event.h:22
Definition biflow-socket.h:327
Definition biflow-socket.h:471
Definition biflow-socket.h:73
void bind(biflow_bindable &other)
Bind method to connect two biflow sockets.
Definition biflow-socket.h:203
void can_receive_any()
can_receive_any Allow unlimited items to arrive.
Definition biflow-socket.h:263
void set_default_txn(tlm::tlm_generic_payload &txn)
set_default_txn set transaction parameters (command, address and data_length)
Definition biflow-socket.h:289
biflow_socket(sc_core::sc_module_name name)
Construct a new biflow socket object.
Definition biflow-socket.h:176
void enqueue(T data)
enqueue Enqueue data to be sent (unlimited queue size) NOTE: Thread safe.
Definition biflow-socket.h:276
void force_send(tlm::tlm_generic_payload &txn)
force_send force send a transaction
Definition biflow-socket.h:300
void can_receive_set(int i)
can_receive_set
Definition biflow-socket.h:252
void reset()
reset Clear the current send queue. NOTE: Thread safe.
Definition biflow-socket.h:311
void register_b_transport(MODULE *mod, void(MODULE::*cb)(tlm::tlm_generic_payload &, sc_core::sc_time &))
Register b_transport to be called whenever data is received from the socket.
Definition biflow-socket.h:226
void can_receive_more(int i)
can_receive_more
Definition biflow-socket.h:236
A SystemC TLM router module for transaction routing based on address.
Definition router.h:114
Tool which reads a Lua configuration file and sets parameters.
Definition biflow.cc:10
Definition biflow-socket.h:55
Definition biflow-socket.h:68
Construct a new biflow socket object.
Definition biflow-socket.h:454