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 } 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:
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
171
177 biflow_socket(sc_core::sc_module_name name)
178 : sc_core::sc_module(name)
179 , input_socket((std::string(name) + "_input_socket").c_str())
180 , output_socket((std::string(name) + "_output_socket").c_str())
181 , input_control_socket((std::string(name) + "_input_socket_control").c_str())
182 , output_control_socket((std::string(name) + "_output_socket_control").c_str())
183 , m_txn(nullptr)
184 {
185 SCP_TRACE(()) << "constructor";
186
187 SC_METHOD(sendall);
188 sensitive << m_send_event;
190 output_control_socket.register_b_transport(this, &biflow_socket::initiator_ctrl);
191 m_send_event.async_detach_suspending();
192 }
193
194 tlm::tlm_target_socket<DEFAULT_TLM_BUSWIDTH>& get_input_socket() { return input_socket; }
195 tlm::tlm_initiator_socket<DEFAULT_TLM_BUSWIDTH>& get_output_socket() { return output_socket; };
196 tlm::tlm_initiator_socket<DEFAULT_TLM_BUSWIDTH>& get_input_control_socket() { return input_control_socket; };
197 tlm::tlm_target_socket<DEFAULT_TLM_BUSWIDTH>& get_output_control_socket() { return output_control_socket; };
205 {
206 SCP_TRACE(())("Binding {} to {}", name(), other.name());
207 m_bound = true;
208 other.new_bind(*this);
209 output_socket.bind(other.get_input_socket());
210 input_control_socket.bind(other.get_output_control_socket());
211 other.get_output_socket().bind(input_socket);
212 other.get_input_control_socket().bind(output_control_socket);
213 other.bind_done();
214 }
215
216 /* target socket handlng */
217
227 void register_b_transport(MODULE* mod, void (MODULE::*cb)(tlm::tlm_generic_payload&, sc_core::sc_time&))
228 {
229 input_socket.register_b_transport(mod, cb);
230 }
231
238 {
239 ctrl c;
240 c.cmd = ctrl::DELTA_CHANGE;
241 c.can_send = i;
242 send_ctrl(c);
243 }
254 {
255 ctrl c;
256 c.cmd = ctrl::ABSOLUTE_VALUE;
257 c.can_send = i;
258 send_ctrl(c);
259 }
265 {
266 ctrl c;
267 c.cmd = ctrl::INFINITE;
268 send_ctrl(c);
269 }
270
277 void enqueue(T data)
278 {
279 SCP_TRACE(())("Sending {}", data);
280 std::lock_guard<std::mutex> guard(m_mutex);
281 m_queue.push_back(data);
282 m_send_event.notify();
283 }
284
290 void set_default_txn(tlm::tlm_generic_payload& txn)
291 {
292 if (!m_txn) m_txn = std::make_unique<tlm::tlm_generic_payload>();
293 m_txn->deep_copy_from(txn);
294 }
295
301 void force_send(tlm::tlm_generic_payload& txn)
302 {
303 sc_core::sc_time delay;
304 output_socket->b_transport(txn, delay);
305 }
306
312 void reset()
313 {
314 std::lock_guard<std::mutex> guard(m_mutex);
315 m_queue.clear();
316 }
317};
318
319/*
320 * @class biflow_router_socket
321 * Connect any number of biflow sockets together, routing data from any of them to all the others.
322 * The router can always accept data (can_receive_any) since it will, itself,
323 * pass the data onto another biflow socket, which will handle the control flow.
324 */
325
326template <class T = uint8_t>
327class biflow_router_socket : public sc_core::sc_module, public biflow_multibindable
328{
329 SCP_LOGGER();
330
331 /* Capture the socket ID by using a class */
332 class remote : public sc_core::sc_object
333 {
334 sc_core::sc_vector<remote>& m_remotes;
335 SCP_LOGGER();
336
337 public:
339 remote* m_sendto = nullptr;
340
341 void route_data(tlm::tlm_generic_payload& txn, sc_core::sc_time& t)
342 {
343 T* ptr = (T*)txn.get_data_ptr();
344 bool sent = false;
345 for (auto& remote : m_remotes) {
346 if (&remote != this && (!m_sendto || m_sendto == &remote)) {
347 sent = true;
348 remote.socket.set_default_txn(txn);
349 for (int i = 0; i < txn.get_data_length(); i++) {
350 T data;
351 memcpy(&data, &(ptr[i]), sizeof(T));
352 remote.socket.enqueue(data);
353 }
354 }
355 }
356 if (!sent) {
357 SCP_WARN(())("Should have been sent - sendto {}", m_sendto->name());
358 }
359 }
360
361 remote(sc_core::sc_module_name name, sc_core::sc_vector<struct remote>& r): socket(name), m_remotes(r)
362 {
363 socket.register_b_transport(this, &remote::route_data);
364 }
365
366 void set_sendto(remote* s) { m_sendto = s; }
367 };
368
369 sc_core::sc_vector<remote> m_remotes;
370
371 biflow_socket<remote, T>* binding = nullptr;
372
373 cci::cci_param<std::string> p_sendto;
374 remote* m_sendto = nullptr;
375
376 void sendto_setup(biflow_bindable& other, remote& remote)
377 {
378 if (!p_sendto.get_value().empty()) {
379 if (m_sendto) {
380 SCP_WARN(())("{} sendto {}", remote.name(), m_sendto->name());
381 remote.set_sendto(m_sendto);
382 } else if (std::string(other.name()).find(p_sendto) == 0) {
383 m_sendto = &remote;
384 SCP_WARN(())("found sendto {}", m_sendto->name());
385 for (auto& r : m_remotes) {
386 if (&remote != &r) {
387 SCP_WARN(())("{} sendto {}", r.name(), m_sendto->name());
388 r.set_sendto(m_sendto);
389 }
390 }
391 } else {
392 SCP_WARN(())("{} is not sendto {}", other.name(), p_sendto.get_value());
393 }
394 }
395 }
396
397public:
398 void new_bind(biflow_bindable& other)
399 {
400 m_remotes.emplace_back(m_remotes);
401 auto& remote = m_remotes[m_remotes.size() - 1];
402 binding = &(remote.socket);
403 binding->new_bind(other);
404 sendto_setup(other, remote);
405 }
406 void bind_done(void)
407 {
408 sc_assert(binding != nullptr);
409 binding->bind_done();
410 binding->can_receive_any();
411 binding = nullptr;
412 }
413
414 void bind(biflow_bindable& other)
415 {
416 SCP_TRACE(())("Biflow Router {} binding to {}", name(), other.name());
417 m_remotes.emplace_back(m_remotes);
418
419 auto& remote = m_remotes[m_remotes.size() - 1];
420 binding = &(remote.socket);
421
422 binding->bind(other); // This will call new_bind etc...
423 binding->can_receive_any();
424 binding = nullptr;
425
426 sendto_setup(other, remote);
427 }
428
429 tlm::tlm_target_socket<DEFAULT_TLM_BUSWIDTH>& get_input_socket()
430 {
431 sc_assert(binding != nullptr);
432 return binding->get_input_socket();
433 }
434 tlm::tlm_initiator_socket<DEFAULT_TLM_BUSWIDTH>& get_output_socket()
435 {
436 sc_assert(binding != nullptr);
437 return binding->get_output_socket();
438 };
439 tlm::tlm_initiator_socket<DEFAULT_TLM_BUSWIDTH>& get_input_control_socket()
440 {
441 sc_assert(binding != nullptr);
442 return binding->get_input_control_socket();
443 };
444 tlm::tlm_target_socket<DEFAULT_TLM_BUSWIDTH>& get_output_control_socket()
445 {
446 sc_assert(binding != nullptr);
447 return binding->get_output_control_socket();
448 };
449
455 struct ctrl {
456 enum { DELTA_CHANGE, ABSOLUTE_VALUE, INFINITE } cmd;
457 uint32_t can_send;
458 };
459 biflow_router_socket(sc_core::sc_module_name name, std::string sendto = "")
460 : sc_core::sc_module(name)
461 , m_remotes("remote_sockets")
462 , p_sendto("sendto", sendto, "Router all sent data to this port")
463 {
464 SCP_TRACE(()) << "constructor";
465 }
466
467 const char* name() { return sc_module::name(); }
468};
469
470template <class MODULE, class T = uint8_t>
471class biflow_socket_multi : public sc_core::sc_module, public biflow_bindable
472{
473 SCP_LOGGER();
474 biflow_socket<MODULE, T> main_socket;
476
477public:
478 tlm::tlm_target_socket<DEFAULT_TLM_BUSWIDTH>& get_input_socket() { return router.get_input_socket(); }
479 tlm::tlm_initiator_socket<DEFAULT_TLM_BUSWIDTH>& get_output_socket() { return router.get_output_socket(); }
480 tlm::tlm_initiator_socket<DEFAULT_TLM_BUSWIDTH>& get_input_control_socket()
481 {
482 return router.get_input_control_socket();
483 }
484 tlm::tlm_target_socket<DEFAULT_TLM_BUSWIDTH>& get_output_control_socket()
485 {
486 return router.get_output_control_socket();
487 }
488 void new_bind(biflow_bindable& other) { router.new_bind(other); }
489 void bind_done() { router.bind_done(); }
490 void bind(biflow_bindable& other) { router.bind(other); }
491
492 void register_b_transport(MODULE* mod, void (MODULE::*cb)(tlm::tlm_generic_payload&, sc_core::sc_time&))
493 {
494 main_socket.register_b_transport(mod, cb);
495 }
496 void can_receive_more(int i) { main_socket.can_receive_more(i); }
497 void can_receive_set(int i) { main_socket.can_receive_set(i); }
498 void can_receive_any() { main_socket.can_receive_any(); }
499
500 void enqueue(T data) { main_socket.enqueue(data); }
501
502 void set_default_txn(tlm::tlm_generic_payload& txn) { main_socket.set_default_txn(txn); }
503
504 void force_send(tlm::tlm_generic_payload& txn) { main_socket.force_send(txn); }
505
506 void reset() { main_socket.reset(); }
507
508 biflow_socket_multi(sc_core::sc_module_name name)
509 : sc_core::sc_module(name)
510 , main_socket((std::string(name) + "_main").c_str())
511 , router((std::string(name) + "_router").c_str(), main_socket.name())
512 {
513 router.bind(main_socket);
514 }
515
516 const char* name() { return sc_module::name(); }
517};
518
519} // namespace gs
520
521#endif
Definition target.h:160
Definition async_event.h:22
Definition biflow-socket.h:328
Definition biflow-socket.h:472
Definition biflow-socket.h:73
void bind(biflow_bindable &other)
Bind method to connect two biflow sockets.
Definition biflow-socket.h:204
void can_receive_any()
can_receive_any Allow unlimited items to arrive.
Definition biflow-socket.h:264
void set_default_txn(tlm::tlm_generic_payload &txn)
set_default_txn set transaction parameters (command, address and data_length)
Definition biflow-socket.h:290
biflow_socket(sc_core::sc_module_name name)
Construct a new biflow socket object.
Definition biflow-socket.h:177
void enqueue(T data)
enqueue Enqueue data to be sent (unlimited queue size) NOTE: Thread safe.
Definition biflow-socket.h:277
void force_send(tlm::tlm_generic_payload &txn)
force_send force send a transaction
Definition biflow-socket.h:301
void can_receive_set(int i)
can_receive_set
Definition biflow-socket.h:253
void reset()
reset Clear the current send queue. NOTE: Thread safe.
Definition biflow-socket.h:312
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:227
void can_receive_more(int i)
can_receive_more
Definition biflow-socket.h:237
Definition router.h:43
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:455