orca-sim
Orca.cpp
Go to the documentation of this file.
1 
21 #include <iostream>
22 #include <iomanip>
23 #include <chrono>
24 #include <cmath>
25 
26 //signal manip
27 #include <signal.h>
28 
29 //simulation artifacts (from URSA)
30 #include <Event.h>
31 #include <Simulator.h>
32 
33 //built-in models (from URSA)
34 #include <UMemory.h>
35 
36 //reusable models
37 #include <THFRiscV.h>
38 #include <TRouter.h>
39 #include <TDmaNetif.h>
40 #include <TNetBridge.h>
41 
42 //orca-specific hardware
43 #include <Tile.h>
44 
45 #include <ProcessingTile.h>
46 #include <NetworkTile.h>
47 
48 //instantiates a mesh of MxN PE
49 Tile* tiles[ORCA_NOC_WIDTH][ORCA_NOC_HEIGHT];
50 
51 //interrupt signal catcher
52 static volatile sig_atomic_t interruption = 0;
53 
54 int _status = 0;
55 
56 static void sig_handler(int _){
57 
58  (void)_;
59 
60  switch(interruption){
61  case 0:
62  interruption = 1;
63  std::cout << std::endl << "Simulation interrupted. Wait for the current epoch to finish or press CTRL+C again to force quit." << std::endl;
64  break;
65  case 1:
66  exit(0);
67  break;
68  case 2:
69  std::cout << std::endl << "Hold your horses!" << std::endl;
70  break;
71  }
72 }
73 
74 //connect routers to each other
75 void connect_routers(HermesRouter* r1, uint32_t p1, HermesRouter* r2, uint32_t p2){
76 
77  r1->SetOutputBuffer(r2->GetInputBuffer(p2), p1);
78  r2->SetOutputBuffer(r1->GetInputBuffer(p1), p2);
79 
80  //std::cout << "router_signal: " << r1->GetName() << " ----["
81  // << p1 << "/" << p2 << "]---- " << r2->GetName() << std::endl;
82 
83  std::cout << r1->GetInputBuffer(p1)->GetName()
84  << " <---> " << r2->GetInputBuffer(p2)->GetName() << std::endl;
85 }
86 
87 int main(int __attribute__((unused)) argc, char** argv){
88 
89  //display usage message
90  if(argc < 2){
91  std::cout << "usage: \n\t" << argv[0] << " <software-image>" << std::endl;
92  return 1;
93  }
94 
95  std::string param1 = std::string(argv[1]);
96 
97  //register interruption handler
98  signal(SIGINT, sig_handler);
99 
100  std::cout << "URSA/ORCA Platform " << std::endl;
101  std::cout << "==============[ TILE IDENTIFICATION ]" << std::endl;
102 
103  //populate tiles
104  for(int x = 0; x < ORCA_NOC_WIDTH; x++){
105  for(int y = 0; y < ORCA_NOC_HEIGHT; y++){
106  if(x == 0 && y == 0)
107  std::cout << "[C]";
108  else
109  std::cout << "[P]";
110  }
111  std::cout << std::endl;
112  }
113 
114  #ifdef ORCA_ENABLE_GDBRSP
115  std::cout << "==============[ GDBRSP SERVERS ]" << std::endl;
116  #endif
117 
118 
119  //populate tiles
120  for(int x = 0; x < ORCA_NOC_WIDTH; x++){
121  for(int y = 0; y < ORCA_NOC_HEIGHT; y++){
122 
123  if(x == 0 && y ==0){
124  tiles[x][y] = (Tile*)new NetworkTile(x, y);
125  std::cout << "[----]";
126  }else{
127  tiles[x][y] = (Tile*)new ProcessingTile(x, y);
128  }
129  }
130 
131  std::cout << std::endl;
132  }
133 
134  std::cout << "==============[ ROUTER CONNECTIONS ]" << std::endl;
135 
136  //connect tiles to each other (left-to-right, right-to-left connections)
137  for(int x = 0; x < ORCA_NOC_WIDTH - 1; x++)
138  for(int y = 0; y < ORCA_NOC_HEIGHT; y++)
139  connect_routers(tiles[x][y]->GetRouter(), EAST, tiles[x+1][y]->GetRouter(), WEST);
140 
141  //connect tiles to each other (bottom-to-top, top-to-bottom connections)
142  for(int x = 0; x < ORCA_NOC_WIDTH; x++)
143  for(int y = 0; y < ORCA_NOC_HEIGHT - 1; y++)
144  connect_routers(tiles[x][y]->GetRouter(), NORTH, tiles[x][y+1]->GetRouter(), SOUTH);
145 
146  //load binaries into main memories (processing tiles only)
147  for(int x = 0; x < ORCA_NOC_WIDTH; x++){
148  for(int y = 0; y < ORCA_NOC_HEIGHT; y++){
149 
150  //zero-zero is for network interface
151  if(x == 0 && y == 0) continue;
152 
153  //index = x + ORCA_NOC_WIDTH * y;
154  ((ProcessingTile*)tiles[x][y])->GetMem0()->LoadBin(param1, MEM0_BASE, MEM0_SIZE);
155  }
156  }
157 
158  std::cout << "==============[ SIMULATION ]" << std::endl;
159 
160  //instantiate simulation
161  Simulator* s = new Simulator();
162 
163  std::cout << "Scheduling..." << std::endl;
164 
165  //schedule hardware to be simulated
166  for(int x = 0; x < ORCA_NOC_WIDTH; x++){
167  for(int y = 0; y < ORCA_NOC_HEIGHT; y++){
168 
169  //schedule network bridge module, which starts at the first cycle
170  if(x == 0 && y == 0){
171  s->Schedule(Event(1, ((NetworkTile*)tiles[x][y])->GetSocket()));
172 
173  //schedule the cpu to start at the third cycle, because no instruction
174  //gets out the cpu before that cycle
175  }else{
176  s->Schedule(Event(3, ((ProcessingTile*)tiles[x][y])->GetCpu()));
177  s->Schedule(Event(1, ((ProcessingTile*)tiles[x][y])->GetDmaNetif()));
178  }
179 
180  //all other hardware start at the first cycle
181  s->Schedule(Event(1, tiles[x][y]->GetRouter()));
182 
183  }
184  }
185 
186  std::cout << "Epoch set to " << ORCA_EPOCH_LENGTH << " cycles." << std::endl;
187  std::cout << "Please wait..." << std::endl;
188 
189  try{
190 
191  std::chrono::high_resolution_clock::time_point t1, t2;
192 
193  while(!interruption){
194 
195  t1 = std::chrono::high_resolution_clock::now();
196  s->Run(ORCA_EPOCH_LENGTH);
197  t2 = std::chrono::high_resolution_clock::now();
198 
199  auto duration = std::chrono::duration_cast<std::chrono::milliseconds>( t2 - t1 ).count();
200  s->NextEpoch();
201 
202  //converts mili to seconds before calculating the frequency
203  double hertz = ((double)ORCA_EPOCH_LENGTH) / ((double)((double)duration / 1000.0));
204 
205  //divide frequency by 1k (Hz -> KHz)
206  std::cout << "notice: epoch #" << s->GetEpochs() << " took ~"
207  << duration << "ms (running @ " << (hertz / 1000000.0)
208  << " MHz)" << std::endl;
209 
210  #ifdef ORCA_EPOCHS_TO_SIM
211  //simulate until reach the limit of pulses
212  if(s->GetEpochs() >= ORCA_EPOCHS_TO_SIM)
213  break;
214  #endif
215  }
216 
217  }catch(std::runtime_error& e){
218  std::cout << e.what() << std::endl;
219  _status = 1;
220  }
221 
222  //show buffer status
223  std::cout << "==============[ BUFFERS' STATUSES ]" << std::endl;
224  for(int x = 0; x < ORCA_NOC_WIDTH; x++){
225  for(int y = 0; y < ORCA_NOC_HEIGHT; y++){
226 
227  HermesRouter* r = tiles[x][y]->GetRouter();
228  std::cout << r->GetName() << ":"
229  << " S=" << r->GetInputBuffer(SOUTH)->size()
230  << " N=" << r->GetInputBuffer(NORTH)->size()
231  << " W=" << r->GetInputBuffer(WEST)->size()
232  << " E=" << r->GetInputBuffer(EAST)->size()
233  << " L=" << r->GetInputBuffer(LOCAL)->size()
234  << " RR=" << r->GetRR()
235  << std::endl;
236  }
237  }
238 
239  //NI states
240  std::cout << "==============[ NIs STATUSES ]" << std::endl;
241  for(int x = 0; x < ORCA_NOC_WIDTH; x++){
242  for(int y = 0; y < ORCA_NOC_HEIGHT; y++){
243 
244  if(x == 0 && y == 0) continue;
245 
246  DmaNetif* n = ((ProcessingTile*)(tiles[x][y]))->GetDmaNetif();
247  std::cout << n->GetName() << ":"
248  << " SEND_STATE=" << static_cast<unsigned int>(n->GetSendState())
249  << " RECV_STATE=" << static_cast<unsigned int>(n->GetRecvState())
250  // << " |"
251  << std::endl;
252  }
253  }
254 
255  //CPU statuses
256  std::cout << "==============[ CPU STATUSES ]" << std::endl;
257  for(int x = 0; x < ORCA_NOC_WIDTH; x++){
258  for(int y = 0; y < ORCA_NOC_HEIGHT; y++){
259 
260  if(x == 0 && y == 0)
261  continue;
262 
263  ProcessingTile* t = (ProcessingTile*)(tiles[x][y]);
264  HFRiscV* n = t->GetCpu();
265  std::cout
266  << n->GetName()
267  << ": INTR=" << (int)(n->GetSignalIntr()->Read())
268  << ", STALL=" << (int)(n->GetSignalStall()->Read()) << std::endl;
269 
270  ((ProcessingTile*)tiles[x][y])->GetMem0()->
271  SaveBin(std::string(argv[1]) + n->GetName() + ".save.bin", MEM0_BASE, MEM0_SIZE);
272  }
273  }
274 
275  delete(s);
276 
277  //delete PE
278  for(int x = 0; x < ORCA_NOC_WIDTH; x++){
279  for(int y = 0; y < ORCA_NOC_HEIGHT; y++){
280 
281  if(x == 0 && y ==0){
282  delete((NetworkTile*)tiles[x][y]);
283  }else{
284  delete((ProcessingTile*)tiles[x][y]);
285  }
286 
287  }
288  }
289 
290  if(_status)
291  std::cout << "Simulation failed!" << std::endl;
292  else
293  std::cout << "Simulation ended without errors." << std::endl;
294 
295  return _status;
296 }
297 
298 
299 
300 
#define MEM0_BASE
Tile * tiles[ORCA_NOC_WIDTH][ORCA_NOC_HEIGHT]
Implementation file for ORCA-SIM program.
Definition: Orca.cpp:49
#define EAST
#define MEM0_SIZE
This file is part of project URSA.
void connect_routers(HermesRouter *r1, uint32_t p1, HermesRouter *r2, uint32_t p2)
Definition: Orca.cpp:75
#define ORCA_EPOCHS_TO_SIM
Definition: Simulator.cpp:34
#define WEST
#define ORCA_EPOCH_LENGTH
Definition: Simulator.cpp:33
#define SOUTH
static volatile sig_atomic_t interruption
Definition: Orca.cpp:52
This file is part of project URSA.
Definition: NetworkTile.h:45
int main(int __attribute__((unused)) argc, char **argv)
Definition: Orca.cpp:87
#define LOCAL
#define NORTH
HermesRouter * GetRouter()
Get current router of the PE.
Definition: Tile.cpp:83
static void sig_handler(int _)
Definition: Orca.cpp:56
Definition: Tile.h:44
int _status
Definition: Orca.cpp:54
HFRiscV * GetCpu()
This class models an entire processing element that contains RAM memory (3x), DMA, NoC Router, HFRiscV core.