summaryrefslogtreecommitdiff
path: root/isa/decode.cpp
blob: 8a85d413a0cd0e3bf84b1eece7fabfa54a0b3948 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <cassert>

#include "isa/isa.h"

instruction_context decode(unsigned int dfifb, unsigned int pc, unsigned int bits)
{
    instruction_context inst;

    auto df = dfifb >> 3;
    auto ifb = dfifb & 00007;

    inst.next_pc = (pc & ~07777) | ((pc + 1) & 07777);

    switch (bits >> 9) {
        case 0: // AND
            inst.need_exec_load = true;
            inst.need_read_acc = true;
            inst.need_write_acc = true;
            inst.ef = [](auto &ctx) {
                ctx.acc = ctx.acc.value() & ctx.data.value();
            };
            break;
        case 1: // TAD
            inst.need_exec_load = true;
            inst.need_read_acc = true;
            inst.need_read_link = true;
            inst.need_write_acc = true;
            inst.need_write_link = true;
            inst.ef = [](auto &ctx) {
                unsigned int sum = (ctx.link.value() << 12) + ctx.acc.value() + ctx.data.value();
                ctx.link = (sum >> 12) & 1;
                ctx.acc = sum & 07777;
            };
            break;
        case 2: // ISZ
            inst.need_exec_load = true;
            inst.need_exec_store = true;
            inst.possibly_redirects = true;
            inst.ef = [](auto &ctx) {
                ctx.data = (ctx.data.value() + 1) & 07777;
                if (*ctx.data)
                    ctx.next_pc = (ctx.next_pc & ~07777) | ((ctx.next_pc + 1) & 07777);
            };
            break;
        case 3: // DCA
            inst.need_read_acc = true;
            inst.need_write_acc = true;
            inst.need_exec_store = true;
            inst.ef = [](auto &ctx) {
                ctx.data = ctx.acc.value();
                ctx.acc = 0;
            };
            break;
        case 4: // JMS
            inst.need_exec_store = true;
            inst.possibly_redirects = true;
            inst.ef = [ifb](auto &ctx) {
                ctx.data = ctx.next_pc;
                ctx.next_pc = (ifb << 12) | ((ctx.final_address.value() + 1) & 07777);
            };
            break;
        case 5: // JMP
            inst.possibly_redirects = true;
            inst.ef = [ifb](auto &ctx) {
                ctx.next_pc = (ifb << 12) | (ctx.final_address.value() & 07777);
            };
            break;
        case 6: // IOT
            inst.ef = [bits](auto &ctx) {
                assert(false);
            };
            break;
        case 7: // OPR
            inst.ef = [bits](auto &ctx) {
                assert(false);
            };
            break;
    }

    // Instructions with memory operands may be direct or indirect
    if (inst.need_exec_load || inst.need_exec_store || inst.possibly_redirects) {
        auto addr = (df << 12) | ((bits & 00200) ? (next_pc & 07600) : 0) | (bits & 00177);
        if (bits & 00400) {
            inst.need_indirect_load = true;
            inst.init_address = addr;
        } else {
            inst.final_address = addr;
        }
    }

    // Non-jump indirect memory operands may be autoincrementing depending on operand bits
    if (!inst.possibly_redirects && inst.need_indirect_load && ((bits & 00170) == 00010))
        inst.need_autoinc_store = true;

    return inst;
}