CIRCT  19.0.0git
State.h
Go to the documentation of this file.
1 //===- State.h - Simulation state definition --------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Defines structures used to keep track of the simulation state in the LLHD
10 // simulator.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef CIRCT_DIALECT_LLHD_SIMULATOR_STATE_H
15 #define CIRCT_DIALECT_LLHD_SIMULATOR_STATE_H
16 
17 #include "llvm/ADT/APInt.h"
18 #include "llvm/ADT/SmallVector.h"
19 #include "llvm/ADT/StringMap.h"
20 
21 #include <map>
22 #include <queue>
23 #include <regex>
24 
25 namespace circt {
26 namespace llhd {
27 namespace sim {
28 
29 /// The simulator's internal representation of time.
30 class Time {
31 public:
32  /// Empty (zero) time constructor. All the time values are defaulted to 0.
33  Time() = default;
34 
35  /// Construct with given time values.
36  Time(uint64_t time, uint64_t delta, uint64_t eps)
37  : time(time), delta(delta), eps(eps) {}
38 
39  /// Compare the time values in order of time, delta, eps.
40  bool operator<(const Time &rhs) const {
41  return time < rhs.time || (time == rhs.time && delta < rhs.delta) ||
42  (time == rhs.time && delta == rhs.delta && eps < rhs.eps);
43  }
44 
45  /// Return true if all the time values are equal.
46  bool operator==(const Time &rhs) const {
47  return time == rhs.time && delta == rhs.delta && eps == rhs.eps;
48  }
49 
50  /// Add two time values.
51  Time operator+(const Time &rhs) const {
52  return Time(time + rhs.time, delta + rhs.delta, eps + rhs.eps);
53  }
54 
55  /// Get the stored time in a printable format.
56  std::string toString() const;
57 
58  uint64_t getTime() const { return time; }
59 
60 private:
61  /// Simulation real time.
62  uint64_t time;
63  uint64_t delta;
64  uint64_t eps;
65 };
66 
67 /// Detail structure that can be easily accessed by the lowered code.
68 struct SignalDetail {
69  uint8_t *value;
70  uint64_t offset;
71  uint64_t instIndex;
72  uint64_t globalIndex;
73 };
74 
75 /// The simulator's internal representation of a signal.
76 class Signal {
77 public:
78  /// Construct an "empty" signal.
79  Signal(std::string name, std::string owner)
80  : name(name), owner(owner), size(0), value(nullptr) {}
81 
82  /// Construct a signal with the given name, owner and initial value.
83  Signal(std::string name, std::string owner, uint8_t *value, uint64_t size)
84  : name(name), owner(owner), size(size), value(value) {}
85 
86  /// Default move constructor.
87  Signal(Signal &&) = default;
88 
89  /// Free 'value' since it is allocated using 'malloc' in the LLVM code
90  /// generated by LLHDToLLVM.
91  ~Signal();
92 
93  /// Returns true if the signals match in name, owner, size and value.
94  bool operator==(const Signal &rhs) const {
95  if (owner != rhs.owner || name != rhs.name || size != rhs.size)
96  return false;
97  return std::memcmp(value, rhs.value, size);
98  }
99 
100  /// Returns true if the owner name is lexically smaller than rhs's owner, or
101  /// the name is lexically smaller than rhs's name, in case they share the same
102  /// owner.
103  bool operator<(const Signal &rhs) const {
104  return (owner < rhs.owner || (owner == rhs.owner && name < rhs.name));
105  }
106 
107  bool isOwner(const std::string &rhs) const { return owner == rhs; };
108 
109  std::string getOwner() const { return owner; }
110 
111  bool isValidSigName() const {
112  return std::regex_match(name, std::regex("(sig)?[0-9]*"));
113  }
114 
115  std::string getName() const { return name; }
116 
117  uint64_t getSize() const { return size; }
118 
119  uint8_t *getValue() const { return value; }
120 
121  const std::vector<unsigned> &getTriggeredInstanceIndices() const {
122  return instanceIndices;
123  }
124 
125  void pushInstanceIndex(unsigned i) { instanceIndices.push_back(i); }
126 
127  bool hasElement() const { return elements.size() > 0; }
128 
129  size_t getElementSize() const { return elements.size(); }
130 
131  void pushElement(std::pair<unsigned, unsigned> val) {
132  elements.push_back(val);
133  }
134 
135  /// Store JIT allocated signal pointer and size.
136  void store(uint8_t *v, uint64_t s) {
137  value = v;
138  size = s;
139  }
140 
141  /// Update signal value when it is changed, the width of incoming signal
142  /// value and the stored signal value are identical.
143  /// As majority signals are smaller than 64 bits, this implementation
144  /// is much faster as it avoided memcpy in most cases.
145  /// @param v Pointer to signal value
146  /// @return true when signal is updated, false when not
147  bool updateWhenChanged(const uint64_t *v) {
148  switch (size) {
149  case 1: {
150  const uint8_t *newVal = reinterpret_cast<const uint8_t *>(v);
151  if (*value == *newVal)
152  return false;
153  *value = *newVal;
154  break;
155  }
156  case 2: {
157  const uint16_t *newVal = reinterpret_cast<const uint16_t *>(v);
158  if (*(uint16_t *)value == *newVal)
159  return false;
160  *(uint16_t *)value = *newVal;
161  break;
162  }
163  case 4: {
164  const uint32_t *newVal = reinterpret_cast<const uint32_t *>(v);
165  if (*(uint32_t *)value == *newVal)
166  return false;
167  *(uint32_t *)value = *newVal;
168  break;
169  }
170  case 8: {
171  if (*(uint64_t *)value == *v)
172  return false;
173  *(uint64_t *)value = *v;
174  break;
175  }
176  default: {
177  if (std::memcmp(value, v, size) == 0)
178  return false;
179  std::memcpy(value, v, size);
180  break;
181  }
182  }
183 
184  return true;
185  }
186 
187  /// Return the value of the signal in hexadecimal string format.
188  std::string toHexString() const;
189 
190  /// Return the value of the i-th element of the signal in hexadecimal string
191  /// format.
192  std::string toHexString(unsigned) const;
193 
194 private:
195  std::string name;
196  std::string owner;
197  // The list of instances this signal triggers.
198  std::vector<unsigned> instanceIndices;
199  uint64_t size;
200  uint8_t *value;
201  std::vector<std::pair<unsigned, unsigned>> elements;
202 };
203 
204 /// The simulator's internal representation of one queue slot.
205 struct Slot {
206  /// Create a new empty slot.
208 
209  /// Returns true if the slot's time is smaller than the compared slot's time.
210  bool operator<(const Slot &rhs) const;
211 
212  /// Returns true if the slot's time is greater than the compared slot's time.
213  bool operator>(const Slot &rhs) const;
214 
215  /// Insert a change.
216  void insertChange(int index, int bitOffset, uint8_t *bytes, unsigned width);
217 
218  /// Insert a scheduled process wakeup.
219  void insertChange(unsigned inst);
220 
221  // A map from signal indexes to change buffers. Makes it easy to sort the
222  // changes such that we can process one signal at a time.
223  llvm::SmallVector<std::pair<unsigned, unsigned>, 32> changes;
224  // Buffers for the signal changes.
225  llvm::SmallVector<std::pair<unsigned, llvm::APInt>, 32> buffers;
226  // The number of used change buffers in the slot.
227  size_t changesSize = 0;
228 
229  // Processes with scheduled wakeup.
230  llvm::SmallVector<unsigned, 4> scheduled;
232  bool unused = false;
233 };
234 
235 /// This is equivalent to and std::priorityQueue<Slot> ordered using the greater
236 /// operator, which adds an insertion method to add changes to a slot.
237 class UpdateQueue : public llvm::SmallVector<Slot, 8> {
238  unsigned topSlot = 0;
239  llvm::SmallVector<unsigned, 4> unused;
240 
241 public:
242  /// Check wheter a slot for the given time already exists. If that's the case,
243  /// add the new change to it, else create a new slot and push it to the queue.
244  void insertOrUpdate(Time time, int index, int bitOffset, uint8_t *bytes,
245  unsigned width);
246 
247  /// Check wheter a slot for the given time already exists. If that's the case,
248  /// add the scheduled wakeup to it, else create a new slot and push it to the
249  /// queue.
250  void insertOrUpdate(Time time, unsigned inst);
251 
252  /// Return a reference to a slot with the given timestamp. If such a slot
253  /// already exists, a reference to it will be returned. Otherwise a reference
254  /// to a fresh slot is returned.
255  Slot &getOrCreateSlot(Time time);
256 
257  /// Get a reference to the current top of the queue (the earliest event
258  /// available).
259  const Slot &top();
260 
261  /// Pop the current top of the queue. This marks the current top slot as
262  /// unused and resets its internal structures such that they can be reused.
263  void pop();
264 
265  unsigned events = 0;
266 };
267 
268 /// State structure for process persistence across suspension.
269 struct ProcState {
270  unsigned inst;
271  int resume;
272  bool *senses;
273  uint8_t *resumeState;
274 };
275 
276 /// The simulator internal representation of an instance.
277 struct Instance {
278  Instance() = default;
279 
280  Instance(std::string name)
281  : name(name), procState(nullptr), entityState(nullptr) {}
282 
283  // The instance name.
284  std::string name;
285  // The instance's hierarchical path.
286  std::string path;
287  // The instance's base unit.
288  std::string unit;
289  bool isEntity;
290  size_t nArgs = 0;
291  // The arguments and signals of this instance.
292  llvm::SmallVector<SignalDetail, 0> sensitivityList;
294  uint8_t *entityState;
296  // A pointer to the base unit jitted function.
297  void (*unitFPtr)(void **);
298 
299  /// Free procState and entityState since they are allocated using 'malloc' in
300  /// the LLVM code generated in LLHDToLLVM.
301  ~Instance();
302 };
303 
304 /// The simulator's state. It contains the current simulation time, signal
305 /// values and the event queue.
306 struct State {
307  /// Construct a new empty (at 0 time) state.
308  State() = default;
309 
310  /// State destructor, ensures all malloc'd regions stored in the state are
311  /// correctly free'd.
312  ~State();
313 
314  /// Pop the head of the queue and update the simulation time.
315  Slot popQueue();
316 
317  /// Push a new scheduled wakeup event in the event queue.
318  void pushQueue(Time time, unsigned inst);
319 
320  /// Find an instance in the instances list by name and return an
321  /// iterator for it.
322  llvm::SmallVectorTemplateCommon<Instance>::iterator
323  getInstanceIterator(std::string instName);
324 
325  /// Add a new signal to the state. Returns the index of the new signal.
326  int addSignal(std::string name, std::string owner);
327 
328  int addSignalData(int index, std::string owner, uint8_t *value,
329  uint64_t size);
330 
331  void addSignalElement(unsigned, unsigned, unsigned);
332 
333  /// Add a pointer to the process persistence state to a process instance.
334  void addProcPtr(std::string name, ProcState *procStatePtr);
335 
336  /// Dump a signal to the out stream. One entry is added for every instance
337  /// the signal appears in.
338  void dumpSignal(llvm::raw_ostream &out, int index);
339 
340  /// Dump the instance layout. Used for testing purposes.
341  void dumpLayout();
342 
343  /// Dump the instances each signal triggers. Used for testing purposes.
344  void dumpSignalTriggers();
345 
347  std::string root;
348  llvm::SmallVector<Instance, 0> instances;
349  llvm::SmallVector<Signal, 0> signals;
351 };
352 
353 } // namespace sim
354 } // namespace llhd
355 } // namespace circt
356 
357 #endif // CIRCT_DIALECT_LLHD_SIMULATOR_STATE_H
int32_t width
Definition: FIRRTL.cpp:36
The simulator's internal representation of a signal.
Definition: State.h:76
std::string name
Definition: State.h:195
Signal(std::string name, std::string owner, uint8_t *value, uint64_t size)
Construct a signal with the given name, owner and initial value.
Definition: State.h:83
void store(uint8_t *v, uint64_t s)
Store JIT allocated signal pointer and size.
Definition: State.h:136
bool isValidSigName() const
Definition: State.h:111
void pushInstanceIndex(unsigned i)
Definition: State.h:125
Signal(Signal &&)=default
Default move constructor.
std::vector< unsigned > instanceIndices
Definition: State.h:198
bool operator==(const Signal &rhs) const
Returns true if the signals match in name, owner, size and value.
Definition: State.h:94
std::string getOwner() const
Definition: State.h:109
Signal(std::string name, std::string owner)
Construct an "empty" signal.
Definition: State.h:79
std::string owner
Definition: State.h:196
std::vector< std::pair< unsigned, unsigned > > elements
Definition: State.h:201
void pushElement(std::pair< unsigned, unsigned > val)
Definition: State.h:131
size_t getElementSize() const
Definition: State.h:129
uint64_t getSize() const
Definition: State.h:117
uint8_t * getValue() const
Definition: State.h:119
std::string getName() const
Definition: State.h:115
bool isOwner(const std::string &rhs) const
Definition: State.h:107
bool updateWhenChanged(const uint64_t *v)
Update signal value when it is changed, the width of incoming signal value and the stored signal valu...
Definition: State.h:147
~Signal()
Free 'value' since it is allocated using 'malloc' in the LLVM code generated by LLHDToLLVM.
Definition: State.cpp:60
const std::vector< unsigned > & getTriggeredInstanceIndices() const
Definition: State.h:121
bool operator<(const Signal &rhs) const
Returns true if the owner name is lexically smaller than rhs's owner, or the name is lexically smalle...
Definition: State.h:103
bool hasElement() const
Definition: State.h:127
std::string toHexString() const
Return the value of the signal in hexadecimal string format.
Definition: State.cpp:37
The simulator's internal representation of time.
Definition: State.h:30
uint64_t delta
Definition: State.h:63
Time operator+(const Time &rhs) const
Add two time values.
Definition: State.h:51
uint64_t getTime() const
Definition: State.h:58
bool operator==(const Time &rhs) const
Return true if all the time values are equal.
Definition: State.h:46
Time()=default
Empty (zero) time constructor. All the time values are defaulted to 0.
std::string toString() const
Get the stored time in a printable format.
Definition: State.cpp:28
bool operator<(const Time &rhs) const
Compare the time values in order of time, delta, eps.
Definition: State.h:40
uint64_t time
Simulation real time.
Definition: State.h:62
Time(uint64_t time, uint64_t delta, uint64_t eps)
Construct with given time values.
Definition: State.h:36
This is equivalent to and std::priorityQueue<Slot> ordered using the greater operator,...
Definition: State.h:237
const Slot & top()
Get a reference to the current top of the queue (the earliest event available).
Definition: State.cpp:161
llvm::SmallVector< unsigned, 4 > unused
Definition: State.h:239
void insertOrUpdate(Time time, int index, int bitOffset, uint8_t *bytes, unsigned width)
Check wheter a slot for the given time already exists.
Definition: State.cpp:102
void pop()
Pop the current top of the queue.
Definition: State.cpp:171
Slot & getOrCreateSlot(Time time)
Return a reference to a slot with the given timestamp.
Definition: State.cpp:113
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
The simulator internal representation of an instance.
Definition: State.h:277
~Instance()
Free procState and entityState since they are allocated using 'malloc' in the LLVM code generated in ...
Definition: State.cpp:198
Instance(std::string name)
Definition: State.h:280
void(* unitFPtr)(void **)
Definition: State.h:297
llvm::SmallVector< SignalDetail, 0 > sensitivityList
Definition: State.h:292
ProcState * procState
Definition: State.h:293
State structure for process persistence across suspension.
Definition: State.h:269
Detail structure that can be easily accessed by the lowered code.
Definition: State.h:68
The simulator's internal representation of one queue slot.
Definition: State.h:205
void insertChange(int index, int bitOffset, uint8_t *bytes, unsigned width)
Insert a change.
Definition: State.cpp:73
bool operator>(const Slot &rhs) const
Returns true if the slot's time is greater than the compared slot's time.
Definition: State.cpp:71
llvm::SmallVector< std::pair< unsigned, unsigned >, 32 > changes
Definition: State.h:223
llvm::SmallVector< unsigned, 4 > scheduled
Definition: State.h:230
Slot(Time time)
Create a new empty slot.
Definition: State.h:207
bool operator<(const Slot &rhs) const
Returns true if the slot's time is smaller than the compared slot's time.
Definition: State.cpp:69
llvm::SmallVector< std::pair< unsigned, llvm::APInt >, 32 > buffers
Definition: State.h:225
The simulator's state.
Definition: State.h:306
llvm::SmallVector< Instance, 0 > instances
Definition: State.h:348
void pushQueue(Time time, unsigned inst)
Push a new scheduled wakeup event in the event queue.
Definition: State.cpp:224
llvm::SmallVector< Signal, 0 > signals
Definition: State.h:349
void dumpSignal(llvm::raw_ostream &out, int index)
Dump a signal to the out stream.
Definition: State.cpp:280
State()=default
Construct a new empty (at 0 time) state.
void dumpLayout()
Dump the instance layout. Used for testing purposes.
Definition: State.cpp:288
Slot popQueue()
Pop the head of the queue and update the simulation time.
Definition: State.cpp:217
void addProcPtr(std::string name, ProcState *procStatePtr)
Add a pointer to the process persistence state to a process instance.
Definition: State.cpp:246
llvm::SmallVectorTemplateCommon< Instance >::iterator getInstanceIterator(std::string instName)
Find an instance in the instances list by name and return an iterator for it.
Definition: State.cpp:231
std::string root
Definition: State.h:347
int addSignalData(int index, std::string owner, uint8_t *value, uint64_t size)
Definition: State.cpp:254
UpdateQueue queue
Definition: State.h:350
void dumpSignalTriggers()
Dump the instances each signal triggers. Used for testing purposes.
Definition: State.cpp:303
int addSignal(std::string name, std::string owner)
Add a new signal to the state. Returns the index of the new signal.
Definition: State.cpp:241
~State()
State destructor, ensures all malloc'd regions stored in the state are correctly free'd.
Definition: State.cpp:209
void addSignalElement(unsigned, unsigned, unsigned)
Definition: State.cpp:276