blob: 0c6198583c3e7602fe88c3d6e9d7fcaedebf65ed [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 Shelley6eb61902020-05-15 22:25:58 -0500260 // There must be at least one isolation rule defined.
261 HEI_ASSERT(0 != numIsoRules);
262
263 // Allocate memory for this isolation node.
264 auto isoNode =
265 std::make_shared<IsolationNode>(nodeId, nodeInst, regType);
266
Zane Shelley0165edc2020-05-11 22:28:29 -0500267 // Add capture registers.
268 for (unsigned int j = 0; j < numCapRegs; j++)
269 {
Zane Shelley6eb61902020-05-15 22:25:58 -0500270 // Read the capture register metadata.
Zane Shelley0165edc2020-05-11 22:28:29 -0500271 RegisterId_t regId;
272 Instance_t regInst;
273 io_stream >> regId >> regInst;
Zane Shelley6eb61902020-05-15 22:25:58 -0500274
275 // Find the hardware register that is stored in this isolation chip
276 // and add it to the list of capture registers. Note that this will
277 // assert that the target register must exist in the isolation chip.
Zane Shelleyf229d5f2020-05-17 21:13:41 -0500278 auto hwReg = i_isoChip->getHardwareRegister({regId, regInst});
Zane Shelley6eb61902020-05-15 22:25:58 -0500279
280 // Add the register to the isolation node.
281 isoNode->addCaptureRegister(hwReg);
Zane Shelley0165edc2020-05-11 22:28:29 -0500282 }
283
284 // Add isolation rules.
285 for (unsigned int j = 0; j < numIsoRules; j++)
286 {
Zane Shelley6eb61902020-05-15 22:25:58 -0500287 // Read the rule metadata.
Zane Shelley0165edc2020-05-11 22:28:29 -0500288 AttentionType_t attnType;
289 io_stream >> attnType;
Zane Shelleyf8c92f92020-05-16 10:17:16 -0500290
291 // Read out the rule for this attention type.
Zane Shelleyf229d5f2020-05-17 21:13:41 -0500292 auto rule = __readExpr(io_stream, i_isoChip, isoNode);
Zane Shelleyf8c92f92020-05-16 10:17:16 -0500293 HEI_ASSERT(rule); // Cannot be null
294
295 // Add the rule to the isolation node.
296 isoNode->addRule(attnType, rule);
Zane Shelley0165edc2020-05-11 22:28:29 -0500297 }
298
Zane Shelleyf229d5f2020-05-17 21:13:41 -0500299 // At this point, we will need to read out the child node metadata.
300 // However, we can't look up the child nodes and add them to this
301 // isolation node yet because we are still in the process of parsing
302 // them out of the Chip Data File. Therefore, we'll save a temporary map
303 // containing the child node information which will be used to look up
304 // the actual node objects later.
305 TmpChildNodeMap cMap{};
Zane Shelley0165edc2020-05-11 22:28:29 -0500306 for (unsigned int j = 0; j < numChildNodes; j++)
307 {
Zane Shelley6eb61902020-05-15 22:25:58 -0500308 // Read the child node metadata.
Zane Shelley0165edc2020-05-11 22:28:29 -0500309 BitPosition_t bit;
Zane Shelleyd0659242020-05-15 23:02:29 -0500310 NodeId_t childId;
311 Instance_t childInst;
312 io_stream >> bit >> childId >> childInst;
Zane Shelleyf229d5f2020-05-17 21:13:41 -0500313
314 auto ret =
315 cMap.emplace(bit, IsolationNode::Key{childId, childInst});
316 HEI_ASSERT(ret.second); // Should not have duplicate entries
317 }
318
319 // Add this isolation node with the temporary child node map to the
320 // returned map of nodes.
321 auto ret = io_tmpNodeMap.emplace(IsolationNode::Key{nodeId, nodeInst},
322 TmpNodeData{isoNode, cMap});
323 HEI_ASSERT(ret.second); // Should not have duplicate entries
324 }
325}
326
327//------------------------------------------------------------------------------
328
329void __insertNodes(IsolationChip::Ptr& io_isoChip,
330 const TmpNodeMap& i_tmpNodeMap)
331{
332 for (const auto& n : i_tmpNodeMap)
333 {
334 const IsolationNode::Ptr& node = n.second.first;
335 const TmpChildNodeMap& childMap = n.second.second;
336
337 // Link the child nodes, if they exist.
338 for (const auto& c : childMap)
339 {
340 const BitPosition_t& bit = c.first;
341 const IsolationNode::Key& childKey = c.second;
342
343 // Find the child node in the temporary map.
344 auto itr = i_tmpNodeMap.find(childKey);
345 HEI_ASSERT(i_tmpNodeMap.end() != itr); // Child node must exist.
346
347 const IsolationNode::Ptr& child = itr->second.first;
348
349 node->addChild(bit, child);
Zane Shelley0165edc2020-05-11 22:28:29 -0500350 }
Zane Shelley6eb61902020-05-15 22:25:58 -0500351
352 // Add this node to the isolation chip.
Zane Shelleyf229d5f2020-05-17 21:13:41 -0500353 io_isoChip->addIsolationNode(node);
Zane Shelley0165edc2020-05-11 22:28:29 -0500354 }
355}
356
357//------------------------------------------------------------------------------
358
Zane Shelley4de8ff82020-05-14 15:39:01 -0500359void __readRoot(ChipDataStream& io_stream, IsolationChip::Ptr& io_isoChip)
Zane Shelley0165edc2020-05-11 22:28:29 -0500360{
Zane Shelley2467db82020-05-18 19:56:30 -0500361 // Read the root node metadata.
Zane Shelley0165edc2020-05-11 22:28:29 -0500362 AttentionType_t attnType;
363 NodeId_t id;
364 Instance_t inst;
365 io_stream >> attnType >> id >> inst;
Zane Shelley2467db82020-05-18 19:56:30 -0500366
367 // Add the root node.
368 io_isoChip->addRootNode(attnType, io_isoChip->getIsolationNode({id, inst}));
Zane Shelley0165edc2020-05-11 22:28:29 -0500369}
370
371//------------------------------------------------------------------------------
372
Zane Shelleydd69c962020-05-05 22:19:11 -0500373void parseChipDataFile(void* i_buffer, size_t i_bufferSize,
Zane Shelley4de8ff82020-05-14 15:39:01 -0500374 IsolationChip::Map& io_isoChips)
Zane Shelleydd69c962020-05-05 22:19:11 -0500375{
376 ChipDataStream stream{i_buffer, i_bufferSize};
377
378 // Read the file metadata.
Zane Shelleyb9a8e762020-05-11 21:41:32 -0500379 FileKeyword_t fileKeyword;
380 ChipType_t chipType;
381 Version_t version;
382 stream >> fileKeyword >> chipType >> version;
Zane Shelleydd69c962020-05-05 22:19:11 -0500383
Zane Shelleyb9a8e762020-05-11 21:41:32 -0500384 // Check the file keyword.
385 HEI_ASSERT(KW_CHIPDATA == fileKeyword);
Zane Shelleydd69c962020-05-05 22:19:11 -0500386
387 // This chip type should not already exist.
388 HEI_ASSERT(io_isoChips.end() == io_isoChips.find(chipType));
389
Zane Shelleyb9a8e762020-05-11 21:41:32 -0500390 // So far there is only one supported version type so check it here.
391 HEI_ASSERT(VERSION_1 == version);
392
Zane Shelleydd69c962020-05-05 22:19:11 -0500393 // Allocate memory for the new isolation chip.
394 auto isoChip = std::make_unique<IsolationChip>(chipType);
395
Zane Shelleyb9a8e762020-05-11 21:41:32 -0500396 // Read the register list metadata.
397 SectionKeyword_t regsKeyword;
398 RegisterId_t numRegs;
399 stream >> regsKeyword >> numRegs;
400
401 // Check the register keyword.
402 HEI_ASSERT(KW_REGS == regsKeyword);
403
404 // There must be at least one register defined.
405 HEI_ASSERT(0 != numRegs);
406
Zane Shelley0165edc2020-05-11 22:28:29 -0500407 for (unsigned int i = 0; i < numRegs; i++)
Zane Shelleyb9a8e762020-05-11 21:41:32 -0500408 {
409 __readRegister(stream, isoChip);
410 }
Zane Shelleydd69c962020-05-05 22:19:11 -0500411
Zane Shelley0165edc2020-05-11 22:28:29 -0500412 // Read the node list metadata.
413 SectionKeyword_t nodeKeyword;
414 NodeId_t numNodes;
415 stream >> nodeKeyword >> numNodes;
416
417 // Check the node keyword.
418 HEI_ASSERT(KW_NODE == nodeKeyword);
419
420 // There must be at least one node defined.
421 HEI_ASSERT(0 != numNodes);
422
Zane Shelleyf229d5f2020-05-17 21:13:41 -0500423 TmpNodeMap tmpNodeMap; // Stores all nodes with child node map.
Zane Shelley0165edc2020-05-11 22:28:29 -0500424 for (unsigned int i = 0; i < numNodes; i++)
425 {
Zane Shelleyf229d5f2020-05-17 21:13:41 -0500426 __readNode(stream, isoChip, tmpNodeMap);
Zane Shelley0165edc2020-05-11 22:28:29 -0500427 }
Zane Shelleyf229d5f2020-05-17 21:13:41 -0500428 // Link all nodes with their child nodes. Then add them to isoChip.
429 __insertNodes(isoChip, tmpNodeMap);
Zane Shelley0165edc2020-05-11 22:28:29 -0500430
431 // Read the root node list metadata.
432 SectionKeyword_t rootKeyword;
433 AttentionType_t numRoots;
434 stream >> rootKeyword >> numRoots;
435
436 // Check the root node keyword.
437 HEI_ASSERT(KW_ROOT == rootKeyword);
438
439 // There must be at least one register defined.
440 HEI_ASSERT(0 != numRoots);
441
442 for (unsigned int i = 0; i < numRoots; i++)
443 {
444 __readRoot(stream, isoChip);
445 }
446
447 // At this point, the stream is done and it should be at the end of the
448 // file.
449 HEI_ASSERT(stream.eof());
450
Zane Shelleydd69c962020-05-05 22:19:11 -0500451 // Add this isolation chip to the collective list of isolation chips.
452 auto ret = io_isoChips.emplace(chipType, std::move(isoChip));
453 HEI_ASSERT(ret.second); // Just in case.
454}
455
456//------------------------------------------------------------------------------
457
458} // namespace libhei