summaryrefslogtreecommitdiff
path: root/isa/isa.h
blob: 4083e16ca0ab31188b3716461759fc3f691f572e (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
#pragma once

#include <cstdint>
#include <functional>
#include <map>
#include <optional>
#include <string>

enum ctlreg {
#define REG(N) N,
#include "ctlreg.def"
#undef REG

    NUM_CTLREGS,
};

const char * const ctlreg_names[] = {
#define REG(N) #N,
#include "ctlreg.def"
#undef REG
};

const std::map<std::string, ctlreg> ctlreg_map = {
#define REG(N) { #N, N },
#include "ctlreg.def"
#undef REG
};

// FLAGS and FLAGS_SAVED
static constexpr unsigned int FLAG_DF_SHIFT = 0;
static constexpr std::uint_fast32_t FLAG_DF = 07 << FLAG_DF_SHIFT;
static constexpr unsigned int FLAG_IF_SHIFT = 3;
static constexpr std::uint_fast32_t FLAG_IF = 07 << FLAG_IF_SHIFT;  // In FLAGS this is IFB, not IF
static constexpr std::uint_fast32_t FLAG_USER_MODE = 1 << 6;
static constexpr std::uint_fast32_t FLAG_INT_ENABLE = 1 << 7;
static constexpr std::uint_fast32_t FLAG_INT_INHIBIT = 1 << 8;
static constexpr std::uint_fast32_t FLAG_INT_REQUEST = 1 << 9;
static constexpr std::uint_fast32_t FLAG_GREATER_THAN = 1 << 10;
static constexpr std::uint_fast32_t FLAG_INT_ENABLE_DELAY = 1 << 12;    // n.b. this is not a "visible" flag

// TT_BITS
static constexpr std::uint_fast32_t TTI_FLAG = 1 << 0;
static constexpr std::uint_fast32_t TTO_TX = 1 << 1;
static constexpr std::uint_fast32_t TTO_FLAG = 1 << 2;
static constexpr unsigned int TTI_DATA_SHIFT = 8;
static constexpr std::uint_fast32_t TTI_DATA = 0xff << TTI_DATA_SHIFT;
static constexpr unsigned int TTO_DATA_SHIFT = 16;
static constexpr std::uint_fast32_t TTO_DATA = 0xff << TTO_DATA_SHIFT;

// TT_FLAGS
static constexpr std::uint_fast32_t TTF_INT_ENABLE = 1 << 0;
static constexpr std::uint_fast32_t TTF_STATUS_ENABLE = 1 << 1;

static std::string opr_disasm_group1[0377];
static std::string opr_disasm_group2_pos[0366];
static std::string opr_disasm_group2_neg[0366];
static std::string opr_disasm_extended_arith[0376];

struct instruction_context {
    // Known statically at decode time
    bool need_indirect_load = false;    // final_address = mem[init_address]
    bool need_autoinc_store = false;    // mem[init_address] += 1
    bool need_exec_load = false;        // data = mem[final_address]
    bool need_read_acc = false;         // acc = %acc
    bool need_read_link = false;        // link = %link
    bool need_read_mq = false;          // mq = %mq
    std::optional<ctlreg> read_ctlreg;  // ctlval = %[read_ctlreg]
    bool need_write_acc = false;        // %acc = acc
    bool need_write_link = false;       // %link = link
    bool need_write_mq = false;         // %mq = mq
    std::optional<ctlreg> write_ctlreg; // %[write_ctlreg] = ctlval
    bool need_exec_store = false;       // mem[final_address] = data
    bool possibly_redirects = false;    // %pc = next_pc

    const char *df = nullptr;
    std::string disasm() const;

    std::function<void(instruction_context &ctx)> ef;
    void execute() { ef(*this); }

    // May change over the lifetime of the instruction execution
    unsigned int bits;
    unsigned int next_pc;                       // includes IF
    std::optional<unsigned int> init_address;   // includes DF
    std::optional<unsigned int> final_address;  // includes DF
    std::optional<std::uint_fast32_t> ctlval;   // control registers may be larger than 16 bits (e.g. TT_BITS)
    std::optional<unsigned int> data;
    std::optional<unsigned int> acc;
    std::optional<bool> link;
    std::optional<unsigned int> mq;
};

void init_disasm_tables();
instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned int bits, bool interrupt);