CIRCT  19.0.0git
Trace.cpp
Go to the documentation of this file.
1 //===- Trace.cpp - Simulation trace implementation ------------------------===//
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 // This file implements the Trace class, used to handle the signal trace
10 // generation for the llhd-sim tool.
11 //
12 //===----------------------------------------------------------------------===//
13 
15 
16 #include "llvm/Support/raw_ostream.h"
17 
18 using namespace circt::llhd::sim;
19 
20 Trace::Trace(std::unique_ptr<State> const &state, llvm::raw_ostream &out,
21  TraceMode mode)
22  : out(out), state(state), mode(mode) {
23  auto root = state->root;
24  for (auto &sig : state->signals) {
25  bool done = (mode != TraceMode::Full && mode != TraceMode::Merged &&
26  !sig.isOwner(root)) ||
27  (mode == TraceMode::NamedOnly && sig.isValidSigName());
28  isTraced.push_back(!done);
29  }
30 }
31 
32 //===----------------------------------------------------------------------===//
33 // Changes gathering methods
34 //===----------------------------------------------------------------------===//
35 
36 void Trace::pushChange(unsigned inst, unsigned sigIndex, int elem = -1) {
37  auto &sig = state->signals[sigIndex];
38  std::string valueDump;
39  std::string path;
40  llvm::raw_string_ostream ss(path);
41 
42  ss << state->instances[inst].path << '/' << sig.getName();
43 
44  if (elem >= 0) {
45  // Add element index to the hierarchical path.
46  ss << '[' << elem << ']';
47  // Get element value dump.
48  valueDump = sig.toHexString(elem);
49  } else {
50  // Get signal value dump.
51  valueDump = sig.toHexString();
52  }
53 
54  // Check wheter we have an actual change from last value.
55  auto lastValKey = std::make_pair(path, elem);
56  if (valueDump != lastValue[lastValKey]) {
57  changes.push_back(std::make_pair(path, valueDump));
58  lastValue[lastValKey] = valueDump;
59  }
60 }
61 
62 void Trace::pushAllChanges(unsigned inst, unsigned sigIndex) {
63  auto &sig = state->signals[sigIndex];
64  if (sig.hasElement()) {
65  // Push changes for all signal elements.
66  for (size_t i = 0, e = sig.getElementSize(); i < e; ++i) {
67  pushChange(inst, sigIndex, i);
68  }
69  } else {
70  // Push one change for the whole signal.
71  pushChange(inst, sigIndex);
72  }
73 }
74 
75 void Trace::addChange(unsigned sigIndex) {
76  currentTime = state->time;
77  if (isTraced[sigIndex]) {
78  if (mode == TraceMode::Full) {
79  auto &sig = state->signals[sigIndex];
80  // Add a change for each connected instance.
81  for (auto inst : sig.getTriggeredInstanceIndices()) {
82  pushAllChanges(inst, sigIndex);
83  }
84  } else if (mode == TraceMode::Reduced) {
85  // The root is always the last instance in the instances list.
86  pushAllChanges(state->instances.size() - 1, sigIndex);
87  } else if (mode == TraceMode::Merged || mode == TraceMode::MergedReduce ||
89  addChangeMerged(sigIndex);
90  }
91  }
92 }
93 
94 void Trace::addChangeMerged(unsigned sigIndex) {
95  auto &sig = state->signals[sigIndex];
96  if (sig.hasElement()) {
97  // Add a change for all sub-elements
98  for (size_t i = 0, e = sig.getElementSize(); i < e; ++i) {
99  auto valueDump = sig.toHexString(i);
100  mergedChanges[std::make_pair(sigIndex, i)] = valueDump;
101  }
102  } else {
103  // Add one change for the whole signal.
104  auto valueDump = sig.toHexString();
105  mergedChanges[std::make_pair(sigIndex, -1)] = valueDump;
106  }
107 }
108 
109 //===----------------------------------------------------------------------===//
110 // Flush methods
111 //===----------------------------------------------------------------------===//
112 
114  std::sort(changes.begin(), changes.end(),
115  [](std::pair<std::string, std::string> &lhs,
116  std::pair<std::string, std::string> &rhs) -> bool {
117  return lhs.first < rhs.first;
118  });
119 }
120 
121 void Trace::flush(bool force) {
123  flushFull();
126  if (state->time.getTime() > currentTime.getTime() || force)
127  flushMerged();
128 }
129 
131  if (changes.size() > 0) {
132  sortChanges();
133 
134  auto timeDump = currentTime.toString();
135  for (auto change : changes) {
136  out << timeDump << " " << change.first << " " << change.second << "\n";
137  }
138  changes.clear();
139  }
140 }
141 
143  // Move the merged changes to the changes vector for dumping.
144  for (auto elem : mergedChanges) {
145  auto sigIndex = elem.first.first;
146  auto sigElem = elem.first.second;
147  auto &sig = state->signals[sigIndex];
148  auto change = elem.second;
149 
150  if (mode == TraceMode::Merged) {
151  // Add the changes for all connected instances.
152  for (auto inst : sig.getTriggeredInstanceIndices()) {
153  pushChange(inst, sigIndex, sigElem);
154  }
155  } else {
156  // The root is always the last instance in the instances list.
157  pushChange(state->instances.size() - 1, sigIndex, sigElem);
158  }
159  }
160 
161  if (changes.size() > 0) {
162  sortChanges();
163 
164  // Flush the changes to output stream.
165  out << currentTime.getTime() << "ps\n";
166  for (auto change : changes) {
167  out << " " << change.first << " " << change.second << "\n";
168  }
169  mergedChanges.clear();
170  changes.clear();
171  }
172 }
uint64_t getTime() const
Definition: State.h:58
std::string toString() const
Get the stored time in a printable format.
Definition: State.cpp:28
std::vector< bool > isTraced
Definition: Trace.h:38
void flush(bool force=false)
Flush the changes buffer to the output stream.
Definition: Trace.cpp:121
void addChangeMerged(unsigned)
Add a merged change to the change buffer.
Definition: Trace.cpp:94
std::map< std::pair< std::string, int >, std::string > lastValue
Definition: Trace.h:44
void pushChange(unsigned inst, unsigned sigIndex, int elem)
Push one change to the changes vector.
Definition: Trace.cpp:36
TraceMode mode
Definition: Trace.h:35
void addChange(unsigned)
Add a value change to the trace changes buffer.
Definition: Trace.cpp:75
void flushFull()
Flush the changes buffer to the output stream with full format.
Definition: Trace.cpp:130
std::vector< std::pair< std::string, std::string > > changes
Definition: Trace.h:40
std::unique_ptr< State > const & state
Definition: Trace.h:34
void pushAllChanges(unsigned inst, unsigned sigIndex)
Push one change for each element of a signal if it is of a structured type, or the full signal otherw...
Definition: Trace.cpp:62
Trace(std::unique_ptr< State > const &state, llvm::raw_ostream &out, TraceMode mode)
Definition: Trace.cpp:20
void sortChanges()
Sorts the changes buffer lexicographically wrt. the hierarchical paths.
Definition: Trace.cpp:113
llvm::raw_ostream & out
Definition: Trace.h:33
std::map< std::pair< unsigned, int >, std::string > mergedChanges
Definition: Trace.h:42