blob: f5c588d1f09ccb0931f473cd44dd40448c393bae [file] [log] [blame]
Zane Shelleydd69c962020-05-05 22:19:11 -05001#include <chip_data/hei_chip_data.hpp>
2#include <chip_data/hei_chip_data_stream.hpp>
Zane Shelleyf8c92f92020-05-16 10:17:16 -05003#include <register/hei_operator_register.hpp>
Zane Shelleyb9a8e762020-05-11 21:41:32 -05004#include <register/hei_scom_register.hpp>
Zane Shelleydd69c962020-05-05 22:19:11 -05005
6namespace libhei
7{
8
9//------------------------------------------------------------------------------
10
Zane Shelleydd69c962020-05-05 22:19:11 -050011using SectionKeyword_t = uint32_t;
12
Zane Shelleyb9a8e762020-05-11 21:41:32 -050013constexpr SectionKeyword_t KW_REGS = 0x52454753; // "REGS" ASCII
Zane Shelleydd69c962020-05-05 22:19:11 -050014constexpr SectionKeyword_t KW_NODE = 0x4e4f4445; // "NODE" ASCII
15constexpr SectionKeyword_t KW_ROOT = 0x524f4f54; // "ROOT" ASCII
16
17using Version_t = uint8_t;
18
19constexpr Version_t VERSION_1 = 0x01;
20
21//------------------------------------------------------------------------------
22
Zane Shelley4de8ff82020-05-14 15:39:01 -050023void __readRegister(ChipDataStream& io_stream, IsolationChip::Ptr& io_isoChip)
Zane Shelleyb9a8e762020-05-11 21:41:32 -050024{
25 // Read the register metadata.
26 RegisterId_t id;
27 RegisterType_t type;
28 RegisterAttributeFlags_t attr;
29 Instance_t numInsts;
30 io_stream >> id >> type >> attr >> numInsts;
31
32 // Must have at least one instance.
33 HEI_ASSERT(0 != numInsts);
34
Zane Shelley0165edc2020-05-11 22:28:29 -050035 for (unsigned int i = 0; i < numInsts; i++)
Zane Shelleyb9a8e762020-05-11 21:41:32 -050036 {
37 // Read the register instance metadata.
38 Instance_t inst;
39 io_stream >> inst;
40
41 // The address size is dependent on the register type.
42 if (REG_TYPE_SCOM == type)
43 {
44 uint32_t addr; // 4-byte address.
45 io_stream >> addr;
46
47 // Get this register from the flyweight factory.
48 auto& factory = Flyweight<const ScomRegister>::getSingleton();
Zane Shelley4de8ff82020-05-14 15:39:01 -050049 auto hwReg = factory.get(id, inst, attr, addr);
Zane Shelleyb9a8e762020-05-11 21:41:32 -050050
51 // Add this register to the isolation chip.
52 io_isoChip->addHardwareRegister(hwReg);
53 }
54 else if (REG_TYPE_ID_SCOM == type)
55 {
56 uint64_t addr; // 8-byte address.
57 io_stream >> addr;
58
59 // Get this register from the flyweight factory.
60 auto& factory = Flyweight<const IdScomRegister>::getSingleton();
Zane Shelley4de8ff82020-05-14 15:39:01 -050061 auto hwReg = factory.get(id, inst, attr, addr);
Zane Shelleyb9a8e762020-05-11 21:41:32 -050062
63 // Add this register to the isolation chip.
64 io_isoChip->addHardwareRegister(hwReg);
65 }
66 else
67 {
68 HEI_ASSERT(false); // Register type unsupported.
69 }
70 }
71}
72
73//------------------------------------------------------------------------------
74
Zane Shelleyf8c92f92020-05-16 10:17:16 -050075Register::ConstPtr __readExpr(ChipDataStream& io_stream,
76 const IsolationChip::Ptr& i_isoChip,
77 IsolationNode::Ptr& io_isoNode)
Zane Shelley0165edc2020-05-11 22:28:29 -050078{
Zane Shelleyf8c92f92020-05-16 10:17:16 -050079 Register::ConstPtr expr{};
80
Zane Shelley0165edc2020-05-11 22:28:29 -050081 uint8_t exprType;
82 io_stream >> exprType;
83 switch (exprType)
84 {
85 case 0x01: // register reference
86 {
87 RegisterId_t regId;
88 Instance_t regInst;
89 io_stream >> regId >> regInst;
Zane Shelley6eb61902020-05-15 22:25:58 -050090
91 // Find the hardware register that is stored in this isolation chip
92 // and add it to the list of capture registers. This ensures all
93 // registers referenced in the rules are are captured by default.
94 // Note that this will assert that the target register must exist in
95 // the isolation chip.
96 auto hwReg = i_isoChip->getHardwareRegister({regId, regInst});
97
98 // Add the register to the isolation node.
99 io_isoNode->addCaptureRegister(hwReg);
100
Zane Shelleyf8c92f92020-05-16 10:17:16 -0500101 // Simply return this register.
102 expr = hwReg;
103
Zane Shelley0165edc2020-05-11 22:28:29 -0500104 break;
105 }
106 case 0x02: // integer constant
107 {
Zane Shelleyf8c92f92020-05-16 10:17:16 -0500108 auto& factory = Flyweight<const ConstantRegister>::getSingleton();
109
Zane Shelley6eb61902020-05-15 22:25:58 -0500110 if (REG_TYPE_SCOM == io_isoNode->getRegisterType() ||
111 REG_TYPE_ID_SCOM == io_isoNode->getRegisterType())
Zane Shelley0165edc2020-05-11 22:28:29 -0500112 {
113 uint64_t constant; // 8-byte value
114 io_stream >> constant;
Zane Shelleyf8c92f92020-05-16 10:17:16 -0500115
116 // Create the constant register and put it in the flyweights.
117 expr = factory.get(constant);
Zane Shelley0165edc2020-05-11 22:28:29 -0500118 }
119 else
120 {
121 HEI_ASSERT(false); // register type unsupported
122 }
Zane Shelleyf8c92f92020-05-16 10:17:16 -0500123
Zane Shelley0165edc2020-05-11 22:28:29 -0500124 break;
125 }
126 case 0x10: // AND operation
127 {
Zane Shelleyf8c92f92020-05-16 10:17:16 -0500128 auto& factory = Flyweight<const AndRegister>::getSingleton();
129
Zane Shelley0165edc2020-05-11 22:28:29 -0500130 uint8_t numSubExpr;
131 io_stream >> numSubExpr;
Zane Shelleyf8c92f92020-05-16 10:17:16 -0500132
133 HEI_ASSERT(2 <= numSubExpr); // must be at least two
134
135 // Read the first two sub-expressions.
136 auto e1 = __readExpr(io_stream, i_isoChip, io_isoNode);
137 auto e2 = __readExpr(io_stream, i_isoChip, io_isoNode);
138 HEI_ASSERT(e1 && e2); // Cannot be null
139
140 // Create the AND register and put it in the flyweights.
141 expr = factory.get(e1, e2);
142
143 // Iterate any remaining expressions.
144 for (uint8_t i = 2; i < numSubExpr; i++)
Zane Shelley0165edc2020-05-11 22:28:29 -0500145 {
Zane Shelleyf8c92f92020-05-16 10:17:16 -0500146 // Read the next sub-expressions.
147 e2 = __readExpr(io_stream, i_isoChip, io_isoNode);
148 HEI_ASSERT(e2); // Cannot be null
149
150 // Create the AND register and put it in the flyweights.
151 expr = factory.get(expr, e2);
Zane Shelley0165edc2020-05-11 22:28:29 -0500152 }
Zane Shelleyf8c92f92020-05-16 10:17:16 -0500153
Zane Shelley0165edc2020-05-11 22:28:29 -0500154 break;
155 }
156 case 0x11: // OR operation
157 {
Zane Shelleyf8c92f92020-05-16 10:17:16 -0500158 auto& factory = Flyweight<const OrRegister>::getSingleton();
159
Zane Shelley0165edc2020-05-11 22:28:29 -0500160 uint8_t numSubExpr;
161 io_stream >> numSubExpr;
Zane Shelleyf8c92f92020-05-16 10:17:16 -0500162
163 HEI_ASSERT(2 <= numSubExpr); // must be at least two
164
165 // Read the first two sub-expressions.
166 auto e1 = __readExpr(io_stream, i_isoChip, io_isoNode);
167 auto e2 = __readExpr(io_stream, i_isoChip, io_isoNode);
168 HEI_ASSERT(e1 && e2); // Cannot be null
169
170 // Create the OR register and put it in the flyweights.
171 expr = factory.get(e1, e2);
172
173 // Iterate any remaining expressions.
174 for (uint8_t i = 2; i < numSubExpr; i++)
Zane Shelley0165edc2020-05-11 22:28:29 -0500175 {
Zane Shelleyf8c92f92020-05-16 10:17:16 -0500176 // Read the next sub-expressions.
177 e2 = __readExpr(io_stream, i_isoChip, io_isoNode);
178 HEI_ASSERT(e2); // Cannot be null
179
180 // Create the OR register and put it in the flyweights.
181 expr = factory.get(expr, e2);
Zane Shelley0165edc2020-05-11 22:28:29 -0500182 }
Zane Shelleyf8c92f92020-05-16 10:17:16 -0500183
Zane Shelley0165edc2020-05-11 22:28:29 -0500184 break;
185 }
186 case 0x12: // NOT operation
187 {
Zane Shelleyf8c92f92020-05-16 10:17:16 -0500188 auto& factory = Flyweight<const NotRegister>::getSingleton();
189
190 // Read the sub-expression
191 auto e = __readExpr(io_stream, i_isoChip, io_isoNode);
192 HEI_ASSERT(e); // Cannot be null
193
194 // Create the NOT register and put it in the flyweights.
195 expr = factory.get(e);
196
Zane Shelley0165edc2020-05-11 22:28:29 -0500197 break;
198 }
199 case 0x13: // left shift operation
200 {
Zane Shelleyf8c92f92020-05-16 10:17:16 -0500201 auto& factory = Flyweight<const LeftShiftRegister>::getSingleton();
202
Zane Shelley0165edc2020-05-11 22:28:29 -0500203 uint8_t shiftValue;
204 io_stream >> shiftValue;
Zane Shelleyf8c92f92020-05-16 10:17:16 -0500205
206 // Read the sub-expression
207 auto e = __readExpr(io_stream, i_isoChip, io_isoNode);
208 HEI_ASSERT(e); // Cannot be null
209
210 // Create the left shift register and put it in the flyweights.
211 expr = factory.get(e, shiftValue);
212
Zane Shelley0165edc2020-05-11 22:28:29 -0500213 break;
214 }
215 case 0x14: // right shift operation
216 {
Zane Shelleyf8c92f92020-05-16 10:17:16 -0500217 auto& factory = Flyweight<const RightShiftRegister>::getSingleton();
218
Zane Shelley0165edc2020-05-11 22:28:29 -0500219 uint8_t shiftValue;
220 io_stream >> shiftValue;
Zane Shelleyf8c92f92020-05-16 10:17:16 -0500221
222 // Read the sub-expression
223 auto e = __readExpr(io_stream, i_isoChip, io_isoNode);
224 HEI_ASSERT(e); // Cannot be null
225
226 // Create the right shift register and put it in the flyweights.
227 expr = factory.get(e, shiftValue);
228
Zane Shelley0165edc2020-05-11 22:28:29 -0500229 break;
230 }
231 default:
232 HEI_ASSERT(false); // unsupported expression type
233 }
Zane Shelleyf8c92f92020-05-16 10:17:16 -0500234
235 return expr;
Zane Shelley0165edc2020-05-11 22:28:29 -0500236}
237
238//------------------------------------------------------------------------------
239
Zane Shelleyf229d5f2020-05-17 21:13:41 -0500240using TmpChildNodeMap = std::map<BitPosition_t, IsolationNode::Key>;
241using TmpNodeData = std::pair<IsolationNode::Ptr, TmpChildNodeMap>;
242using TmpNodeMap = std::map<IsolationNode::Key, TmpNodeData>;
243
244void __readNode(ChipDataStream& io_stream, const IsolationChip::Ptr& i_isoChip,
245 TmpNodeMap& io_tmpNodeMap)
Zane Shelley0165edc2020-05-11 22:28:29 -0500246{
247 // Read the node metadata.
248 NodeId_t nodeId;
249 RegisterType_t regType;
250 Instance_t numInsts;
251 io_stream >> nodeId >> regType >> numInsts;
252
253 for (unsigned int i = 0; i < numInsts; i++)
254 {
255 // Read the node instance metadata.
256 Instance_t nodeInst;
257 uint8_t numCapRegs, numIsoRules, numChildNodes;
258 io_stream >> nodeInst >> numCapRegs >> numIsoRules >> numChildNodes;
259
Zane Shelleybcb43952021-07-08 22:13:57 -0500260 // It is possible to have rules defined and no child nodes, However, if
261 // there are no rules defined (FFDC-only node), there should not be
262 // any child nodes defined.
263 HEI_ASSERT(0 != numIsoRules || 0 == numChildNodes);
Zane Shelley6eb61902020-05-15 22:25:58 -0500264
265 // Allocate memory for this isolation node.
266 auto isoNode =
267 std::make_shared<IsolationNode>(nodeId, nodeInst, regType);
268
Zane Shelley0165edc2020-05-11 22:28:29 -0500269 // Add capture registers.
270 for (unsigned int j = 0; j < numCapRegs; j++)
271 {
Zane Shelley6eb61902020-05-15 22:25:58 -0500272 // Read the capture register metadata.
Zane Shelley0165edc2020-05-11 22:28:29 -0500273 RegisterId_t regId;
274 Instance_t regInst;
275 io_stream >> regId >> regInst;
Zane Shelley6eb61902020-05-15 22:25:58 -0500276
277 // Find the hardware register that is stored in this isolation chip
278 // and add it to the list of capture registers. Note that this will
279 // assert that the target register must exist in the isolation chip.
Zane Shelleyf229d5f2020-05-17 21:13:41 -0500280 auto hwReg = i_isoChip->getHardwareRegister({regId, regInst});
Zane Shelley6eb61902020-05-15 22:25:58 -0500281
282 // Add the register to the isolation node.
283 isoNode->addCaptureRegister(hwReg);
Zane Shelley0165edc2020-05-11 22:28:29 -0500284 }
285
286 // Add isolation rules.
287 for (unsigned int j = 0; j < numIsoRules; j++)
288 {
Zane Shelley6eb61902020-05-15 22:25:58 -0500289 // Read the rule metadata.
Zane Shelley0165edc2020-05-11 22:28:29 -0500290 AttentionType_t attnType;
291 io_stream >> attnType;
Zane Shelleyf8c92f92020-05-16 10:17:16 -0500292
293 // Read out the rule for this attention type.
Zane Shelleyf229d5f2020-05-17 21:13:41 -0500294 auto rule = __readExpr(io_stream, i_isoChip, isoNode);
Zane Shelleyf8c92f92020-05-16 10:17:16 -0500295 HEI_ASSERT(rule); // Cannot be null
296
297 // Add the rule to the isolation node.
298 isoNode->addRule(attnType, rule);
Zane Shelley0165edc2020-05-11 22:28:29 -0500299 }
300
Zane Shelleyf229d5f2020-05-17 21:13:41 -0500301 // At this point, we will need to read out the child node metadata.
302 // However, we can't look up the child nodes and add them to this
303 // isolation node yet because we are still in the process of parsing
304 // them out of the Chip Data File. Therefore, we'll save a temporary map
305 // containing the child node information which will be used to look up
306 // the actual node objects later.
307 TmpChildNodeMap cMap{};
Zane Shelley0165edc2020-05-11 22:28:29 -0500308 for (unsigned int j = 0; j < numChildNodes; j++)
309 {
Zane Shelley6eb61902020-05-15 22:25:58 -0500310 // Read the child node metadata.
Zane Shelley0165edc2020-05-11 22:28:29 -0500311 BitPosition_t bit;
Zane Shelleyd0659242020-05-15 23:02:29 -0500312 NodeId_t childId;
313 Instance_t childInst;
314 io_stream >> bit >> childId >> childInst;
Zane Shelleyf229d5f2020-05-17 21:13:41 -0500315
316 auto ret =
317 cMap.emplace(bit, IsolationNode::Key{childId, childInst});
318 HEI_ASSERT(ret.second); // Should not have duplicate entries
319 }
320
321 // Add this isolation node with the temporary child node map to the
322 // returned map of nodes.
323 auto ret = io_tmpNodeMap.emplace(IsolationNode::Key{nodeId, nodeInst},
324 TmpNodeData{isoNode, cMap});
325 HEI_ASSERT(ret.second); // Should not have duplicate entries
326 }
327}
328
329//------------------------------------------------------------------------------
330
331void __insertNodes(IsolationChip::Ptr& io_isoChip,
332 const TmpNodeMap& i_tmpNodeMap)
333{
334 for (const auto& n : i_tmpNodeMap)
335 {
336 const IsolationNode::Ptr& node = n.second.first;
337 const TmpChildNodeMap& childMap = n.second.second;
338
339 // Link the child nodes, if they exist.
340 for (const auto& c : childMap)
341 {
342 const BitPosition_t& bit = c.first;
343 const IsolationNode::Key& childKey = c.second;
344
345 // Find the child node in the temporary map.
346 auto itr = i_tmpNodeMap.find(childKey);
347 HEI_ASSERT(i_tmpNodeMap.end() != itr); // Child node must exist.
348
349 const IsolationNode::Ptr& child = itr->second.first;
350
351 node->addChild(bit, child);
Zane Shelley0165edc2020-05-11 22:28:29 -0500352 }
Zane Shelley6eb61902020-05-15 22:25:58 -0500353
354 // Add this node to the isolation chip.
Zane Shelleyf229d5f2020-05-17 21:13:41 -0500355 io_isoChip->addIsolationNode(node);
Zane Shelley0165edc2020-05-11 22:28:29 -0500356 }
357}
358
359//------------------------------------------------------------------------------
360
Zane Shelley4de8ff82020-05-14 15:39:01 -0500361void __readRoot(ChipDataStream& io_stream, IsolationChip::Ptr& io_isoChip)
Zane Shelley0165edc2020-05-11 22:28:29 -0500362{
Zane Shelley2467db82020-05-18 19:56:30 -0500363 // Read the root node metadata.
Zane Shelley0165edc2020-05-11 22:28:29 -0500364 AttentionType_t attnType;
365 NodeId_t id;
366 Instance_t inst;
367 io_stream >> attnType >> id >> inst;
Zane Shelley2467db82020-05-18 19:56:30 -0500368
369 // Add the root node.
370 io_isoChip->addRootNode(attnType, io_isoChip->getIsolationNode({id, inst}));
Zane Shelley0165edc2020-05-11 22:28:29 -0500371}
372
373//------------------------------------------------------------------------------
374
Zane Shelleydd69c962020-05-05 22:19:11 -0500375void parseChipDataFile(void* i_buffer, size_t i_bufferSize,
Zane Shelley4de8ff82020-05-14 15:39:01 -0500376 IsolationChip::Map& io_isoChips)
Zane Shelleydd69c962020-05-05 22:19:11 -0500377{
378 ChipDataStream stream{i_buffer, i_bufferSize};
379
380 // Read the file metadata.
Zane Shelleyb9a8e762020-05-11 21:41:32 -0500381 FileKeyword_t fileKeyword;
382 ChipType_t chipType;
383 Version_t version;
384 stream >> fileKeyword >> chipType >> version;
Zane Shelleydd69c962020-05-05 22:19:11 -0500385
Zane Shelleyb9a8e762020-05-11 21:41:32 -0500386 // Check the file keyword.
387 HEI_ASSERT(KW_CHIPDATA == fileKeyword);
Zane Shelleydd69c962020-05-05 22:19:11 -0500388
389 // This chip type should not already exist.
390 HEI_ASSERT(io_isoChips.end() == io_isoChips.find(chipType));
391
Zane Shelleyb9a8e762020-05-11 21:41:32 -0500392 // So far there is only one supported version type so check it here.
393 HEI_ASSERT(VERSION_1 == version);
394
Zane Shelleydd69c962020-05-05 22:19:11 -0500395 // Allocate memory for the new isolation chip.
396 auto isoChip = std::make_unique<IsolationChip>(chipType);
397
Zane Shelleyb9a8e762020-05-11 21:41:32 -0500398 // Read the register list metadata.
399 SectionKeyword_t regsKeyword;
400 RegisterId_t numRegs;
401 stream >> regsKeyword >> numRegs;
402
403 // Check the register keyword.
404 HEI_ASSERT(KW_REGS == regsKeyword);
405
406 // There must be at least one register defined.
407 HEI_ASSERT(0 != numRegs);
408
Zane Shelley0165edc2020-05-11 22:28:29 -0500409 for (unsigned int i = 0; i < numRegs; i++)
Zane Shelleyb9a8e762020-05-11 21:41:32 -0500410 {
411 __readRegister(stream, isoChip);
412 }
Zane Shelleydd69c962020-05-05 22:19:11 -0500413
Zane Shelley0165edc2020-05-11 22:28:29 -0500414 // Read the node list metadata.
415 SectionKeyword_t nodeKeyword;
416 NodeId_t numNodes;
417 stream >> nodeKeyword >> numNodes;
418
419 // Check the node keyword.
420 HEI_ASSERT(KW_NODE == nodeKeyword);
421
422 // There must be at least one node defined.
423 HEI_ASSERT(0 != numNodes);
424
Zane Shelleyf229d5f2020-05-17 21:13:41 -0500425 TmpNodeMap tmpNodeMap; // Stores all nodes with child node map.
Zane Shelley0165edc2020-05-11 22:28:29 -0500426 for (unsigned int i = 0; i < numNodes; i++)
427 {
Zane Shelleyf229d5f2020-05-17 21:13:41 -0500428 __readNode(stream, isoChip, tmpNodeMap);
Zane Shelley0165edc2020-05-11 22:28:29 -0500429 }
Zane Shelleyf229d5f2020-05-17 21:13:41 -0500430 // Link all nodes with their child nodes. Then add them to isoChip.
431 __insertNodes(isoChip, tmpNodeMap);
Zane Shelley0165edc2020-05-11 22:28:29 -0500432
433 // Read the root node list metadata.
434 SectionKeyword_t rootKeyword;
435 AttentionType_t numRoots;
436 stream >> rootKeyword >> numRoots;
437
438 // Check the root node keyword.
439 HEI_ASSERT(KW_ROOT == rootKeyword);
440
441 // There must be at least one register defined.
442 HEI_ASSERT(0 != numRoots);
443
444 for (unsigned int i = 0; i < numRoots; i++)
445 {
446 __readRoot(stream, isoChip);
447 }
448
449 // At this point, the stream is done and it should be at the end of the
450 // file.
451 HEI_ASSERT(stream.eof());
452
Zane Shelleydd69c962020-05-05 22:19:11 -0500453 // Add this isolation chip to the collective list of isolation chips.
454 auto ret = io_isoChips.emplace(chipType, std::move(isoChip));
455 HEI_ASSERT(ret.second); // Just in case.
456}
457
458//------------------------------------------------------------------------------
459
460} // namespace libhei