loom
402 строки · 16.2 Кб
1/*
2MIT License
3
4Copyright (c) 2022 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,
5
6https://bmstu.codes/lsx/simodo/loom
7*/
8
9#include "SystemVerilogSemantics_abstract.h"
10#include "simodo/interpret/AnalyzeException.h"
11#include "simodo/bormental/DrBormental.h"
12#include "simodo/inout/convert/functions.h"
13#include "simodo/inout/format/fmt.h"
14
15#include "simodo/interpret/StackOfNames.h"
16
17#include <limits>
18#include <cassert>
19#include <cmath>
20#include <float.h>
21
22using namespace simodo;
23
24namespace sv
25{
26SystemVerilogSemantics_abstract::SystemVerilogSemantics_abstract(interpret::ModuleManagement_interface & module_management)
27: _module_management(module_management)
28{
29}
30
31SystemVerilogSemantics_abstract::~SystemVerilogSemantics_abstract()
32{
33}
34
35void SystemVerilogSemantics_abstract::reset()
36{
37}
38
39interpret::InterpretState SystemVerilogSemantics_abstract::before_start()
40{
41return interpret::InterpretState::Flow;
42}
43
44interpret::InterpretState SystemVerilogSemantics_abstract::before_finish(interpret::InterpretState state)
45{
46return state;
47}
48
49bool SystemVerilogSemantics_abstract::isOperationExists(ast::OperationCode operation_code) const
50{
51SystemVerilogOperationCode operation = static_cast<SystemVerilogOperationCode>(operation_code);
52
53switch(operation)
54{
55case SystemVerilogOperationCode::None:
56case SystemVerilogOperationCode::PushConst:
57case SystemVerilogOperationCode::Assign:
58case SystemVerilogOperationCode::Equal:
59case SystemVerilogOperationCode::NotEqual:
60case SystemVerilogOperationCode::Less:
61case SystemVerilogOperationCode::LessOrEqual:
62case SystemVerilogOperationCode::More:
63case SystemVerilogOperationCode::MoreOrEqual:
64return true;
65default:
66return false;
67}
68}
69
70interpret::InterpretState SystemVerilogSemantics_abstract::performOperation(const ast::Node & op)
71{
72SystemVerilogOperationCode operation = static_cast<SystemVerilogOperationCode>(op.operation());
73
74switch(operation)
75{
76case SystemVerilogOperationCode::None:
77return executeNone();
78case SystemVerilogOperationCode::PushConst:
79return executePushConst(op);
80case SystemVerilogOperationCode::Assign:
81return executeAssign(op);
82case SystemVerilogOperationCode::Equal:
83case SystemVerilogOperationCode::NotEqual:
84case SystemVerilogOperationCode::Less:
85case SystemVerilogOperationCode::LessOrEqual:
86case SystemVerilogOperationCode::More:
87case SystemVerilogOperationCode::MoreOrEqual:
88return executeCompare(op);
89default:
90break;
91}
92
93throw bormental::DrBormental("SystemVerilogSemantics_abstract::performOperation",
94inout::fmt("Invalid operation index %1")
95.arg(op.operation()));
96}
97
98interpret::InterpretState SystemVerilogSemantics_abstract::executeNone()
99{
100return interpret::InterpretState::Flow;
101}
102
103interpret::InterpretState SystemVerilogSemantics_abstract::executePushConst(const simodo::ast::Node & op)
104{
105assert(_interpret);
106
107variable::Variable constant_variable;
108[[maybe_unused]] size_t index = 0;
109
110switch(op.token().type())
111{
112case inout::LexemeType::Annotation:
113constant_variable = { u"", op.token().lexeme(), op.token().location() };
114break;
115case inout::LexemeType::Number:
116{
117std::string number_string = inout::toU8(op.token().lexeme());
118if (number_string[0] != '\''){
119if (op.token().qualification() == inout::TokenQualification::Integer)
120constant_variable = { u"", static_cast<int64_t>(std::stoll(number_string)), op.token().location() };
121else
122constant_variable = { u"", std::stod(number_string), op.token().location() };
123break;
124}
125char type_of_number = number_string[1];
126number_string = number_string.substr(2);
127
128switch (type_of_number)
129{
130case 'b':
131constant_variable = { u"",
132static_cast<int64_t>(std::stoll(number_string,nullptr,2)),
133op.token().location() };
134break;
135case 'o':
136constant_variable = { u"",
137static_cast<int64_t>(std::stoll(inout::toU8(op.token().lexeme().substr(2)),nullptr,8)),
138op.token().location() };
139break;
140case 'h':
141constant_variable = { u"",
142static_cast<int64_t>(std::stoll(inout::toU8(op.token().lexeme().substr(2)),nullptr,16)),
143op.token().location() };
144break;
145
146default:
147throw bormental::DrBormental("SystemVerilogSemantics_abstract::executePushConstant",
148inout::fmt("Invalid internal type of constant to convert (%1)")
149.arg(getLexemeTypeName(op.token().type())));
150}
151break;
152}
153case inout::LexemeType::Punctuation:
154if (op.token().lexeme() == u"true" || op.token().lexeme() == u"false")
155constant_variable = { u"", op.token().lexeme() == u"true", op.token().location() };
156else if (op.token().lexeme() == u"null") {
157constant_variable = variable::null_variable(op.token().location());
158index = constant_variable.value().variant().index();
159}
160break;
161default:
162throw bormental::DrBormental("SystemVerilogSemantics_abstract::executePushConstant",
163inout::fmt("Invalid internal type of constant to convert (%1)")
164.arg(getLexemeTypeName(op.token().type())));
165}
166
167if (!op.branches().empty()) {
168std::vector<variable::Value> unit_parts;
169
170for(const ast::Node & n : op.branches())
171unit_parts.push_back(n.token().lexeme());
172
173constant_variable.spec().set(u"unit", unit_parts);
174}
175
176stack().push(constant_variable);
177
178return interpret::InterpretState::Flow;
179}
180
181interpret::InterpretState SystemVerilogSemantics_abstract::executeAssign(const simodo::ast::Node & )
182{
183assert(_interpret);
184
185interpret::name_index_t left = stack().top(1);
186interpret::name_index_t right = stack().top(0);
187
188variable::Variable & left_var = stack().variable(left).origin();
189const variable::Variable & right_var = stack().variable(right).origin();
190
191if (left_var.value().isArray() && right_var.type() == variable::ValueType::Int) {
192std::shared_ptr<variable::Array> array_variable = left_var.value().getArray();
193if (array_variable->dimensions().size() != 1)
194throw bormental::DrBormental("SystemVerilogSemantics_abstract::executeAssign",
195inout::fmt("Invalid internal type..."));
196variable::index_t size = array_variable->dimensions()[0];
197std::vector<variable::Value> array;
198int64_t var = right_var.value().getInt();
199
200for(variable::index_t i=0; i < size; ++i ) {
201array.push_back(var & 1);
202var >>= 1;
203}
204left_var.value() = array;
205}
206else
207left_var.value() = right_var.value().copy();
208
209stack().pop(2);
210
211return interpret::InterpretState::Flow;
212}
213
214interpret::InterpretState SystemVerilogSemantics_abstract::executeCompare(const ast::Node & op)
215{
216interpret::name_index_t top_name_index = stack().top();
217
218try
219{
220compare(static_cast<SystemVerilogOperationCode>(op.operation()), op.bound().location());
221}
222catch(...)
223{
224stack().pop(stack().top()+1-top_name_index);
225stack().variable(stack().top()) = variable::error_variable().copyVariable();
226throw;
227}
228
229return interpret::InterpretState::Flow;
230}
231
232void SystemVerilogSemantics_abstract::compare(SystemVerilogOperationCode opcode, const inout::TokenLocation & location)
233{
234variable::Variable & op1_origin = stack().variable(stack().top(1)).origin();
235variable::Variable & op2_origin = stack().variable(stack().top(0)).origin();
236
237if (op1_origin.value().isError() || op2_origin.value().isError()) {
238stack().pop(2);
239stack().push(variable::error_variable().copyVariable());
240return;
241}
242
243variable::ValueType target_type = getType4TypeConversion(opcode, op1_origin.type(), op2_origin.type());
244
245if (target_type == variable::ValueType::Null)
246throw interpret::AnalyzeException("ScriptSemantics_abstract::compare",
247location.makeLocation(inter().files()),
248inout::fmt("For operation %1, the use of types %2 and %3 is not provided")
249.arg(getSblOperationCodeName(opcode))
250.arg(getValueTypeName(op1_origin.type()))
251.arg(getValueTypeName(op2_origin.type())));
252
253variable::Variable op1 = inter().expr().convertVariable(op1_origin, target_type);
254variable::Variable op2 = inter().expr().convertVariable(op2_origin, target_type);
255variable::Value res;
256
257switch(opcode)
258{
259case SystemVerilogOperationCode::Equal:
260res = performCompareEqual(op1.value(), op2.value());
261break;
262case SystemVerilogOperationCode::NotEqual:
263res = !performCompareEqual(op1.value(), op2.value()).getBool();
264break;
265case SystemVerilogOperationCode::Less:
266res = performCompareLess(op1.value(), op2.value());
267break;
268case SystemVerilogOperationCode::LessOrEqual:
269res = performCompareLessOrEqual(op1.value(), op2.value());
270break;
271case SystemVerilogOperationCode::More:
272res = !performCompareLessOrEqual(op1.value(), op2.value()).getBool();
273break;
274case SystemVerilogOperationCode::MoreOrEqual:
275res = !performCompareLess(op1.value(), op2.value()).getBool();
276break;
277default:
278break;
279}
280
281if (res.type() == variable::ValueType::Null)
282throw interpret::AnalyzeException("ScriptSemantics_abstract::compare",
283location.makeLocation(inter().files()),
284inout::fmt("For operation %1, the use of types %2 and %3 is not provided")
285.arg(getSblOperationCodeName(opcode))
286.arg(getValueTypeName(op1.type()))
287.arg(getValueTypeName(op2.type())));
288
289stack().pop(2);
290stack().push({{}, res, location, {}});
291}
292
293variable::Value SystemVerilogSemantics_abstract::performCompareEqual(const variable::Value & op1, const variable::Value & op2) const
294{
295switch(op1.type())
296{
297case variable::ValueType::Bool:
298if (op1.variant().index() != std::variant_npos && op2.variant().index() != std::variant_npos)
299return op1.getBool() == op2.getBool();
300else
301return variable::ValueType::Bool;
302case variable::ValueType::Int:
303if (op1.variant().index() != std::variant_npos && op2.variant().index() != std::variant_npos)
304return op1.getInt() == op2.getInt();
305else
306return variable::ValueType::Bool;
307case variable::ValueType::Float:
308if (op1.variant().index() != std::variant_npos && op2.variant().index() != std::variant_npos)
309{
310double val1 = op1.getFloat();
311double val2 = op2.getFloat();
312
313// Учёт погрешности вычислений с плавающей точкой.
314// Машинный эпсилон (разница между 1.0 и следующим представимым значением для double)
315// должен быть масштабирован до величины используемых значений и умножен на желаемую
316// точность в ULP (единицы на последнем месте). ULP нужно подбирать в зависимсоти от
317// степени накапливаемой погрешности.
318/// \todo Подобрать оптимальное значение ULP
319return std::abs(val1 - val2) <= DBL_EPSILON * std::abs(val1+val2) * 2;
320}
321else
322return variable::ValueType::Bool;
323case variable::ValueType::String:
324if (op1.variant().index() != std::variant_npos && op2.variant().index() != std::variant_npos)
325return op1.getString() == op2.getString();
326else
327return variable::ValueType::Bool;
328default:
329break;
330}
331
332return {};
333}
334
335variable::Value SystemVerilogSemantics_abstract::performCompareLess(const variable::Value & op1, const variable::Value & op2) const
336{
337switch(op1.type())
338{
339case variable::ValueType::Int:
340if (op1.variant().index() != std::variant_npos && op2.variant().index() != std::variant_npos)
341return op1.getInt() < op2.getInt();
342else
343return variable::ValueType::Bool;
344case variable::ValueType::Float:
345if (op1.variant().index() != std::variant_npos && op2.variant().index() != std::variant_npos)
346return op1.getFloat() < op2.getFloat();
347else
348return variable::ValueType::Bool;
349case variable::ValueType::String:
350if (op1.variant().index() != std::variant_npos && op2.variant().index() != std::variant_npos)
351return op1.getString() < op2.getString();
352else
353return variable::ValueType::Bool;
354default:
355break;
356}
357
358return {};
359}
360
361variable::Value SystemVerilogSemantics_abstract::performCompareLessOrEqual(const variable::Value & op1, const variable::Value & op2) const
362{
363switch(op1.type())
364{
365case variable::ValueType::Int:
366if (op1.variant().index() != std::variant_npos && op2.variant().index() != std::variant_npos)
367return op1.getInt() <= op2.getInt();
368else
369return variable::ValueType::Bool;
370case variable::ValueType::Float:
371if (op1.variant().index() != std::variant_npos && op2.variant().index() != std::variant_npos)
372return op1.getFloat() <= op2.getFloat();
373else
374return variable::ValueType::Bool;
375case variable::ValueType::String:
376if (op1.variant().index() != std::variant_npos && op2.variant().index() != std::variant_npos)
377return op1.getString() <= op2.getString();
378else
379return variable::ValueType::Bool;
380default:
381break;
382}
383
384return {};
385}
386
387variable::ValueType SystemVerilogSemantics_abstract::getType4TypeConversion(SystemVerilogOperationCode /*opcode*/, variable::ValueType type1, variable::ValueType type2) const
388{
389if (type1 == type2)
390return type1;
391
392if ((type1 == variable::ValueType::Int && type2 == variable::ValueType::Float) ||
393(type1 == variable::ValueType::Float && type2 == variable::ValueType::Int))
394return variable::ValueType::Float;
395
396if (type1 == variable::ValueType::String || type2 == variable::ValueType::String)
397return variable::ValueType::String;
398
399return variable::ValueType::Null;
400}
401
402}