kulp / tenyr
1
#include "sim.h"
2
#include "common.h"
3

4
#include <stdlib.h>
5

6 1
static void do_op(enum op op, int type, int32_t *rhs, int32_t X, int32_t Y,
7
        int32_t I)
8
{
9 1
    int32_t p[3] = { 0 };
10
    // The `type` determines which position the immediate has
11 1
    switch (type) {
12 1
        case 0:
13
        case 1:
14
        case 2:
15 1
            p[type] = SEXTEND32(SMALL_IMMEDIATE_BITWIDTH, I);
16 1
            p[2 - (type > 1)] = X;
17 1
            p[1 - (type > 0)] = Y;
18 1
            break;
19 1
        case 3:
20 1
            p[0] = SEXTEND32(MEDIUM_IMMEDIATE_BITWIDTH, I);
21 1
            p[1] = X;
22 1
            p[2] = 0;
23 1
            break;
24
    }
25

26
    #define Ps(x) ((( int32_t*)p)[x])
27
    #define Pu(x) (((uint32_t*)p)[x])
28
    #define Sh(Lv,Op,Ri) (int32_t)((Pu(Ri)) < 32 ? (Lv) Op (Pu(Ri)) : ((Lv) Op 31) Op 1)
29 1
    int32_t pack2 = (int32_t)(Pu(2) << 12);
30 1
    int32_t pack1 = (int32_t)(Pu(1) & 0xfff);
31 1
    int32_t pack0 = (int32_t)(Ps(0));
32 1
    int32_t mask  = (int32_t)((Pu(1) < 32) ? (1ull << Pu(1)) : 0);
33

34
    // This switch is exhaustive for the four bit opcode.
35 1
    switch (op & 0xf) {
36 1
        case OP_ADD               : *rhs =  (Ps(2) +  Ps(1)) + Ps(0); break;
37 1
        case OP_SUBTRACT          : *rhs =  (Ps(2) -  Ps(1)) + Ps(0); break;
38 1
        case OP_MULTIPLY          : *rhs =  (Ps(2) *  Ps(1)) + Ps(0); break;
39

40 1
        case OP_SHIFT_RIGHT_LOGIC : *rhs =  Sh(Pu(2), >>, 1) + Ps(0); break;
41 1
        case OP_SHIFT_RIGHT_ARITH : *rhs =  Sh(Ps(2), >>, 1) + Ps(0); break;
42 1
        case OP_SHIFT_LEFT        : *rhs =  Sh(Pu(2), <<, 1) + Ps(0); break;
43

44 1
        case OP_COMPARE_LT        : *rhs = -(Ps(2) <  Ps(1)) + Ps(0); break;
45 1
        case OP_COMPARE_EQ        : *rhs = -(Ps(2) == Ps(1)) + Ps(0); break;
46 1
        case OP_COMPARE_GE        : *rhs = -(Ps(2) >= Ps(1)) + Ps(0); break;
47

48 1
        case OP_BITWISE_AND       : *rhs =  (Ps(2) &  Ps(1)) + Ps(0); break;
49 1
        case OP_BITWISE_ANDN      : *rhs =  (Ps(2) &~ Ps(1)) + Ps(0); break;
50 1
        case OP_BITWISE_OR        : *rhs =  (Ps(2) |  Ps(1)) + Ps(0); break;
51 1
        case OP_BITWISE_ORN       : *rhs =  (Ps(2) |~ Ps(1)) + Ps(0); break;
52 1
        case OP_BITWISE_XOR       : *rhs =  (Ps(2) ^  Ps(1)) + Ps(0); break;
53

54 1
        case OP_PACK              : *rhs =  (pack2 |  pack1) + pack0; break;
55 1
        case OP_TEST_BIT          : *rhs = -!!(Ps(2) & mask) + Ps(0); break;
56
    }
57
    #undef Ps
58
    #undef Pu
59
    #undef Sh
60
}
61

62 1
static int do_common(struct sim_state *s, int32_t *Z, int32_t *rhs,
63
        int32_t *value, int loading, int storing, int arrow_right)
64
{
65 1
    int32_t * const r = arrow_right ? Z   : rhs;
66 1
    int32_t * const w = arrow_right ? rhs : Z  ;
67

68 1
    int rc = 0;
69 1
    if (loading) {
70 1
        rc = s->dispatch_op(s, OP_DATA_READ, *r, value);
71
    } else
72 1
        *value = *r;
73

74 1
    if (storing) {
75 1
        rc = s->dispatch_op(s, OP_WRITE, *w, value);
76 1
    } else if (w != &s->machine.regs[0])  // throw away write to reg 0
77 1
        *w = *value;
78

79 1
    return rc;
80
}
81

