• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

CyberZHG / MIXAL / 20697838146

10 Jan 2021 08:00AM UTC coverage: 98.174% (-0.2%) from 98.385%
20697838146

push

github

CyberZHG
Add examples in 1.3.2

25 of 29 new or added lines in 4 files covered. (86.21%)

4 existing lines in 1 file now uncovered.

3548 of 3614 relevant lines covered (98.17%)

19275.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.31
/src/machine.cpp
1
#include <iostream>
2
#include <set>
3
#include <tuple>
4
#include <sstream>
5
#include <cassert>
6
#include "machine.h"
7
#include "parser.h"
8

9
namespace mixal {
10

11
Computer::Computer() :
225✔
12
      overflow(false), comparison(ComparisonIndicator::EQUAL), memory(),
900,225✔
13
      devices(NUM_IO_DEVICE, nullptr),
450✔
14
      _pseudoVarIndex(), _lineOffset(), _elapsed() {}
450✔
15

16
Register2& Computer::rI(const int index) {
44,040✔
17
    switch (index) {
44,040✔
18
    case 1: return rI1;
1,513✔
19
    case 2: return rI2;
11,843✔
20
    case 3: return rI3;
27,888✔
21
    case 4: return rI4;
1,165✔
22
    case 5: return rI5;
1,615✔
23
    case 6: return rI6;
15✔
24
    }
25
    throw RuntimeError(_lineOffset, "Invalid offset for index register: " + std::to_string(index));
1✔
26
}
27

28
Computer::~Computer() {
225✔
29
    for (size_t i = 0; i < devices.size(); ++i) {
4,950✔
30
        delete devices[i];
4,725✔
31
    }
32
}
225✔
33

34
const ComputerWord& Computer::memoryAt(const int16_t index) const {
1✔
35
    return memory[index];
1✔
36
}
37

38
ComputerWord& Computer::memoryAt(const int16_t index) {
1✔
39
    return memory[index];
1✔
40
}
41

42
void Computer::reset() {
×
43
    rA.reset();
×
44
    rX.reset();
×
45
    for (int i = 1; i <= NUM_INDEX_REGISTER; ++i) {
×
46
        rI(i).reset();
×
47
    }
48
    rJ.reset();
×
49
    overflow = false;
×
50
    comparison = ComparisonIndicator::EQUAL;
×
51
    for (int i = 0; i < NUM_MEMORY; ++i) {
×
52
        memory[i].reset();
×
53
    }
54
    for (size_t i = 0; i < NUM_IO_DEVICE; ++i) {
×
55
        devices[i] = nullptr;
×
56
    }
57
    _pseudoVarIndex = 0;
×
58
    _lineOffset = 0;
×
59
    _elapsed = 0;
×
60
    _constants.clear();
×
61
}
×
62

63
std::string Computer::getSingleLineSymbol() {
5✔
64
    std::string symbolName = getPseudoSymbolName();
5✔
65
    _constants[symbolName] = AtomicValue(_lineOffset);
5✔
66
    return symbolName;
10✔
67
}
5✔
68

69
void Computer::executeSingle() {
2✔
70
    executeSingle(memory[_lineOffset]);
2✔
71
}
2✔
72

73
void Computer::executeUntilSelfLoop() {
59✔
74
    int32_t lastOffset = _lineOffset;
59✔
75
    while (true) {
76
        if (_lineOffset < 0 || NUM_MEMORY <= _lineOffset) {
4,278✔
77
            throw RuntimeError(_lineOffset, "Invalid code line: " + std::to_string(_lineOffset));
1✔
78
        }
79
        executeSingle(memory[_lineOffset]);
4,277✔
80
        if (memory[_lineOffset].operation() != Instructions::JBUS
4,277✔
81
            && memory[_lineOffset].operation() != Instructions::JRED
4,277✔
82
            && lastOffset == _lineOffset) {
8,554✔
83
            break;
58✔
84
        }
85
        lastOffset = _lineOffset;
4,219✔
86
    }
87
    waitDevices();
58✔
88
}
58✔
89

90
void Computer::executeUntilHalt() {
16✔
91
    while (true) {
92
        if (_lineOffset < 0 || NUM_MEMORY <= _lineOffset) {
4,113✔
93
            throw RuntimeError(_lineOffset, "Invalid code line: " + std::to_string(_lineOffset));
1✔
94
        }
95
        if (memory[_lineOffset].operation() == Instructions::HLT &&
4,124✔
96
            memory[_lineOffset].field() == 2) {
12✔
97
            ++_lineOffset;
12✔
98
            break;
12✔
99
        }
100
        executeSingle(memory[_lineOffset]);
4,100✔
101
    }
102
    waitDevices();
12✔
103
}
12✔
104

105
void Computer::executeUntilHaltOrSelfLoop() {
2✔
106
    int32_t lastOffset = _lineOffset;
2✔
107
    while (true) {
108
        if (_lineOffset < 0 || NUM_MEMORY <= _lineOffset) {
71,679✔
NEW
109
            throw RuntimeError(_lineOffset, "Invalid code line: " + std::to_string(_lineOffset));
×
110
        }
111
        if (memory[_lineOffset].operation() == Instructions::HLT &&
72,180✔
112
            memory[_lineOffset].field() == 2) {
501✔
113
            ++_lineOffset;
1✔
114
            break;
1✔
115
        }
116
        executeSingle(memory[_lineOffset]);
71,678✔
117
        if (memory[_lineOffset].operation() != Instructions::JBUS
71,678✔
118
            && memory[_lineOffset].operation() != Instructions::JRED
71,678✔
119
            && lastOffset == _lineOffset) {
143,356✔
120
            break;
1✔
121
        }
122
        lastOffset = _lineOffset;
71,677✔
123
    }
124
    waitDevices();
2✔
125
}
2✔
126

127
void Computer::executeSingle(ParsedResult* instruction) {
67✔
128
    if (instruction->address.literalConstant() ||
133✔
129
        instruction->index.literalConstant() ||
133✔
130
        instruction->field.literalConstant()) {
66✔
131
        throw RuntimeError(_lineOffset, "Literal constant cannot be used in single execution");
3✔
132
    }
133
    if (instruction->parsedType == ParsedType::INSTRUCTION) {
66✔
134
        if (!instruction->evaluated()) {
48✔
135
            if (!instruction->evaluate(_constants)) {
10✔
136
                throw RuntimeError(_lineOffset, "Unresolved symbol found when trying to execute");
9✔
137
            }
138
        }
139
        executeSingle(instruction->word);
45✔
140
    } else if (instruction->parsedType == ParsedType::PSEUDO) {
18✔
141
        executeSinglePseudo(instruction);
18✔
142
    }
143
}
60✔
144

145
void Computer::executeSingle(const InstructionWord& instruction) {
80,209✔
146
    switch (instruction.operation()) {
80,209✔
147
    case Instructions::ADD:
13✔
148
        executeADD(instruction);
13✔
149
        break;
13✔
150
    case Instructions::SUB:
2✔
151
        executeSUB(instruction);
2✔
152
        break;
2✔
153
    case Instructions::MUL:
3✔
154
        executeMUL(instruction);
3✔
155
        break;
3✔
156
    case Instructions::DIV:
9,544✔
157
        executeDIV(instruction);
9,544✔
158
        break;
9,542✔
159
    case Instructions::HLT:
503✔
160
        switch (instruction.field()) {
503✔
161
        case 0: executeNUM(); break;
2✔
162
        case 1: executeCHAR(); break;
501✔
163
        }
164
        break;
503✔
165
    case Instructions::SLA:
30✔
166
        switch (instruction.field()) {
30✔
167
        case 0: executeSLA(instruction); break;
6✔
168
        case 1: executeSRA(instruction); break;
6✔
169
        case 2: executeSLAX(instruction); break;
5✔
170
        case 3: executeSRAX(instruction); break;
5✔
171
        case 4: executeSLC(instruction); break;
4✔
172
        case 5: executeSRC(instruction); break;
4✔
173
        }
174
        break;
30✔
175
    case Instructions::MOVE:
6✔
176
        executeMOVE(instruction);
6✔
177
        break;
6✔
178
    case Instructions::LDA:
555✔
179
        executeLD(instruction, &rA);
555✔
180
        break;
554✔
181
    case Instructions::LD1:
72✔
182
    case Instructions::LD2:
183
    case Instructions::LD3:
184
    case Instructions::LD4:
185
    case Instructions::LD5:
186
    case Instructions::LD6:
187
        executeLDi(instruction);
72✔
188
        break;
70✔
189
    case Instructions::LDX:
14✔
190
        executeLD(instruction, &rX);
14✔
191
        break;
13✔
192
    case Instructions::LDAN:
1✔
193
        executeLDN(instruction, &rA);
1✔
194
        break;
1✔
195
    case Instructions::LD1N:
6✔
196
    case Instructions::LD2N:
197
    case Instructions::LD3N:
198
    case Instructions::LD4N:
199
    case Instructions::LD5N:
200
    case Instructions::LD6N:
201
        executeLDiN(instruction);
6✔
202
        break;
6✔
203
    case Instructions::LDXN:
1✔
204
        executeLDN(instruction, &rX);
1✔
205
        break;
1✔
206
    case Instructions::STA:
5✔
207
        executeST(instruction, &rA);
5✔
208
        break;
4✔
209
    case Instructions::ST1:
505✔
210
    case Instructions::ST2:
211
    case Instructions::ST3:
212
    case Instructions::ST4:
213
    case Instructions::ST5:
214
    case Instructions::ST6:
215
        executeSTi(instruction);
505✔
216
        break;
505✔
217
    case Instructions::STX:
504✔
218
        executeST(instruction, &rX);
504✔
219
        break;
503✔
220
    case Instructions::STJ:
4✔
221
        executeSTJ(instruction);
4✔
222
        break;
4✔
223
    case Instructions::STZ:
1✔
224
        executeSTZ(instruction);
1✔
225
        break;
1✔
226
    case Instructions::JBUS:
80✔
227
        executeJBUS(instruction);
80✔
228
        break;
80✔
229
    case Instructions::IOC:
4✔
230
        executeIOC(instruction);
4✔
231
        break;
4✔
232
    case Instructions::IN:
6✔
233
        executeIN(instruction);
6✔
234
        break;
5✔
235
    case Instructions::OUT:
62✔
236
        executeOUT(instruction);
62✔
237
        break;
60✔
238
    case Instructions::JRED:
4✔
239
        executeJRED(instruction);
4✔
240
        break;
4✔
241
    case Instructions::JMP:
8,841✔
242
        switch (instruction.field()) {
8,841✔
243
        case 0: executeJMP(instruction); break;
564✔
244
        case 1: executeJSJ(instruction); break;
1✔
245
        case 2: executeJOV(instruction); break;
2✔
246
        case 3: executeJNOV(instruction); break;
2✔
247
        case 4: executeJL(instruction); break;
2✔
248
        case 5: executeJE(instruction); break;
2✔
249
        case 6: executeJG(instruction); break;
8,254✔
250
        case 7: executeJGE(instruction); break;
10✔
251
        case 8: executeJNE(instruction); break;
2✔
252
        case 9: executeJLE(instruction); break;
2✔
253
        }
254
        break;
8,841✔
255
    case Instructions::JAN:
12✔
256
        switch (instruction.field()) {
12✔
257
        case 0: executeJN(instruction, &rA); break;
2✔
258
        case 1: executeJZ(instruction, &rA); break;
2✔
259
        case 2: executeJP(instruction, &rA); break;
2✔
260
        case 3: executeJNN(instruction, &rA); break;
2✔
261
        case 4: executeJNZ(instruction, &rA); break;
2✔
262
        case 5: executeJNP(instruction, &rA); break;
2✔
263
        }
264
        break;
12✔
265
    case Instructions::J1N:
1,072✔
266
    case Instructions::J2N:
267
    case Instructions::J3N:
268
    case Instructions::J4N:
269
    case Instructions::J5N:
270
    case Instructions::J6N:
271
        switch (instruction.field()) {
1,072✔
272
        case 0: executeJiN(instruction); break;
52✔
273
        case 1: executeJiZ(instruction); break;
501✔
274
        case 2: executeJiP(instruction); break;
513✔
275
        case 3: executeJiNN(instruction); break;
2✔
276
        case 4: executeJiNZ(instruction); break;
2✔
277
        case 5: executeJiNP(instruction); break;
2✔
278
        }
279
        break;
1,072✔
280
    case Instructions::JXN:
9,550✔
281
        switch (instruction.field()) {
9,550✔
282
        case 0: executeJN(instruction, &rX); break;
2✔
283
        case 1: executeJZ(instruction, &rX); break;
9,540✔
284
        case 2: executeJP(instruction, &rX); break;
2✔
285
        case 3: executeJNN(instruction, &rX); break;
2✔
286
        case 4: executeJNZ(instruction, &rX); break;
2✔
287
        case 5: executeJNP(instruction, &rX); break;
2✔
288
        }
289
        break;
9,550✔
290
    case Instructions::INCA:
9,564✔
291
        switch (instruction.field()) {
9,564✔
292
        case 0: executeINC(instruction, &rA); break;
3✔
293
        case 1: executeDEC(instruction, &rA); break;
3✔
294
        case 2: executeENT(instruction, &rA); break;
9,556✔
295
        case 3: executeENN(instruction, &rA); break;
2✔
296
        }
297
        break;
9,564✔
298
    case Instructions::INC1:
13,411✔
299
    case Instructions::INC2:
300
    case Instructions::INC3:
301
    case Instructions::INC4:
302
    case Instructions::INC5:
303
    case Instructions::INC6:
304
        switch (instruction.field()) {
13,411✔
305
        case 0: executeINCi(instruction); break;
10,589✔
306
        case 1: executeDECi(instruction); break;
1,014✔
307
        case 2: executeENTi(instruction); break;
1,805✔
308
        case 3: executeENNi(instruction); break;
3✔
309
        }
310
        break;
13,411✔
311
    case Instructions::INCX:
9,554✔
312
        switch (instruction.field()) {
9,554✔
313
        case 0: executeINC(instruction, &rX); break;
3✔
314
        case 1: executeDEC(instruction, &rX); break;
3✔
315
        case 2: executeENT(instruction, &rX); break;
9,546✔
316
        case 3: executeENN(instruction, &rX); break;
2✔
317
        }
318
        break;
9,554✔
319
    case Instructions::CMPA:
8,274✔
320
        executeCMP(instruction, &rA);
8,274✔
321
        break;
8,274✔
322
    case Instructions::CMP1:
4✔
323
    case Instructions::CMP2:
324
    case Instructions::CMP3:
325
    case Instructions::CMP4:
326
    case Instructions::CMP5:
327
    case Instructions::CMP6:
328
        executeCMPi(instruction);
4✔
329
        break;
4✔
330
    case Instructions::CMPX:
2✔
331
        executeCMP(instruction, &rX);
2✔
332
        break;
2✔
333
    }
334
    ++_lineOffset;
80,198✔
335
    _elapsed += Instructions::getCost(static_cast<Instructions::Code>(instruction.operation()),
80,198✔
336
                                      instruction.field());
80,198✔
337
}
80,198✔
338

339
void Computer::executeSinglePseudo(ParsedResult* instruction) {
18✔
340
    switch (instruction->word.operation() + Instructions::PSEUDO) {
18✔
341
    case Instructions::EQU:
5✔
342
        executeEQU(instruction);
5✔
343
        break;
4✔
344
    case Instructions::ORIG:
9✔
345
        executeORIG(instruction);
9✔
346
        break;
8✔
347
    case Instructions::CON:
4✔
348
        executeCON(instruction);
4✔
349
        break;
3✔
350
    }
351
}
15✔
352

353
void Computer::loadCodes(const std::string& codes, bool addHalt) {
1✔
354
    std::vector<std::string> lines;
1✔
355
    std::string item;
1✔
356
    std::stringstream ss(codes);
1✔
357
    while (std::getline(ss, item, '\n')) {
13✔
358
        lines.emplace_back(item);
12✔
359
    }
360
    loadCodes(lines, addHalt);
1✔
361
}
1✔
362

363
void Computer::loadCodes(const std::vector<std::string>& codes, bool addHalt) {
83✔
364
    // Parse and save all the results and intermediate expressions
365
    std::vector<ParsedResult> results(codes.size());
83✔
366
    std::unordered_map<std::string, AtomicValue> evaluated;
83✔
367
    std::unordered_map<std::string, Expression*> expressions;
83✔
368
    std::vector<std::tuple<std::string, Expression, Expression>> constants;  // (name, address, value)
83✔
369
    std::string lineBase = getPseudoSymbolName();
83✔
370
    evaluated[lineBase] = AtomicValue(0);
83✔
371
    int32_t lineOffset = 0, endIndex = -1;
83✔
372
    for (size_t codeIndex = 0; codeIndex < codes.size(); ++codeIndex) {
579✔
373
        const auto& code = codes[codeIndex];
496✔
374
        auto& result = results[codeIndex];
496✔
375
        auto lineSymbol = getPseudoSymbolName();
496✔
376
        result = Parser::parseLine(code, lineSymbol, true);
496✔
377
        if (result.parsedType == ParsedType::PSEUDO) {
496✔
378
            int32_t operation = result.word.operation() + Instructions::PSEUDO;
115✔
379
            switch (operation) {
115✔
380
            case Instructions::EQU:
10✔
381
                expressions[result.rawLocation] = &result.address;
10✔
382
                break;
10✔
383
            case Instructions::ORIG:
88✔
384
                if (result.rawAddress.find('*') == std::string::npos) {
88✔
385
                    if (!result.rawLocation.empty()) {
87✔
386
                        expressions[result.rawLocation] = &result.address;
1✔
387
                    }
388
                } else {
389
                     // When there is a `*` in the address, the location should equal to
390
                     // the `*` value before the calculation.
391
                    result.location = Expression::getConstOffsetExpression(lineBase, lineOffset);
1✔
392
                    expressions[result.rawLocation] = &result.location;
1✔
393
                    expressions[lineSymbol] = &result.location;
1✔
394
                }
395
                lineBase = getPseudoSymbolName();
88✔
396
                expressions[lineBase] = &result.address;
88✔
397
                lineOffset = 0;
88✔
398
                break;
88✔
399
            case Instructions::CON:
15✔
400
            case Instructions::ALF:
401
                if (!result.rawLocation.empty()) {
15✔
402
                    lineSymbol = result.rawLocation;
5✔
403
                }
404
                constants.emplace_back(
15✔
405
                    lineSymbol,
406
                    Expression::getConstOffsetExpression(lineBase, lineOffset++),
15✔
407
                    result.address);
15✔
408
                break;
15✔
409
            case Instructions::END:
2✔
410
                endIndex = codeIndex;
2✔
411
                break;
2✔
412
            }
413
        } else if (result.parsedType == ParsedType::INSTRUCTION) {
381✔
414
            bool usedLineSymbol = !result.rawLocation.empty() ||
378✔
415
                                (!result.rawAddress.empty() && result.address.depends().contains(lineSymbol)) ||
269✔
416
                                (!result.rawIndex.empty() && result.index.depends().contains(lineSymbol)) ||
910✔
417
                                (!result.rawField.empty() && result.field.depends().contains(lineSymbol));
263✔
418
            result.location = Expression::getConstOffsetExpression(lineBase, lineOffset);
378✔
419
            if (!result.rawLocation.empty()) {
378✔
420
                if (!(Atomic::isLocalSymbol(result.rawLocation) && result.rawLocation[1] == 'H')) {
109✔
421
                    expressions[result.rawLocation] = &result.location;
98✔
422
                }
423
            } else if (usedLineSymbol) {
269✔
424
                result.rawLocation = lineSymbol;
6✔
425
            }
426
            expressions[lineSymbol] = &result.location;
378✔
427
            ++lineOffset;
378✔
428
        }
429
    }
496✔
430
    // Replace local symbols
431
    std::unordered_map<std::string, std::string> localSymbolMapping;
166✔
432
    for (auto& result : results) {
579✔
433
        if (!result.rawLocation.empty() && Atomic::isLocalSymbol(result.rawLocation) && result.rawLocation[1] == 'H') {
496✔
434
            auto lineSymbol = getPseudoSymbolName();
11✔
435
            result.rawLocation[1] = 'B';
11✔
436
            localSymbolMapping[result.rawLocation] = lineSymbol;
11✔
437
            result.rawLocation[1] = 'H';
11✔
438
            expressions[lineSymbol] = &result.location;
11✔
439
        }
11✔
440
        result.address.replaceSymbol(localSymbolMapping);
496✔
441
    }
442
    for (int i = static_cast<int>(results.size()) - 1; i >= 0; --i) {
579✔
443
        auto& result = results[i];
496✔
444
        if (!result.rawLocation.empty() && Atomic::isLocalSymbol(result.rawLocation) && result.rawLocation[1] == 'H') {
496✔
445
            auto lineSymbol = getPseudoSymbolName();
11✔
446
            result.rawLocation[1] = 'F';
11✔
447
            localSymbolMapping[result.rawLocation] = lineSymbol;
11✔
448
            result.rawLocation[1] = 'H';
11✔
449
            expressions[lineSymbol] = &result.location;
11✔
450
        }
11✔
451
        result.address.replaceSymbol(localSymbolMapping);
496✔
452
    }
453
    // Add halt
454
    if (addHalt) {
83✔
455
        auto lineSymbol = getPseudoSymbolName();
79✔
456
        auto haltCommand = Parser::parseLine("HLT", lineSymbol, false);
79✔
457
        constants.emplace_back(
79✔
458
            lineSymbol,
459
             Expression::getConstOffsetExpression(lineBase, lineOffset++),
158✔
460
             Expression::getConstExpression(AtomicValue(haltCommand.word.value())));
158✔
461
    }
79✔
462
    // Add expressions and literal constants
463
    for (auto& result : results) {
579✔
464
        if (!result.rawAddress.empty()) {
496✔
465
            if (result.address.literalConstant()) {
482✔
466
                auto lineSymbol = getPseudoSymbolName();
75✔
467
                constants.emplace_back(
75✔
468
                    lineSymbol,
469
                    Expression::getConstOffsetExpression(lineBase, lineOffset++),
75✔
470
                    result.address);
75✔
471
                result.address = Expression::getConstExpression(lineSymbol);
75✔
472
            }
75✔
473
            expressions[getPseudoSymbolName()] = &result.address;
482✔
474
        }
475
        if (!result.rawIndex.empty()) {
496✔
476
            expressions[getPseudoSymbolName()] = &result.index;
34✔
477
        }
478
        if (!result.rawField.empty()) {
496✔
479
            expressions[getPseudoSymbolName()] = &result.field;
40✔
480
        }
481
    }
482
    if (endIndex != -1) {
83✔
483
        auto lineSymbol = results[endIndex].rawLocation.empty() ? getPseudoSymbolName() : results[endIndex].rawLocation;
2✔
484
        constants.emplace_back(
2✔
485
            lineSymbol,
486
            Expression::getConstOffsetExpression(lineBase, lineOffset++),
2✔
487
            results[endIndex].address);
2✔
488
    }
2✔
489
    // Add collected constants to expressions
490
    for (auto& it : constants) {
254✔
491
        expressions[std::get<0>(it)] = &std::get<1>(it);
171✔
492
        expressions[getPseudoSymbolName()] = &std::get<2>(it);
171✔
493
    }
494
    // Try to solve all the expressions
495
    std::unordered_map<std::string, int> dependNums;
166✔
496
    std::unordered_map<std::string, std::unordered_set<std::string>> solves;
166✔
497
    std::set<std::pair<int, std::string>> tasks;
166✔
498
    for (auto& it : expressions) {
1,580✔
499
        dependNums[it.first] = static_cast<int>(it.second->depends().size());
1,497✔
500
        for (auto& depend : it.second->depends()) {
2,453✔
501
            solves[depend].insert(it.first);
956✔
502
            if (evaluated.contains(depend)) {
956✔
503
                --dependNums[it.first];
1✔
504
            }
505
        }
506
        tasks.insert({dependNums[it.first], it.first});
1,497✔
507
    }
508
    while (!tasks.empty()) {
1,578✔
509
        auto symbol = tasks.begin()->second;
1,496✔
510
        auto& expression = expressions[symbol];
1,496✔
511
        if (tasks.begin()->first != 0 || !expression->evaluate(evaluated)) {
1,496✔
512
            std::ostringstream oss;
1✔
513
            oss << "Unresolved symbol found while trying to calculate: ";
1✔
514
            oss << tasks.begin()->second << "=" << *expression;
1✔
515
            throw RuntimeError(0, oss.str());
1✔
516
        }
1✔
517
        evaluated[symbol] = expression->result();
1,495✔
518
        tasks.erase({0, symbol});
1,495✔
519
        for (const auto& solve : solves[symbol]) {
2,448✔
520
            tasks.erase({dependNums[solve], solve});
953✔
521
            tasks.insert({--dependNums[solve], solve});
953✔
522
        }
523
    }
1,496✔
524
    // Load constants to memory
525
    for (auto& it : constants) {
251✔
526
        int32_t location = std::get<1>(it).result().value;
170✔
527
        if (location < 0 || location >= NUM_MEMORY) {
170✔
528
            throw RuntimeError(location, "Location of the code is invalid: " + std::to_string(location));
1✔
529
        }
530
        memory[location].set(std::get<2>(it).result().value);
169✔
531
    }
532
    // Load results to memory
533
    _lineOffset = -1;
81✔
534
    for (auto& result : results) {
563✔
535
        if (result.parsedType == ParsedType::INSTRUCTION) {
483✔
536
            result.evaluate(evaluated);
367✔
537
            int32_t location = result.location.result().value;
367✔
538
            if (location < 0 || location >= NUM_MEMORY) {
367✔
539
                throw RuntimeError(location, "Location of the code is invalid: " + std::to_string(location));
1✔
540
            }
541
            if (_lineOffset == -1) {
366✔
542
                _lineOffset = location;
79✔
543
            }
544
            memory[location].set(result.word.negative,
1,830✔
545
                                 result.word.address(),
366✔
546
                                 result.word.index(),
366✔
547
                                 result.word.field(),
366✔
548
                                 result.word.operation());
366✔
549
        }
550
    }
551
    if (endIndex != -1) {
80✔
552
        results[endIndex].address.evaluate(evaluated);
2✔
553
        _lineOffset = results[endIndex].address.result().value;
2✔
554
    } else if (_lineOffset == -1) {
78✔
555
        _lineOffset = 0;
1✔
556
    }
557
}
95✔
558

559
std::string Computer::getPseudoSymbolName() {
1,581✔
560
    return "#" + std::to_string(_pseudoVarIndex++);
1,581✔
561
}
562

563
int32_t Computer::getIndexedAddress(const InstructionWord& instruction, bool checkRange) {
62,357✔
564
    int32_t offset = 0;
62,357✔
565
    if (instruction.index() != 0) {
62,357✔
566
        const auto& rIi = rI(instruction.index());
28,969✔
567
        offset = static_cast<int32_t>(rIi.value());
28,969✔
568
    }
569
    const int32_t address = static_cast<int32_t>(instruction.addressValue()) + offset;
62,357✔
570
    if (checkRange && !(0 <= address && address < NUM_MEMORY)) {
62,357✔
571
        throw RuntimeError(_lineOffset, "Invalid address in instruction '" + instruction.getBytesString() +
2✔
572
                                        "': " + std::to_string(address));
3✔
573
    }
574
    return address;
62,356✔
575
}
576

577
void Computer::copyToRegister5(const InstructionWord& instruction, const ComputerWord& word, Register5* reg) const {
26,693✔
578
    int32_t start = instruction.field() / 8;
26,693✔
579
    int32_t stop = instruction.field() % 8;
26,693✔
580
    reg->reset();
26,693✔
581
    if (start > stop || stop > 5) {
26,693✔
582
        throw RuntimeError(_lineOffset, "Invalid field value: ("
2✔
583
                                        + std::to_string(start) + ":" + std::to_string(stop) + ")");
2✔
584
    }
585
    if (start == 0) {
26,691✔
586
        reg->negative = word.negative;
26,673✔
587
        ++start;
26,673✔
588
    }
589
    for (int32_t i = stop, j = 5; i >= start; --i, --j) {
160,073✔
590
        reg->set(j, word[i]);
133,382✔
591
    }
592
}
26,691✔
593

594
void Computer::copyFromRegister5(const InstructionWord& instruction, const Register5& reg, ComputerWord* word) const {
1,019✔
595
    int32_t start = instruction.field() / 8;
1,019✔
596
    int32_t stop = instruction.field() % 8;
1,019✔
597
    if (start > stop || stop > 5) {
1,019✔
598
        throw RuntimeError(_lineOffset, "Invalid field value: ("
2✔
599
                                        + std::to_string(start) + ":" + std::to_string(stop) + ")");
2✔
600
    }
601
    if (start == 0) {
1,017✔
602
        word->negative = reg.negative;
509✔
603
        ++start;
509✔
604
    }
605
    for (int32_t i = stop, j = 5; i >= start; --i, --j) {
5,559✔
606
        word->set(i, reg[j]);
4,542✔
607
    }
608
}
1,017✔
609

610
void Computer::copyToRegister2(const InstructionWord& instruction, const ComputerWord& word, Register2* reg) const {
78✔
611
    int32_t start = instruction.field() / 8;
78✔
612
    int32_t stop = instruction.field() % 8;
78✔
613
    if (start > stop || stop > 5) {
78✔
614
        throw RuntimeError(_lineOffset, "Invalid field value: ("
2✔
615
                                        + std::to_string(start) + ":" + std::to_string(stop) + ")");
2✔
616
    }
617
    reg->reset();
76✔
618
    if (start == 0) {
76✔
619
        reg->negative = word.negative;
72✔
620
        ++start;
72✔
621
    }
622
    for (int32_t i = stop, j = 2; i >= start && j > 0; --i, --j) {
213✔
623
        reg->set(j, word[i]);
137✔
624
    }
625
}
76✔
626

627
/** Check whether the given value can be fitted into the given number of bytes.
628
 * 
629
 * Overflow will be triggered if the value can not be fitted into 5 bytes.
630
 * (Which means rI will not trigger overflow.)
631
 */
632
int32_t Computer::checkRange(int32_t value, const int bytes) {
13,438✔
633
    int32_t range = 1 << (6 * bytes);
13,438✔
634
    if (std::abs(value) >= range) {
13,438✔
635
        if (bytes == 5) {
13✔
636
            overflow = true;
9✔
637
        }
638
        value %= range;
13✔
639
    }
640
    return value;
13,438✔
641
}
642

643
uint8_t Computer::getAX(const int index) const {
190✔
644
    assert(1 <= index && index <= 10);
645
    return index <= 5 ? rA[index] : rX[index - 5];
190✔
646
}
647

648
void Computer::setAX(const int index, const uint8_t value) {
228✔
649
    assert(1 <= index && index <= 10);
650
    if (index <= 5) {
228✔
651
        rA[index] = value;
114✔
652
    } else {
653
        rX[index - 5] = value;
114✔
654
    }
655
}
228✔
656

657
};  // namespace mixal
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc