blob: b97ac0176cfd80182573e1048c7b6c1863bfcfa7 [file] [log] [blame]
Zane Shelleya9b44342021-08-08 17:15:52 -05001#include <analyzer/ras-data/ras-data-parser.hpp>
2#include <util/data_file.hpp>
3#include <util/trace.hpp>
4
5#include <filesystem>
6#include <fstream>
7#include <string>
8
9namespace fs = std::filesystem;
10
11namespace analyzer
12{
13
14//------------------------------------------------------------------------------
15
16std::shared_ptr<Resolution>
Zane Shelley7698b302021-08-09 16:00:03 -050017 RasDataParser::getResolution(const libhei::Signature& i_signature)
Zane Shelleya9b44342021-08-08 17:15:52 -050018{
Zane Shelley7698b302021-08-09 16:00:03 -050019 const auto data = iv_dataFiles.at(i_signature.getChip().getType());
20
21 const auto action = parseSignature(data, i_signature);
22
23 return parseAction(data, action);
Zane Shelleya9b44342021-08-08 17:15:52 -050024}
25
26//------------------------------------------------------------------------------
27
28void RasDataParser::initDataFiles()
29{
30 iv_dataFiles.clear(); // initially empty
31
32 // Get the RAS data schema files from the package `schema` subdirectory.
33 fs::path schemaDir{PACKAGE_DIR "schema"};
Zane Shelleyee54c992021-08-08 17:46:48 -050034 auto schemaRegex = R"(ras-data-schema-v[0-9]{2}\.json)";
35 std::vector<fs::path> schemaPaths;
36 util::findFiles(schemaDir, schemaRegex, schemaPaths);
Zane Shelleya9b44342021-08-08 17:15:52 -050037
Zane Shelleyee54c992021-08-08 17:46:48 -050038 // Parse each of the schema files.
39 std::map<unsigned int, nlohmann::json> schemaFiles;
40 for (const auto& path : schemaPaths)
41 {
42 // Trace each data file for debug.
43 trace::inf("File found: path=%s", path.string().c_str());
Zane Shelleya9b44342021-08-08 17:15:52 -050044
Zane Shelleyee54c992021-08-08 17:46:48 -050045 // Open the file.
46 std::ifstream file{path};
47 assert(file.good()); // The file must be readable.
Zane Shelleya9b44342021-08-08 17:15:52 -050048
Zane Shelleyee54c992021-08-08 17:46:48 -050049 // Parse the JSON.
50 auto schema = nlohmann::json::parse(file);
Zane Shelleya9b44342021-08-08 17:15:52 -050051
Zane Shelleyee54c992021-08-08 17:46:48 -050052 // Get the schema version.
53 auto version = schema.at("version").get<unsigned int>();
54
55 // Keep track of the schemas.
56 auto ret = schemaFiles.emplace(version, schema);
57 assert(ret.second); // Should not have duplicate entries
58 }
59
60 // Get the RAS data files from the package `data` subdirectory.
Zane Shelleya9b44342021-08-08 17:15:52 -050061 fs::path dataDir{PACKAGE_DIR "ras-data"};
62 std::vector<fs::path> dataPaths;
63 util::findFiles(dataDir, R"(.*\.json)", dataPaths);
64
65 // Parse each of the data files.
66 for (const auto& path : dataPaths)
67 {
68 // Trace each data file for debug.
69 trace::inf("File found: path=%s", path.string().c_str());
70
71 // Open the file.
72 std::ifstream file{path};
73 assert(file.good()); // The file must be readable.
74
75 // Parse the JSON.
76 const auto data = nlohmann::json::parse(file);
77
Zane Shelleyee54c992021-08-08 17:46:48 -050078 // Get the data version.
79 auto version = data.at("version").get<unsigned int>();
80
81 // Get the schema for this file.
82 auto schema = schemaFiles.at(version);
83
Zane Shelleya9b44342021-08-08 17:15:52 -050084 // Validate the data against the schema.
85 assert(util::validateJson(schema, data));
86
87 // Get the chip model/EC level from the data. The value is currently
88 // stored as a string representation of the hex value. So it will have
89 // to be converted to an integer.
90 libhei::ChipType_t chipType =
91 std::stoul(data.at("model_ec").get<std::string>(), 0, 16);
92
93 // So far, so good. Add the entry.
94 auto ret = iv_dataFiles.emplace(chipType, data);
95 assert(ret.second); // Should not have duplicate entries
96 }
97}
98
99//------------------------------------------------------------------------------
100
Zane Shelley7698b302021-08-09 16:00:03 -0500101std::string RasDataParser::parseSignature(const nlohmann::json& i_data,
102 const libhei::Signature& i_signature)
103{
104 // Get the signature keys. All are hex (lower case) with no prefix.
105 char buf[5];
106 sprintf(buf, "%04x", i_signature.getId());
107 std::string id{buf};
108
109 sprintf(buf, "%02x", i_signature.getBit());
110 std::string bit{buf};
111
112 sprintf(buf, "%02x", i_signature.getInstance());
113 std::string inst{buf};
114
115 // Return the action.
116 return i_data.at("signatures").at(id).at(bit).at(inst).get<std::string>();
117}
118
119//------------------------------------------------------------------------------
120
Zane Shelley5d63cef2021-09-17 18:10:17 -0500121std::tuple<callout::BusType, std::string>
122 RasDataParser::parseBus(const nlohmann::json& i_data,
123 const std::string& i_name)
124{
125 auto bus = i_data.at("buses").at(i_name);
126
127 // clang-format off
128 static const std::map<std::string, callout::BusType> m =
129 {
130 {"SMP_BUS", callout::BusType::SMP_BUS},
131 {"OMI_BUS", callout::BusType::OMI_BUS},
132 };
133 // clang-format on
134
135 auto busType = m.at(bus.at("type").get<std::string>());
136
137 std::string unitPath{}; // default empty if unit does not exist
138 if (bus.contains("unit"))
139 {
140 unitPath = bus.at("unit").get<std::string>();
141 }
142
143 return std::make_tuple(busType, unitPath);
144}
145
146//------------------------------------------------------------------------------
147
Zane Shelley7698b302021-08-09 16:00:03 -0500148std::shared_ptr<Resolution>
149 RasDataParser::parseAction(const nlohmann::json& i_data,
150 const std::string& i_action)
151{
152 auto o_list = std::make_shared<ResolutionList>();
153
154 // This function will be called recursively and we want to prevent cyclic
155 // recursion.
156 static std::vector<std::string> stack;
157 assert(stack.end() == std::find(stack.begin(), stack.end(), i_action));
158 stack.push_back(i_action);
159
160 // Iterate the action list and apply the changes.
161 for (const auto& a : i_data.at("actions").at(i_action))
162 {
163 auto type = a.at("type").get<std::string>();
164
165 if ("action" == type)
166 {
167 auto name = a.at("name").get<std::string>();
168
169 o_list->push(parseAction(i_data, name));
170 }
171 else if ("callout_self" == type)
172 {
173 auto priority = a.at("priority").get<std::string>();
174 auto guard = a.at("guard").get<bool>();
175
Zane Shelleye4bfb472021-08-10 12:47:32 -0500176 std::string path{}; // Must be empty to callout the chip.
177
178 o_list->push(std::make_shared<HardwareCalloutResolution>(
179 path, getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500180 }
181 else if ("callout_unit" == type)
182 {
183 auto name = a.at("name").get<std::string>();
184 auto priority = a.at("priority").get<std::string>();
185 auto guard = a.at("guard").get<bool>();
186
Zane Shelleye4bfb472021-08-10 12:47:32 -0500187 auto path = i_data.at("units").at(name).get<std::string>();
188
189 o_list->push(std::make_shared<HardwareCalloutResolution>(
190 path, getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500191 }
192 else if ("callout_connected" == type)
193 {
194 auto name = a.at("name").get<std::string>();
195 auto priority = a.at("priority").get<std::string>();
196 auto guard = a.at("guard").get<bool>();
197
Zane Shelley5d63cef2021-09-17 18:10:17 -0500198 auto busData = parseBus(i_data, name);
199
200 o_list->push(std::make_shared<ConnectedCalloutResolution>(
201 std::get<0>(busData), std::get<1>(busData),
202 getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500203 }
204 else if ("callout_bus" == type)
205 {
Zane Shelley4757a7b2021-09-20 22:23:38 -0500206 auto name = a.at("name").get<std::string>();
207 auto priority = a.at("priority").get<std::string>();
208 auto guard = a.at("guard").get<bool>();
Zane Shelley7698b302021-08-09 16:00:03 -0500209
Zane Shelley4757a7b2021-09-20 22:23:38 -0500210 auto busData = parseBus(i_data, name);
211
212 o_list->push(std::make_shared<BusCalloutResolution>(
213 std::get<0>(busData), std::get<1>(busData),
214 getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500215 }
216 else if ("callout_clock" == type)
217 {
Zane Shelley84721d92021-09-08 13:30:27 -0500218 auto name = a.at("name").get<std::string>();
Zane Shelley7698b302021-08-09 16:00:03 -0500219 auto priority = a.at("priority").get<std::string>();
220 auto guard = a.at("guard").get<bool>();
221
Zane Shelley84721d92021-09-08 13:30:27 -0500222 // clang-format off
223 static const std::map<std::string, callout::ClockType> m =
224 {
225 {"OSC_REF_CLOCK_0", callout::ClockType::OSC_REF_CLOCK_0},
226 {"OSC_REF_CLOCK_1", callout::ClockType::OSC_REF_CLOCK_1},
227 };
228 // clang-format on
229
230 o_list->push(std::make_shared<ClockCalloutResolution>(
231 m.at(name), getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500232 }
233 else if ("callout_procedure" == type)
234 {
235 auto name = a.at("name").get<std::string>();
236 auto priority = a.at("priority").get<std::string>();
237
238 // clang-format off
Zane Shelleyc85716c2021-08-17 10:54:06 -0500239 static const std::map<std::string, callout::Procedure> m =
Zane Shelley7698b302021-08-09 16:00:03 -0500240 {
Zane Shelleyc85716c2021-08-17 10:54:06 -0500241 {"LEVEL2", callout::Procedure::NEXTLVL},
Zane Shelley7698b302021-08-09 16:00:03 -0500242 };
243 // clang-format on
244
245 o_list->push(std::make_shared<ProcedureCalloutResolution>(
246 m.at(name), getPriority(priority)));
247 }
248 else if ("callout_part" == type)
249 {
250 auto name = a.at("name").get<std::string>();
251 auto priority = a.at("priority").get<std::string>();
252
Zane Shelleya4134772022-01-10 17:22:44 -0600253 // clang-format off
254 static const std::map<std::string, callout::PartType> m =
255 {
256 {"PNOR", callout::PartType::PNOR},
257 };
258 // clang-format on
259
260 o_list->push(std::make_shared<PartCalloutResolution>(
261 m.at(name), getPriority(priority)));
Zane Shelley7698b302021-08-09 16:00:03 -0500262 }
263 else if ("plugin" == type)
264 {
265 auto name = a.at("name").get<std::string>();
Zane Shelleye13a9f92021-12-16 21:19:11 -0600266 auto inst = a.at("instance").get<unsigned int>();
Zane Shelley7698b302021-08-09 16:00:03 -0500267
Zane Shelleye13a9f92021-12-16 21:19:11 -0600268 o_list->push(std::make_shared<PluginResolution>(name, inst));
Zane Shelley7698b302021-08-09 16:00:03 -0500269 }
270 else
271 {
272 throw std::logic_error("Unsupported action type: " + type);
273 }
274 }
275
276 // Done with this action pop it off the stack.
277 stack.pop_back();
278
279 return o_list;
280}
281
282//------------------------------------------------------------------------------
283
Zane Shelleyc85716c2021-08-17 10:54:06 -0500284callout::Priority RasDataParser::getPriority(const std::string& i_priority)
Zane Shelley7698b302021-08-09 16:00:03 -0500285{
286 // clang-format off
Zane Shelleyc85716c2021-08-17 10:54:06 -0500287 static const std::map<std::string, callout::Priority> m =
Zane Shelley7698b302021-08-09 16:00:03 -0500288 {
Zane Shelleyc85716c2021-08-17 10:54:06 -0500289 {"HIGH", callout::Priority::HIGH},
290 {"MED", callout::Priority::MED},
291 {"MED_A", callout::Priority::MED_A},
292 {"MED_B", callout::Priority::MED_B},
293 {"MED_C", callout::Priority::MED_C},
294 {"LOW", callout::Priority::LOW},
Zane Shelley7698b302021-08-09 16:00:03 -0500295 };
296 // clang-format on
297
298 return m.at(i_priority);
299}
300
301//------------------------------------------------------------------------------
302
Zane Shelleya9b44342021-08-08 17:15:52 -0500303} // namespace analyzer