The Sparta Modeling Framework
Loading...
Searching...
No Matches
Bus.hpp
Go to the documentation of this file.
1// <Bus> -*- C++ -*-
2
3
10#pragma once
11
12#include <sstream>
13#include <algorithm>
14
16#include "sparta/ports/Port.hpp"
18
19namespace sparta
20{
45 class Bus : public sparta::TreeNode
46 {
47 void populatePortMap_(PortSet::RegisteredPortMap & port_map,
48 const PortSet::RegisteredPortMap & src_ports,
49 const std::string & strip_str) const
50 {
51 for(auto & rpi : src_ports)
52 {
53 // Remove beginning/trailing in/out
54 std::string stripped_port_name =
55 sparta::utils::strip_string_pattern(strip_str + "_", rpi.first);
56
57 stripped_port_name =
58 sparta::utils::strip_string_pattern("_" + strip_str, stripped_port_name);
59
60 // Remove underscores
61 stripped_port_name.erase(std::remove(stripped_port_name.begin(),
62 stripped_port_name.end(), '_'),
63 stripped_port_name.end());
64 const auto & it = port_map.find(stripped_port_name);
65 sparta_assert(it == port_map.end(),
66 "Error: Cannot discern between port name " << rpi.first
67 << " and " << it->second->getName());
68 port_map.emplace(std::make_pair(stripped_port_name, rpi.second));
69 }
70 }
71
72 void checkBinding_(const PortSet::RegisteredPortMap & port_map1,
73 const PortSet::RegisteredPortMap & port_map2,
74 std::string & unbound_ports) const
75 {
76 // First check to make sure that we can COMPLETELY bind
77 // the buses
78 for(auto & pm1_pt : port_map1) {
79 const auto & pm2_pt = port_map2.find(pm1_pt.first);
80 if(pm2_pt == port_map2.end()) {
81 unbound_ports += pm1_pt.second->getLocation() + ", ";
82 }
83 }
84 for(auto & pm2_pt : port_map2) {
85 const auto & pm1_pt = port_map1.find(pm2_pt.first);
86 if(pm1_pt == port_map1.end()) {
87 unbound_ports += pm2_pt.second->getLocation() + ", ";
88 }
89 }
90 }
91
92 void bindPorts_(const PortSet::RegisteredPortMap & port_map1,
93 const PortSet::RegisteredPortMap & port_map2) const
94 {
95 // It will be a complete bind, go for it
96 for(auto & pm1_pt : port_map1)
97 {
98 const auto & pm2_pt = port_map2.find(pm1_pt.first);
99 sparta_assert(pm2_pt != port_map2.end());
100 // Bi-directional
101 sparta::bind(pm1_pt.second, pm2_pt->second);
102 }
103 }
104
105 // Internal port set
106 sparta::PortSet port_set_;
107 bool precedence_set_ = false;
108
109 public:
116 Bus(TreeNode * parent,
117 const std::string & name,
118 const std::string& group = GROUP_NAME_NONE,
119 group_idx_type group_idx = GROUP_IDX_NONE,
120 const std::string & desc = "");
121
127 return port_set_;
128 }
129
135 void registerPort(Port * port) {
136 sparta_assert(precedence_set_ == false,
137 "Cannot add ports after any call to set precedence, e.g. inportsPrecede()");
138
139 port_set_.addChild(port);
140 }
141
146 for(auto & p : port_set_.getPorts(Port::IN)) {
147 p.second->enableCollection(this);
148 }
149 for(auto & p : port_set_.getPorts(Port::OUT)) {
150 p.second->enableCollection(this);
151 }
152 }
153
160 return port_set_.getPorts(direction);
161 }
162
167 void setInPortDelay(uint32_t delay_cycles) {
169 for(auto & pi : in_ports) {
170 sparta::Port * port = pi.second;
171 sparta_assert (port != nullptr);
172 port->setPortDelay (static_cast<sparta::Clock::Cycle>(delay_cycles));
173 }
174 }
175
180 void setInPortDelay(double delay_cycles) {
182 for(auto & pi : in_ports) {
183 sparta::Port * port = pi.second;
184 sparta_assert (port != nullptr);
185 port->setPortDelay (delay_cycles);
186 }
187 }
188
193 template<typename EventT>
194 void inportsPrecede(EventT & event) {
196 for(auto & pi : in_ports) {
197 InPort * port = dynamic_cast<InPort*>(pi.second);
198 sparta_assert (port != nullptr);
199 port->registerConsumerEvent(event);
200 }
201 precedence_set_ = true;
202 }
203
208 template<typename EventT>
209 void outportsSucceed(EventT & event) {
211 for(auto & pi : out_ports) {
212 OutPort * port = dynamic_cast<OutPort*>(pi.second);
213 sparta_assert (port != nullptr);
214 port->registerProducingEvent(event);
215 }
216 precedence_set_ = true;
217 }
218
223 void bind(Bus * other_bus)
224 {
225 // Step 1, separate the bus' in and out ports
226 PortSet::RegisteredPortMap this_bus_in_ports;
227 PortSet::RegisteredPortMap this_bus_out_ports;
228 PortSet::RegisteredPortMap other_bus_in_ports;
229 PortSet::RegisteredPortMap other_bus_out_ports;
230 populatePortMap_(this_bus_in_ports, getPorts(Port::IN), "in");
231 populatePortMap_(this_bus_out_ports, getPorts(Port::OUT), "out");
232 populatePortMap_(other_bus_in_ports, other_bus->getPorts(Port::IN), "in");
233 populatePortMap_(other_bus_out_ports, other_bus->getPorts(Port::OUT), "out");
234
235 // Step 2, throw an exception for those ports that cannot
236 // be not bound -- not equivalent buses
237 //
238 // I could make sure that the number of entries in
239 // this_bus_in_ports == other_bus_out_ports, but that
240 // doesn't help the developer debug the issue. Instead,
241 // we try to find the likely unbound ports
242 std::string unbound_ports;
243 checkBinding_(this_bus_in_ports, other_bus_out_ports, unbound_ports);
244 checkBinding_(this_bus_out_ports, other_bus_in_ports, unbound_ports);
245 sparta_assert(unbound_ports.empty(),
246 "When binding bus '" << getName()
247 << "' to bus '" << other_bus->getName()
248 << "', the following ports will NOT get bound (no equivalence): "
249 << unbound_ports);
250
251 // Step 3, go through this bus's in ports and bind to the
252 // out port in other_bus.
253 bindPorts_(this_bus_in_ports, other_bus_out_ports);
254 bindPorts_(this_bus_out_ports, other_bus_in_ports);
255 }
256 protected:
257 void onSettingParent_(const TreeNode* parent) const override;
258 };
259
268 class BusSet : public TreeNode
269 {
270 public:
276 BusSet(TreeNode * parent, const std::string & desc) :
277 TreeNode(parent, "buses", desc)
278 {}
279
281 BusSet(const BusSet &) = delete;
282
284 BusSet & operator=(const BusSet &) = delete;
285
286 protected:
287
288 void onAddingChild_(TreeNode* child) override {
289 Bus * bus = dynamic_cast<Bus*>(child);
290 sparta_assert(bus != nullptr,
291 "ERROR: Attempting to add object '" << child->getName()
292 << "' which is not a Bus type to '" << getLocation() << "'");
293
294 }
295
296 private:
298 std::unordered_map<std::string, Bus*> registered_buses_;
299 };
300
302 inline Bus::Bus(TreeNode * parent,
303 const std::string & name,
304 const std::string& group,
305 group_idx_type group_idx,
306 const std::string & desc) :
307 TreeNode(name, group, group_idx, desc),
308 port_set_(this, desc + " PortSet")
309 {
310 setExpectedParent_(parent);
311 if(parent != nullptr) {
312 parent->addChild(this); // Do not inherit parent state
313 }
314 }
315
317 inline void Bus::onSettingParent_(const TreeNode* parent) const
318 {
319 // Buses can only be added to a BusSet
320 const BusSet * bus_set = dynamic_cast<const BusSet*>(parent);
321 sparta_assert(bus_set != nullptr,
322 "ERROR: Attempting to add Bus '" << getName()
323 << "' to something that is not a BusSet");
324 }
325
333 inline void bind(Bus * p1, Bus * p2) {
334 sparta_assert(p1 != nullptr);
335 sparta_assert(p2 != nullptr);
336 p1->bind(p2);
337 }
338
346 inline void bind(Bus & p1, Bus & p2) {
347 bind(&p1, &p2);
348 }
349
357 inline void bind(Bus * p1, Bus & p2) {
358 sparta_assert(p1 != nullptr);
359 bind(p1, &p2);
360 }
361
369 inline void bind(Bus & p1, Bus * p2) {
370 sparta_assert(p2 != nullptr);
371 bind(&p1, p2);
372 }
373}
374
File that defines the PortSet class.
File that defines the Port base class.
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
Cool string utilities.
A TreeNode that represents a set of Buses.
Definition Bus.hpp:269
BusSet(const BusSet &)=delete
Cannot copy BusSets.
BusSet(TreeNode *parent, const std::string &desc)
Construct a BusSet with a given parent. The parent can be nullptr.
Definition Bus.hpp:276
BusSet & operator=(const BusSet &)=delete
Cannot assign BusSets.
void onAddingChild_(TreeNode *child) override
Hook for reacting to or rejecting new children. Invoked immediately before adding a child to this nod...
Definition Bus.hpp:288
Class that defines a Bus type.
Definition Bus.hpp:46
Bus(TreeNode *parent, const std::string &name, const std::string &group=GROUP_NAME_NONE, group_idx_type group_idx=GROUP_IDX_NONE, const std::string &desc="")
Construct a bus given the parent BusSet.
Definition Bus.hpp:302
void onSettingParent_(const TreeNode *parent) const override
Sanity checking...
Definition Bus.hpp:317
void inportsPrecede(EventT &event)
Make all inports precede the given event.
Definition Bus.hpp:194
void setInPortDelay(uint32_t delay_cycles)
Set the port delay to the given value for all IN ports.
Definition Bus.hpp:167
void registerPort(Port *port)
Register the given port with the bus.
Definition Bus.hpp:135
PortSet::RegisteredPortMap & getPorts(Port::Direction direction)
Get the ports in this PortSet for the given direction.
Definition Bus.hpp:159
void bind(Bus *other_bus)
Bind bus1 to bus2.
Definition Bus.hpp:223
PortSet & getPortSet()
Get the port set this bus uses to maintain the ports.
Definition Bus.hpp:126
void setInPortDelay(double delay_cycles)
Set the port delay to the given value for all IN ports.
Definition Bus.hpp:180
void outportsSucceed(EventT &event)
Make all outports succeed the given event.
Definition Bus.hpp:209
void enableCollection()
Definition Bus.hpp:145
Base class for all InPort types.
Definition Port.hpp:297
void registerConsumerEvent(Scheduleable &consumer)
Add an event "listener" to this port.
Definition Port.hpp:366
Base class for all OutPort types.
Definition Port.hpp:493
void registerProducingEvent(Scheduleable &producer)
Add an event "producer" to this port.
Definition Port.hpp:528
A TreeNode that represents a set of ports used by a Resource.
Definition PortSet.hpp:29
RegisteredPortMap & getPorts(Port::Direction direction)
Get the ports in this PortSet for the given direction.
Definition PortSet.hpp:105
std::unordered_map< std::string, Port * > RegisteredPortMap
Convenience typedef.
Definition PortSet.hpp:33
The port interface used to bind port types together and defines a port behavior.
Definition Port.hpp:59
Direction
The direction of this port.
Definition Port.hpp:68
virtual void setPortDelay(sparta::Clock::Cycle)
Set the delay for a port.
Definition Port.hpp:198
Node in a composite tree representing a sparta Tree item.
Definition TreeNode.hpp:205
static const group_idx_type GROUP_IDX_NONE
GroupIndex indicating that a node has no group index because it belongs to no group.
Definition TreeNode.hpp:303
std::string getLocation() const override final
static constexpr char GROUP_NAME_NONE[]
Group name indicating that a node belongs to no group.
Definition TreeNode.hpp:314
void addChild(TreeNode *child, bool inherit_phase=true)
Adds a TreeNode to this node as a child.
uint32_t group_idx_type
Index within a group.
Definition TreeNode.hpp:261
const std::string & getName() const override
Gets the name of this node.
void setExpectedParent_(const TreeNode *parent)
Tracks a node as an expected parent without actually adding this node as a child. This is used almost...
Macros for handling exponential backoff.
void bind(Bus *p1, Bus *p2)
Bind two buses together.
Definition Bus.hpp:333