orca-sim
DmaNetif.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 
27 // std API
28 #include <iostream>
29 #include <sstream>
30 #include <iomanip>
31 
32 // simulator API
33 #include "TimedModel.hpp"
34 #include "Buffer.hpp"
35 #include "DmaNetif.hpp"
36 
42 
43 DmaNetif::DmaNetif(std::string name) : TimedModel(name) {
44  _sig_stall = nullptr;
45  _sig_intr = nullptr;
46 
47  _sig_send_status = nullptr;
48  _sig_recv_status = nullptr;
49 
50  _sig_recv_reload = nullptr;
51 
52  _sig_prog_addr = nullptr;
53  _sig_prog_size = nullptr;
54  _sig_prog_send = nullptr;
55  _sig_prog_recv = nullptr;
56  _sig_prog_dest = nullptr;
57 
58  _ib = new Buffer<FlitType>(name + ".IN", NI_BUFFER_LEN);
59 
60  this->Reset();
61 }
62 
64  delete _ib;
65 }
66 
70 }
71 
73  _ob = ob;
74 }
75 
77  return _ib;
78 }
79 
80 // state getters
83 
84 void DmaNetif::SetMem0(Memory* m0) { _mem0 = m0; } // main mem
85 void DmaNetif::SetMem1(Memory* m1) { _mem1 = m1; } // recv mem
86 void DmaNetif::SetMem2(Memory* m2) { _mem2 = m2; } // send mem
87 
88 // getters
95 
99 
101 
102 // setters
109 
113 
115 
117  // independent processes, can run parallel
118  this->recvProcess();
119  this->sendProcess();
120 
121  return 1; // takes only 1 cycle to change both states
122 }
123 
125  // recv state machine
126  switch (_recv_state) {
127 
128  // wait for the leading flit do start the loading process
130  if (_ib->size() > 0) {
131  _ib->pop(); // discard first flit
133  _recv_address = _mem0->GetBase(); //write to 1st position
134  }
135  } break;
136 
137  // collect the size of data to be loaded into memory
139  if (_ib->size() > 0) {
140  _recv_reg = _ib->top();
143  _ib->pop();
145  }
146  } break;
147 
149  if (_ib->size() > 0) {
150  _recv_reg = _ib->top();
151  _ib->pop();
153  reinterpret_cast<int8_t*>(&_recv_reg), sizeof(FlitType));
155  _recv_address += sizeof(FlitType);
156 
157  if(_recv_payload_remaining == 0)
159  }
160  break;
161 
163 
164  break;
165 
166  // wait some flit to arrive at the local port
168  // If buffer has any flit, copy that flit to internal
169  // memory and proceed to next flit. Please note that
170  // it is expected the first flit to containg address
171  // data. Whatever comes first we treat as the addr flit.
172  if (_ib->size() > 0) {
173  // copy the first flit into an auxiliar register and pop buffer
174  _recv_reg = _ib->top();
175  _ib->pop();
176 
177  // reset memory pointer and write copied flit to first position
178  _recv_address = 0;
179 
180  #ifdef NETIF_WRITE_ADDRESS_CHECKING
181  if (_recv_address < _mem1->GetBase() || _
182  recv_address > _mem1->GetLastAddr()) {
183  stringstream ss;
184  ss << this->GetName()
185  << ", recv::WAIT_ADDR_FLIT, unable to write to _mem1 "
186  << std::hex << "0x" << _recv_address << std::endl;
187  throw std::runtime_error(ss.str());
188  }
189  #endif
190 
191  // write first flit to recv mem
193  reinterpret_cast<int8_t*>(&_recv_reg), sizeof(FlitType));
194  _recv_address += sizeof(FlitType);
195 
196  // change states
198  }
199  } break;
200 
201  // read size flit to determine how many flits will come next. please
202  // note that we treat whatever flit comes next as the size flit
204  if (_ib->size() > 0) {
205  // copy size flit to an auxiliar register and pop buffer
206  _recv_reg = _ib->top();
207  _ib->pop();
208 
209  // report current size (in flits) to the cpu
210  // we sum 2 due to the size flit does not take the first two
211  // flits into account.
213 
214  #ifdef NETIF_WRITE_ADDRESS_CHECKING
215  if (_recv_address < _mem1->GetBase() ||
216  recv_address > _mem1->GetLastAddr()) {
217  stringstream ss;
218  ss << this->GetName()
219  << ", recv::WAIT_SIZE_FLIT, unable to write to _mem1 "
220  << std::hex << "0x" << _recv_address << std::endl;
221  throw std::runtime_error(ss.str());
222  }
223  #endif
224 
225  // write to the second position and increment memory pointer
227  reinterpret_cast<int8_t*>(&_recv_reg), sizeof(FlitType));
228  _recv_address += sizeof(FlitType);
229 
230  // set current payload size and the number of remaining flits
233 
234  // change states
236  }
237  } break;
238 
239  // wait for remaining flits to arrive, and interrupt
241  // check whether there are more flits to receive
242  if (_recv_payload_remaining > 0) {
243  // check whether there is any data in the buffer
244  if (_ib->size() > 0) {
245  // copy one flit into the auxiliary register and pop buffer
246  _recv_reg = _ib->top();
247  _ib->pop();
248 
249  #ifdef NETIF_WRITE_ADDRESS_CHECKING
250  if (_recv_address < _mem1->GetBase() ||
252  stringstream ss;
253  ss << this->GetName()
254  << ", recv::WAIT_PAYLOAD, unable to write to _mem1 "
255  << std::hex << "0x" << _recv_address << std::endl;
256  throw std::runtime_error(ss.str());
257  }
258  #endif
259 
260  // write the flit to memory and increment memory counter
262  reinterpret_cast<int8_t*>(&_recv_reg),
263  sizeof(FlitType));
264 
265  _recv_address += sizeof(FlitType);
266 
267  // one less flit to be received
269  }
270 
271  // whether the ni received all the payload,
272  // and interrupt the cpu and change states
273  } else {
274  _sig_intr->Write(0x1);
276  }
277  } break;
278 
279  // wait for the cpu to configure the dma
281  if (_sig_prog_recv->Read() == 0x1) {
282  // configured via cpu. accounts the +2, so no sum is necessary
284  _sig_recv_status->Write(0x0);
285 
287  _recv_address = 0; // reset memory pointer
288  _sig_stall->Write(0x1); // stall cpu
289  }
290  } break;
291 
292  // copy data, and release
294  // for each flit, copy from the auxiliary _mem1 memory
295  // to the _mem0 main memory
296  if (_recv_payload_remaining > 0) {
297  #ifdef NETIF_READ_ADDRESS_CHECKING
298  if (_recv_address < _mem1->GetBase() ||
300  stringstream ss;
301  ss << this->GetName()
302  << ", recv::COPY_RELEASE, unable to read to _mem1 "
303  << std::hex << "0x" << _recv_address << std::endl;
304  throw std::runtime_error(ss.str());
305  }
306  #endif
307 
308  // read data to the auxiliary register
310  reinterpret_cast<int8_t*>(&_recv_reg), sizeof(FlitType));
311 
312  #ifdef NETIF_WRITE_ADDRESS_CHECKING
313  uint32_t addr = _recv_address + _sig_prog_addr->Read();
314  if (addr < _mem0->GetBase() || addr > _mem0->GetLastAddr()) {
315  stringstream ss;
316  ss << this->GetName()
317  << ", recv::COPY_RELEASE, unable to write to _mem0 "
318  << std::hex << "0x" << addr << std::endl;
319  throw std::runtime_error(ss.str());
320  }
321  #endif
322 
323  // write auxiliary flit to main memory
325  reinterpret_cast<int8_t*>(&_recv_reg), sizeof(FlitType));
326 
327  _recv_address += sizeof(FlitType); // read next address
328  _recv_payload_remaining--; // one less flit to write
329 
330  // if there is no more flits to receive, lower the interruption,
331  // restore the cpu (release stall), then change states
332  } else {
333  _sig_stall->Write(0x0);
334  _sig_intr->Write(0x0);
335 
337  }
338  } break;
339 
341  if (_sig_prog_recv->Read() == 0x0) {
343  }
344  } break;
345  }
346 }
347 
349  // send state machine
350  switch (_send_state) {
351  // wait the cpu to configure the ni
353  if (_sig_prog_send->Read() == 0x1) {
354  _sig_stall->Write(0x1); // raise stall
355  _sig_send_status->Write(0x1); // raise status
356 
357  _send_address = 0;
360 
361  // change states
363  }
364  } break;
365 
366  // copy data from the main memory to the auxiliary memory
367  // and releases cpu, lower status and stall
369  if (_send_payload_remaining > 0) {
370  #ifdef NETIF_READ_ADDRESS_CHECKING
371  uint32_t addr = _send_address + _sig_prog_addr->Read();
372  if (addr < _mem0->GetBase() || addr > _mem0->GetLastAddr()) {
373  stringstream ss;
374  ss << this->GetName()
375  << ", send::COPY_RELEASE, unable to read from _mem0 "
376  << std::hex << "0x" << addr << std::endl;
377  throw std::runtime_error(ss.str());
378  }
379  #endif
380 
381  // read from main memory
383  reinterpret_cast<int8_t*>(&_send_reg), sizeof(FlitType));
384 
385  #ifdef NETIF_WRITE_ADDRESS_CHECKING
386  if (_send_address < _mem2->GetBase() ||
388  stringstream ss;
389  ss << this->GetName()
390  << ", send::COPY_RELEASE, unable to write to _mem2 "
391  << std::hex << "0x" << _send_address << std::endl;
392  throw std::runtime_error(ss.str());
393  }
394  #endif
395 
396  // write auxiliary flit to auxiliary memory
398  reinterpret_cast<int8_t*>(&_send_reg), sizeof(FlitType));
399 
400  _send_address += sizeof(FlitType); // write next address
401  _send_payload_remaining--; // one less packet to send
402 
403  // all flits copied to the aux memory, switch to noc-mode
404  } else {
405  _sig_stall->Write(0x0); // lowers stall
406  _send_payload_remaining = _send_payload_size; // flits to push
407  _send_address = 0; // reset memory pointer
409  }
410  } break;
411 
413  // make sure the buffer has room to receive another packet
414  if (_send_payload_remaining > 0) {
415  if (_ob->size() < _ob->capacity()) {
417  reinterpret_cast<int8_t*>(&_send_reg),
418  sizeof(FlitType));
419  _ob->push(_send_reg);
421 
422  _send_address += sizeof(FlitType);
423  }
424 
425  // make sure the cpu have lowered the start signal at least once
426  // before getting back to the waiting state (prevent duplicates)
427  } else {
429  }
430  } break;
431 
433  if (_sig_prog_send->Read() == 0x0) {
434  _sig_send_status->Write(0x0); // notify free
436  }
437  } break;
438  }
439 }
Signal< uint32_t > * _sig_prog_size
Definition: DmaNetif.hpp:123
The Signal class models a generic bus of width equals to the sizeof(T)
Definition: Signal.hpp:45
Signal< uint8_t > * GetSignalSendStatus()
Definition: DmaNetif.cpp:91
Signal< uint32_t > * GetSignalProgAddr()
Definition: DmaNetif.cpp:97
void SetSignalProgRecv(Signal< uint8_t > *)
Definition: DmaNetif.cpp:107
Signal< uint8_t > * _sig_stall
Definition: DmaNetif.hpp:114
void push(T)
Pushes an object to the back of the buffer.
Definition: Buffer.cpp:74
Signal< uint8_t > * _sig_send_status
Definition: DmaNetif.hpp:119
void Write(uint32_t addr, MemoryType *data, uint32_t length)
Writes data to the memory.
Definition: Memory.cpp:75
This class models a TimedModel.
Definition: TimedModel.hpp:42
void SetSignalIntr(Signal< uint8_t > *)
Definition: DmaNetif.cpp:104
#define NI_BUFFER_LEN
Definition: DmaNetif.hpp:31
T top()
Peeks at the top of the buffer.
Definition: Buffer.cpp:100
Signal< uint16_t > * _sig_prog_dest
Definition: DmaNetif.hpp:125
void SetOutputBuffer(Buffer< FlitType > *ob)
Definition: DmaNetif.cpp:72
Signal< uint32_t > * GetSignalProgSize()
Definition: DmaNetif.cpp:98
Signal< uint8_t > * _sig_prog_send
Definition: DmaNetif.hpp:117
DmaNetifRecvState _recv_state
Definition: DmaNetif.hpp:106
void SetSignalProgSend(Signal< uint8_t > *)
Definition: DmaNetif.cpp:106
Signal< uint8_t > * _sig_recv_reload
Definition: DmaNetif.hpp:116
T Read()
Get the last value writen to the bus.
Definition: Signal.cpp:118
Signal< uint8_t > * GetSignalIntr()
Definition: DmaNetif.cpp:90
Signal< uint8_t > * _sig_intr
Definition: DmaNetif.hpp:115
void SetSignalRecvReload(Signal< uint8_t > *)
Definition: DmaNetif.cpp:108
Buffer< FlitType > * _ib
Definition: DmaNetif.hpp:138
Buffer< FlitType > * _ob
Definition: DmaNetif.hpp:139
void SetSignalProgSize(Signal< uint32_t > *)
Definition: DmaNetif.cpp:112
uint32_t SimulationTime
void SetSignalRecvStatus(Signal< uint32_t > *)
Definition: DmaNetif.cpp:110
void Write(T val)
Writes some value to the bus.
Definition: Signal.cpp:127
MemoryAddr GetLastAddr()
Get the address of the last addressable memory cell.
Definition: Memory.cpp:183
Signal< uint32_t > * _sig_recv_status
Definition: DmaNetif.hpp:121
Signal< uint8_t > * GetSignalRecvReload()
Definition: DmaNetif.cpp:94
Signal< uint8_t > * GetSignalProgSend()
Definition: DmaNetif.cpp:92
std::string GetName()
Getter method for the <_name> field.
Definition: Model.cpp:34
MemoryAddr GetBase()
(getter) Gets the base address, which is the first addressable memory cell in the module...
Definition: Memory.cpp:173
void SetSignalProgDest(Signal< uint16_t > *)
Definition: DmaNetif.cpp:114
void Read(uint32_t addr, MemoryType *buffer, uint32_t length)
Reads data from a given memory location.
Definition: Memory.cpp:111
Signal< uint8_t > * GetSignalProgRecv()
Definition: DmaNetif.cpp:93
uint16_t FlitType
flit
Definition: DmaNetif.hpp:58
DmaNetifSendState _send_state
Definition: DmaNetif.hpp:107
Signal< uint16_t > * GetSignalProgDest()
Definition: DmaNetif.cpp:100
Signal< uint8_t > * GetSignalStall()
Definition: DmaNetif.cpp:89
Buffer< FlitType > * GetInputBuffer()
Definition: DmaNetif.cpp:76
DmaNetifRecvState GetRecvState()
Definition: DmaNetif.cpp:81
uint32_t capacity()
Returns max size of the buffer.
Definition: Buffer.cpp:91
Signal< uint32_t > * _sig_prog_addr
Definition: DmaNetif.hpp:122
This class models a memory module.
Definition: Memory.hpp:55
SimulationTime Run()
Method which is called by the simulator when during the execution of the TimedModel.
Definition: DmaNetif.cpp:116
Signal< uint8_t > * _sig_prog_recv
Definition: DmaNetif.hpp:118
void SetSignalSendStatus(Signal< uint8_t > *)
Definition: DmaNetif.cpp:105
void Reset()
Resets the instance to its starting state.
Definition: DmaNetif.cpp:67
DmaNetifSendState GetSendState()
Definition: DmaNetif.cpp:82
Signal< uint32_t > * GetSignalRecvStatus()
Definition: DmaNetif.cpp:96
uint32_t size()
Counts elements from the buffer.
Definition: Buffer.cpp:109
void pop()
Removes the object at the front of the buffer.
Definition: Buffer.cpp:56
void SetSignalStall(Signal< uint8_t > *)
Definition: DmaNetif.cpp:103
void SetSignalProgAddr(Signal< uint32_t > *)
Definition: DmaNetif.cpp:111