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