orca-sim
HermesRouter.cpp
Go to the documentation of this file.
1 /******************************************************************************
2  * This file is part of project ORCA. More information on the project
3  * can be found at the following repositories at GitHub's website.
4  *
5  * http://https://github.com/andersondomingues/orca-sim
6  * http://https://github.com/andersondomingues/orca-software
7  * http://https://github.com/andersondomingues/orca-mpsoc
8  * http://https://github.com/andersondomingues/orca-tools
9  *
10  * Copyright (C) 2018-2020 Anderson Domingues, <ti.andersondomingues@gmail.com>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License along
23  * with this program; if not, write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 ******************************************************************************/
26 #include <cstdlib>
27 #include <sstream>
28 #include <iomanip>
29 
30 #include "HermesRouter.hpp"
31 
36 
41 std::string HermesRouter::GetPortName(int port) {
42  switch (port) {
43  case SOUTH: return "SOUTH";
44  case NORTH: return "NORTH";
45  case WEST: return "WEST";
46  case EAST: return "EAST";
47  default: return "LOCAL";
48  }
49  return "???";
50 }
51 
57 HermesRouter::HermesRouter(std::string name, uint32_t x_pos, uint32_t y_pos):
58  TimedModel(name) {
59  _x = x_pos;
60  _y = y_pos;
61 
62  // for all ports, create a new input buffer; Note that data is bufferred by
63  // input buffers, since output buffers come from somewhere else;
64  for (int i = 0; i < 5; i++) {
65  std::string bname = GetName() + ".IN-" + this->GetPortName(i);
66  _ob[i] = nullptr;
67  _ib[i] = new Buffer<FlitType>(bname, BUFFER_CAPACITY);
68  }
69 
70  #ifdef ROUTER_ENABLE_COUNTERS
71  // if counters are enabled, initiate the respective signals
72  // please note that these signals are not mapped to anywhere yet
73  _counter_active = new Signal<uint32_t>(GetName() + ".counters.active");
74  #endif
75 
76  this->Reset();
77 }
78 
83  #ifdef ROUTER_ENABLE_COUNTERS
84  delete _counter_active;
85  #endif
86 
87  for (int i = 0; i < 5; i++)
88  delete(_ib[i]);
89 }
90 
92  _round_robin = LOCAL; // starts checking on local port
93 
94  for (int i = 0; i < 5; i++) {
95  _flits_to_send[i] = 0;
96  _switch_control[i] = -1;
97  }
98 
99  // TODO(ad): reset buffers
100 }
101 
103  return _round_robin;
104 }
105 
111  // CROSSBAR CONTROL: connect priority port to destination if it has any
112  // packet to send but is waiting for the destination to free
113  if (_ib[_round_robin]->size() > 0 && _switch_control[_round_robin] == -1) {
114  // find the destination using the address in the first flit
115  uint8_t target_port = this->GetRouteXY(_ib[_round_robin]->top());
116 
117  // check whether the destination port is bound to some other source port
118  bool bound = false;
119 
120  for (int i = 0; i < 5; i++) {
121  if (_switch_control[i] == target_port) {
122  bound = true;
123  break;
124  }
125  }
126 
127  // if the port is not bind, binds it to the source
128  if (!bound) {
129  // set crossbar connection
130  _switch_control[_round_robin] = target_port;
131  // -2 means "the size flit has not arrived yet"
133  }
134  }
135 
136  // drive flits into destination ports
137  for (int i = 0; i < 5; i++) {
138  // check whether the switch control is closed for some port
139  if (_switch_control[i] != -1) {
140  // prevent routing to a non-existing router
141  #ifdef ROUTER_PORT_CONNECTED_CHECKING
142  if (_ob[_switch_control[i]] == nullptr) {
143  stringstream ss;
144  ss << this->GetName() << ": unable to route to unknown port"
145  << std::endl;
146  std::runtime_error(ss.str());
147  }
148 
149  if (_ib[i] == nullptr) {
150  stringstream ss;
151  ss << this->GetName() << ": unable to route from unknown port"
152  << std::endl;
153  std::runtime_error(ss.str());
154  }
155  #endif
156  // check whether the output is able to receive new flits.
157  // buffer must have some room
158  if (!_ob[_switch_control[i]]->full() && _ib[i]->size() > 0) {
159  // if -2, we send the address flit
160  if (_flits_to_send[i] == -2) {
161  // push one flit to destination port
162  _ob[_switch_control[i]]->push(_ib[i]->top());
163  _flits_to_send[i] = -1;
164  _ib[i]->pop(); // remove flit from source port
165 
166  // if -1, we set the size flit and send it
167  } else if (_flits_to_send[i] == -1) {
168  _flits_to_send[i] = _ib[i]->top();
169  // push one flit to destination port
170  _ob[_switch_control[i]]->push(_ib[i]->top());
171  _ib[i]->pop(); // remove flit from source port
172 
173  } else {
174  _flits_to_send[i] -= 1;
175  // push one flit to destination port
176  _ob[_switch_control[i]]->push(_ib[i]->top());
177  _ib[i]->pop(); // remove flit from source port
178  }
179 
180  #ifdef ROUTER_ENABLE_COUNTERS
181  _is_active = true;
182  #endif
183 
184  // free port
185  if (_flits_to_send[i] == 0)
186  _switch_control[i] = -1;
187  }
188  }
189  }
190 
191  // round robin update
192  _round_robin = (_round_robin + 1) % 5;
193 
194  #ifdef ROUTER_ENABLE_COUNTERS
195  if (is_active) {
196  _counter_active->Inc(1);
197  _is_active = false;
198  }
199  #endif
200  return 1;
201 }
202 
203 #ifdef ROUTER_ENABLE_COUNTERS
204 Signal<uint32_t>* TRouter::GetSignalCounterActive() {
205  return this->_counter_active;
206 }
207 
208 #endif
209 
215  FlitType tx = (flit & 0x00F0) >> 4;
216  FlitType ty = flit & 0x000F;
217 
218  // if X=0, then route "vertically" (Y)
219  if (_x == tx) {
220  return (_y == ty)
221  ? LOCAL
222  : (_y > ty)
223  ? SOUTH
224  : NORTH;
225  // route X
226  } else {
227  return (_x > tx)
228  ? WEST
229  : EAST;
230  }
231 }
232 
238  return _ob[r];
239 }
240 
242  return _ib[r];
243 }
244 
246  _ob[port] = b;
247 }
248 
249 std::string HermesRouter::ToString() {
250  std::stringstream ss;
251  ss << this->GetName() + ": ";
252 
253  for (int i = 0; i < 5; i++) {
254  if (_ob[i] != nullptr)
255  ss << "{" << _ob[i]->GetName() << "} ";
256  }
257 
258  return ss.str();
259 }
SimulationTime Run()
Implementation of the Process&#39; interface.
std::string GetPortName(int port)
Get the name of the port of id equals to <port>
Buffer< FlitType > * GetOutputBuffer(uint32_t p)
Get a pointer to one of the output buffers.
void push(T)
Pushes an object to the back of the buffer.
Definition: Buffer.cpp:74
void Reset()
Resets the instance to its starting state.
#define EAST
This class models a TimedModel.
Definition: TimedModel.hpp:42
void SetOutputBuffer(Buffer< FlitType > *b, uint32_t port)
T top()
Peeks at the top of the buffer.
Definition: Buffer.cpp:100
#define WEST
#define SOUTH
#define LOCAL
HermesRouter(std::string name, uint32_t x_pos, uint32_t y_pos)
Ctor.
uint32_t SimulationTime
#define NORTH
std::string GetName()
Getter method for the <_name> field.
Definition: Model.cpp:34
#define BUFFER_CAPACITY
uint32_t size()
Counts elements from the buffer.
Definition: Buffer.cpp:109
Buffer< FlitType > * GetInputBuffer(uint32_t p)
void pop()
Removes the object at the front of the buffer.
Definition: Buffer.cpp:56
uint32_t GetRouteXY(FlitType flit)
return this