loom

Форк
0
/
SystemVerilogSemantics_abstract.cpp 
402 строки · 16.2 Кб
1
/*
2
MIT License
3

4
Copyright (c) 2022 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,
5

6
https://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

22
using namespace simodo;
23

24
namespace sv
25
{
26
    SystemVerilogSemantics_abstract::SystemVerilogSemantics_abstract(interpret::ModuleManagement_interface & module_management)
27
        : _module_management(module_management)
28
    {
29
    }
30

31
    SystemVerilogSemantics_abstract::~SystemVerilogSemantics_abstract()
32
    {
33
    }
34

35
    void SystemVerilogSemantics_abstract::reset()
36
    {
37
    }
38

39
    interpret::InterpretState SystemVerilogSemantics_abstract::before_start() 
40
    { 
41
        return interpret::InterpretState::Flow; 
42
    }
43

44
    interpret::InterpretState SystemVerilogSemantics_abstract::before_finish(interpret::InterpretState state) 
45
    { 
46
        return state; 
47
    }
48

49
    bool SystemVerilogSemantics_abstract::isOperationExists(ast::OperationCode operation_code) const
50
    {
51
        SystemVerilogOperationCode operation = static_cast<SystemVerilogOperationCode>(operation_code);
52

53
        switch(operation)
54
        {
55
        case SystemVerilogOperationCode::None:
56
        case SystemVerilogOperationCode::PushConst:
57
        case SystemVerilogOperationCode::Assign:
58
        case SystemVerilogOperationCode::Equal:
59
        case SystemVerilogOperationCode::NotEqual:
60
        case SystemVerilogOperationCode::Less:
61
        case SystemVerilogOperationCode::LessOrEqual:
62
        case SystemVerilogOperationCode::More:
63
        case SystemVerilogOperationCode::MoreOrEqual:
64
            return true;
65
        default:
66
            return false;
67
        }
68
    }
69

70
    interpret::InterpretState SystemVerilogSemantics_abstract::performOperation(const ast::Node & op) 
71
    {
72
        SystemVerilogOperationCode operation = static_cast<SystemVerilogOperationCode>(op.operation());
73

74
        switch(operation)
75
        {
76
        case SystemVerilogOperationCode::None:
77
            return executeNone();
78
        case SystemVerilogOperationCode::PushConst:
79
            return executePushConst(op);
80
        case SystemVerilogOperationCode::Assign:
81
            return executeAssign(op);
82
        case SystemVerilogOperationCode::Equal:
83
        case SystemVerilogOperationCode::NotEqual:
84
        case SystemVerilogOperationCode::Less:
85
        case SystemVerilogOperationCode::LessOrEqual:
86
        case SystemVerilogOperationCode::More:
87
        case SystemVerilogOperationCode::MoreOrEqual:
88
            return executeCompare(op);
89
        default:
90
            break;
91
        }
92

93
        throw bormental::DrBormental("SystemVerilogSemantics_abstract::performOperation", 
94
                            inout::fmt("Invalid operation index %1")
95
                                .arg(op.operation()));
96
    }
97

98
    interpret::InterpretState SystemVerilogSemantics_abstract::executeNone()
99
    {
100
        return interpret::InterpretState::Flow;
101
    }
102

103
    interpret::InterpretState SystemVerilogSemantics_abstract::executePushConst(const simodo::ast::Node & op)
104
    {
105
        assert(_interpret);
106

107
        variable::Variable   constant_variable;
108
        [[maybe_unused]] size_t index = 0;
109
        
110
        switch(op.token().type())
111
        {
112
        case inout::LexemeType::Annotation:
113
            constant_variable = { u"", op.token().lexeme(), op.token().location() };
114
            break;
115
        case inout::LexemeType::Number:
116
        {
117
            std::string number_string = inout::toU8(op.token().lexeme());
118
            if (number_string[0] != '\''){
119
                if (op.token().qualification() == inout::TokenQualification::Integer)
120
                    constant_variable = { u"", static_cast<int64_t>(std::stoll(number_string)), op.token().location() };
121
                else
122
                    constant_variable = { u"", std::stod(number_string), op.token().location() };
123
                break;
124
            }
125
            char type_of_number = number_string[1];
126
            number_string = number_string.substr(2);
127

128
            switch (type_of_number)
129
            {
130
            case 'b':
131
                constant_variable = { u"", 
132
                        static_cast<int64_t>(std::stoll(number_string,nullptr,2)), 
133
                        op.token().location() };
134
                break;
135
            case 'o':
136
                constant_variable = { u"", 
137
                        static_cast<int64_t>(std::stoll(inout::toU8(op.token().lexeme().substr(2)),nullptr,8)), 
138
                        op.token().location() };
139
                break;
140
            case 'h':
141
                constant_variable = { u"", 
142
                        static_cast<int64_t>(std::stoll(inout::toU8(op.token().lexeme().substr(2)),nullptr,16)), 
143
                        op.token().location() };
144
                break;
145
            
146
            default:
147
                throw bormental::DrBormental("SystemVerilogSemantics_abstract::executePushConstant", 
148
                                        inout::fmt("Invalid internal type of constant to convert (%1)")
149
                                            .arg(getLexemeTypeName(op.token().type())));
150
            }
151
            break;
152
        }
153
        case inout::LexemeType::Punctuation:
154
            if (op.token().lexeme() == u"true" || op.token().lexeme() == u"false")
155
                constant_variable = { u"", op.token().lexeme() == u"true", op.token().location() };
156
            else if (op.token().lexeme() == u"null") {
157
                constant_variable = variable::null_variable(op.token().location());
158
                index = constant_variable.value().variant().index();
159
            }
160
            break;
161
        default:
162
            throw bormental::DrBormental("SystemVerilogSemantics_abstract::executePushConstant", 
163
                                        inout::fmt("Invalid internal type of constant to convert (%1)")
164
                                            .arg(getLexemeTypeName(op.token().type())));
165
        }
166

167
        if (!op.branches().empty()) {
168
            std::vector<variable::Value> unit_parts;
169

170
            for(const ast::Node & n : op.branches())
171
                unit_parts.push_back(n.token().lexeme());
172

173
            constant_variable.spec().set(u"unit", unit_parts);
174
        }
175

176
        stack().push(constant_variable);
177

178
        return interpret::InterpretState::Flow;
179
    }
180

181
    interpret::InterpretState SystemVerilogSemantics_abstract::executeAssign(const simodo::ast::Node & )
182
    {
183
        assert(_interpret);
184

185
        interpret::name_index_t left  = stack().top(1);
186
        interpret::name_index_t right = stack().top(0);
187

188
        variable::Variable & left_var        = stack().variable(left).origin();
189
        const variable::Variable & right_var = stack().variable(right).origin();
190

191
        if (left_var.value().isArray() && right_var.type() == variable::ValueType::Int) {
192
            std::shared_ptr<variable::Array> array_variable = left_var.value().getArray();
193
            if (array_variable->dimensions().size() != 1)
194
                throw bormental::DrBormental("SystemVerilogSemantics_abstract::executeAssign", 
195
                                            inout::fmt("Invalid internal type..."));
196
            variable::index_t            size = array_variable->dimensions()[0];
197
            std::vector<variable::Value> array;
198
            int64_t                      var = right_var.value().getInt();
199

200
            for(variable::index_t i=0; i < size; ++i ) {
201
                array.push_back(var & 1);
202
                var >>= 1;
203
            }
204
            left_var.value() = array;
205
        }
206
        else
207
            left_var.value() = right_var.value().copy();
208

209
        stack().pop(2);
210

211
        return interpret::InterpretState::Flow;
212
    }
213

214
    interpret::InterpretState SystemVerilogSemantics_abstract::executeCompare(const ast::Node & op)
215
    {
216
        interpret::name_index_t top_name_index = stack().top();
217

218
        try
219
        {
220
            compare(static_cast<SystemVerilogOperationCode>(op.operation()), op.bound().location());
221
        }
222
        catch(...)
223
        {
224
            stack().pop(stack().top()+1-top_name_index);
225
            stack().variable(stack().top()) = variable::error_variable().copyVariable();
226
            throw;
227
        }
228

229
        return interpret::InterpretState::Flow;
230
    }
231

232
    void SystemVerilogSemantics_abstract::compare(SystemVerilogOperationCode opcode, const inout::TokenLocation & location)
233
    {
234
        variable::Variable & op1_origin = stack().variable(stack().top(1)).origin();
235
        variable::Variable & op2_origin = stack().variable(stack().top(0)).origin();
236

237
        if (op1_origin.value().isError() || op2_origin.value().isError()) {
238
            stack().pop(2);
239
            stack().push(variable::error_variable().copyVariable());
240
            return;
241
        }
242

243
        variable::ValueType target_type = getType4TypeConversion(opcode, op1_origin.type(), op2_origin.type());
244

245
        if (target_type == variable::ValueType::Null)
246
            throw interpret::AnalyzeException("ScriptSemantics_abstract::compare", 
247
                                    location.makeLocation(inter().files()), 
248
                                    inout::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

253
        variable::Variable  op1 = inter().expr().convertVariable(op1_origin, target_type);
254
        variable::Variable  op2 = inter().expr().convertVariable(op2_origin, target_type);
255
        variable::Value     res;
256

257
        switch(opcode)
258
        {
259
        case SystemVerilogOperationCode::Equal:
260
            res = performCompareEqual(op1.value(), op2.value());
261
            break;
262
        case SystemVerilogOperationCode::NotEqual:
263
            res = !performCompareEqual(op1.value(), op2.value()).getBool();
264
            break;
265
        case SystemVerilogOperationCode::Less:
266
            res = performCompareLess(op1.value(), op2.value());
267
            break;
268
        case SystemVerilogOperationCode::LessOrEqual:
269
            res = performCompareLessOrEqual(op1.value(), op2.value());
270
            break;
271
        case SystemVerilogOperationCode::More:
272
            res = !performCompareLessOrEqual(op1.value(), op2.value()).getBool();
273
            break;
274
        case SystemVerilogOperationCode::MoreOrEqual:
275
            res = !performCompareLess(op1.value(), op2.value()).getBool();
276
            break;
277
        default:
278
            break;
279
        }
280

281
        if (res.type() == variable::ValueType::Null)
282
            throw interpret::AnalyzeException("ScriptSemantics_abstract::compare", 
283
                                    location.makeLocation(inter().files()), 
284
                                    inout::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

289
        stack().pop(2);
290
        stack().push({{}, res, location, {}});
291
    }
292

293
    variable::Value SystemVerilogSemantics_abstract::performCompareEqual(const variable::Value & op1, const variable::Value & op2) const
294
    {
295
        switch(op1.type())
296
        {
297
        case variable::ValueType::Bool:
298
            if (op1.variant().index() != std::variant_npos && op2.variant().index() != std::variant_npos)
299
                return op1.getBool() == op2.getBool();
300
            else
301
                return variable::ValueType::Bool;
302
        case variable::ValueType::Int:
303
            if (op1.variant().index() != std::variant_npos && op2.variant().index() != std::variant_npos)
304
                return op1.getInt() == op2.getInt();
305
            else
306
                return variable::ValueType::Bool;
307
        case variable::ValueType::Float:
308
            if (op1.variant().index() != std::variant_npos && op2.variant().index() != std::variant_npos)
309
            {
310
                double val1 = op1.getFloat();
311
                double val2 = op2.getFloat();
312

313
                // Учёт погрешности вычислений с плавающей точкой.
314
                // Машинный эпсилон (разница между 1.0 и следующим представимым значением для double)
315
                // должен быть масштабирован до величины используемых значений и умножен на желаемую
316
                // точность в ULP (единицы на последнем месте). ULP нужно подбирать в зависимсоти от
317
                // степени накапливаемой погрешности.
318
                /// \todo Подобрать оптимальное значение ULP
319
                return std::abs(val1 - val2) <= DBL_EPSILON * std::abs(val1+val2) * 2;
320
            }
321
            else
322
                return variable::ValueType::Bool;
323
        case variable::ValueType::String:
324
            if (op1.variant().index() != std::variant_npos && op2.variant().index() != std::variant_npos)
325
                return op1.getString() == op2.getString();
326
            else
327
                return variable::ValueType::Bool;
328
        default:
329
            break;
330
        }
331

332
        return {};
333
    }
334

335
    variable::Value SystemVerilogSemantics_abstract::performCompareLess(const variable::Value & op1, const variable::Value & op2) const
336
    {
337
        switch(op1.type())
338
        {
339
        case variable::ValueType::Int:
340
            if (op1.variant().index() != std::variant_npos && op2.variant().index() != std::variant_npos)
341
                return op1.getInt() < op2.getInt();
342
            else
343
                return variable::ValueType::Bool;
344
        case variable::ValueType::Float:
345
            if (op1.variant().index() != std::variant_npos && op2.variant().index() != std::variant_npos)
346
                return op1.getFloat() < op2.getFloat();
347
            else
348
                return variable::ValueType::Bool;
349
        case variable::ValueType::String:
350
            if (op1.variant().index() != std::variant_npos && op2.variant().index() != std::variant_npos)
351
                return op1.getString() < op2.getString();
352
            else
353
                return variable::ValueType::Bool;
354
        default:
355
            break;
356
        }
357

358
        return {};
359
    }
360

361
    variable::Value SystemVerilogSemantics_abstract::performCompareLessOrEqual(const variable::Value & op1, const variable::Value & op2) const
362
    {
363
        switch(op1.type())
364
        {
365
        case variable::ValueType::Int:
366
            if (op1.variant().index() != std::variant_npos && op2.variant().index() != std::variant_npos)
367
                return op1.getInt() <= op2.getInt();
368
            else
369
                return variable::ValueType::Bool;
370
        case variable::ValueType::Float:
371
            if (op1.variant().index() != std::variant_npos && op2.variant().index() != std::variant_npos)
372
                return op1.getFloat() <= op2.getFloat();
373
            else
374
                return variable::ValueType::Bool;
375
        case variable::ValueType::String:
376
            if (op1.variant().index() != std::variant_npos && op2.variant().index() != std::variant_npos)
377
                return op1.getString() <= op2.getString();
378
            else
379
                return variable::ValueType::Bool;
380
        default:
381
            break;
382
        }
383

384
        return {};
385
    }
386

387
    variable::ValueType SystemVerilogSemantics_abstract::getType4TypeConversion(SystemVerilogOperationCode /*opcode*/, variable::ValueType type1, variable::ValueType type2) const
388
    {
389
        if (type1 == type2)
390
            return type1;
391

392
        if ((type1 == variable::ValueType::Int && type2 == variable::ValueType::Float) ||
393
            (type1 == variable::ValueType::Float && type2 == variable::ValueType::Int))
394
            return variable::ValueType::Float;
395

396
        if (type1 == variable::ValueType::String || type2 == variable::ValueType::String)
397
            return variable::ValueType::String;
398

399
        return variable::ValueType::Null;
400
    }
401

402
}

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.