]> git.sesse.net Git - interpreter_trials/blob - interpreter6.cpp
Add a tail-call variant with state as global variables in locked registers.
[interpreter_trials] / interpreter6.cpp
1 #include "bytecode.h"
2 #include <utility>
3 #include "interpreter.h"
4
5 namespace interpreter6
6 {
7
8     struct Flags
9     {
10         unsigned int zero:16;
11         unsigned int negative:16;
12     };
13
14     struct CpuState
15     {
16         int32_t regs[16] = {0};
17         uint32_t final_cycle_count = 0;
18         bool exit = false;
19     };
20
21
22     struct ReturnVal
23     {
24         uint8_t *pc;
25         Flags flags;
26         uint32_t cycle_count;
27     };
28
29
30 #define PARAMS CpuState *state, uint8_t *pc, Flags flags, uint32_t cycle_count
31 #define ARGS state, pc, flags, cycle_count
32 #define RETURN_VAL {pc, flags, cycle_count}
33
34     ReturnVal op_return(PARAMS)
35     {
36         cycle_count += 1;
37         state->final_cycle_count = cycle_count;
38         state->exit = true;
39         return RETURN_VAL;
40     }
41
42     ReturnVal op_add(PARAMS)
43     {
44         uint8_t reg = *pc++;
45         uint8_t dest = reg>>4, src = reg & 0xf;
46
47         int32_t v = state->regs[dest];
48         v += state->regs[src];
49
50         flags.zero = (v == 0);
51         flags.negative = (v < 0);
52         state->regs[dest] = v;
53         cycle_count += 2;
54         return RETURN_VAL;
55     }
56
57     ReturnVal op_sub(PARAMS)
58     {
59         uint8_t reg = *pc++;
60         uint8_t dest = reg>>4, src = reg & 0xf;
61
62         int32_t v = state->regs[dest];
63         v -= state->regs[src];
64
65         flags.zero = (v == 0);
66         flags.negative = (v < 0);
67         state->regs[dest] = v;
68         cycle_count += 2;
69         return RETURN_VAL;
70     }
71
72     ReturnVal op_mov(PARAMS)
73     {
74         uint8_t reg = *pc++;
75         uint8_t dest = reg>>4, src = reg & 0xf;
76
77         state->regs[dest] = state->regs[src];
78         cycle_count += 2;
79         return RETURN_VAL;
80
81     }
82
83     ReturnVal op_movi(PARAMS)
84     {
85         uint8_t reg = *pc++;
86         uint8_t dest = reg>>4;
87
88         int32_t imm = *(int32_t *)pc;
89         pc += 4;
90
91         state->regs[dest] = imm;
92         cycle_count += 6;
93         return RETURN_VAL;
94
95     }
96
97     ReturnVal op_b(PARAMS)
98     {
99         int8_t rel = *pc++;
100         pc += rel;
101         cycle_count += 2;
102         return RETURN_VAL;
103     }
104
105     ReturnVal op_bnz(PARAMS)
106     {
107         int8_t rel = *pc++;
108         if(!flags.zero)
109         {
110             pc += rel;
111         }
112         cycle_count += 2;
113         return RETURN_VAL;
114     }
115
116     ReturnVal (*dispatch_table[])(PARAMS) =
117     {
118         op_return,
119         op_add,
120         op_sub,
121         op_mov,
122         op_movi,
123         op_b,
124         op_bnz
125     };
126
127     std::pair<int32_t, uint32_t> interpreter_run(uint8_t *program, int32_t param)
128     {
129         CpuState local_state;
130         CpuState *state = &local_state;
131         uint8_t *pc = program;
132         state->regs[X0] = param;
133         state->exit = false;
134         uint32_t cycle_count = 0;
135         Flags flags = {0, 0};
136         while(!state->exit)
137         {
138             uint8_t opcode = *pc++;
139             ReturnVal ret = dispatch_table[opcode](ARGS);
140             pc = ret.pc;
141             flags = ret.flags;
142             cycle_count = ret.cycle_count;
143         }
144
145         return std::make_pair(state->regs[X0], state->final_cycle_count);
146
147     }
148
149
150 }