82 1
static int run_instruction(struct sim_state *s, const struct element *i, void *run_data)
83
{
84
    (void)run_data;
85 1
    int32_t * const ip = &s->machine.regs[15];
86 1
    int32_t rhs = 0;
87 1
    int32_t Y = 0, imm = 0, value = 0;
88 1
    enum op op = OP_BITWISE_OR;
89

90 1
    ++*ip;
91

92 1
    const struct instruction_type012 * const g = &i->insn.u.type012;
93 1
    const struct instruction_type3   * const v = &i->insn.u.type3;
94

95 1
    switch (i->insn.u.typeany.p) {
96 1
        case 0:
97
        case 1:
98
        case 2:
99 1
            Y   = s->machine.regs[g->y];
100 1
            imm = g->imm;
101 1
            op  = (enum op)g->op;
102 1
            break;
103 1
        case 3:
104 1
            Y   = 0;
105 1
            imm = v->imm;
106 1
            op  = OP_BITWISE_OR;
107 1
            break;
108
    }
109

110 1
    do_op(op, g->p, &rhs, s->machine.regs[g->x], Y, imm);
111 1
    return do_common(s, &s->machine.regs[g->z], &rhs, &value, g->dd == 3,
112 1
            g->dd == 1 || g->dd == 2, g->dd == 1);
113
}
114

115 1
static int updates_P(const struct insn_or_data i)
116
{
117 1
    struct instruction_typeany t = i.u.typeany;
118 1
    return (t.z == 15) && (t.dd == 0 || t.dd == 3);
119
}
120

121 1
int interp_step_sim(struct sim_state *s, const struct run_ops *ops,
122
        void **run_data, void *ops_data)
123
{
124 1
    if (ops->pre_fetch)
125 1
        if (ops->pre_fetch(s, ops_data))
126 1
            return 0;
127

128 1
    struct element i = { .insn = { .reladdr = 0 } };
129 1
    if (s->dispatch_op(s, OP_INSN_READ, s->machine.regs[15], &i.insn.u.word))
130 0
        return -1;
131

132 1
    i.insn.reladdr = s->machine.regs[15];
133

134 1
    if (ops->pre_insn)
135 1
        if (ops->pre_insn(s, &i, ops_data))
136 1
            return 0;
137

138 1
    if (run_instruction(s, &i, *run_data))
139 1
        return -1;
140

141 1
    if (ops->post_insn)
142 1
        if (ops->post_insn(s, &i, ops_data))
143 1
            return 0;
144

145
    // return  2 means "successful step, updated P register"
146
    // return  1 means "successful step, can continue as-is"
147
    // return  0 means "stopped because a hook told us to stop"
148
    // return -1 means "stopped because some error occurred"
149
    // TODO use an enumeration
150 1
    return updates_P(i.insn) ? 2 : 1;
151
}
152

153 1
int interp_run_sim(struct sim_state *s, const struct run_ops *ops,
154
        void **run_data, void *ops_data)
155
{
156 1
    int rc = 0;
157

158 1
    *run_data = NULL; // this runner needs no data yet
159 0
    do {
160 1
        rc = interp_step_sim(s, ops, run_data, ops_data);
161 1
    } while (rc > 0);
162

163 1
    return rc;
164
}
165

166 1
int load_sim(op_dispatcher *dispatch, void *sud, const struct format *f,
167
        void *ud, STREAM *in, int32_t load_address)
168
{
169 1
    struct element i;
170 1
    while (f->in(in, &i, ud) >= 0) {
171 1
        if (dispatch(sud, OP_WRITE, load_address + i.insn.reladdr, &i.insn.u.word))
172 1
            return -1;
173

174
        // Do a minimal word-at-a-time verification as we go.
175 1
        int32_t word = 0;
176 1
        if (dispatch(sud, OP_INSN_READ, load_address + i.insn.reladdr, &word))
177 0
            return -1;
178

179 1
        if (word != i.insn.u.word)
180 0
            return -1;
181
    }
182

183 1
    return 0;
184
}
185

186
/* vi: set ts=4 sw=4 et: */

Read our documentation on viewing source code .

Loading