]> git.sesse.net Git - interpreter_trials/blob - interpreter12.cpp
Add a tail-call variant with state as global variables in locked registers.
[interpreter_trials] / interpreter12.cpp
1 #include "bytecode.h"
2 #include <utility>
3 #include "interpreter.h"
4
5 namespace interpreter12
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     };
19
20 #ifdef __arm__
21 register CpuState *state asm("r4");
22 register uint8_t *pc asm("r5");
23 register Flags flags asm("r6");
24 register uint32_t cycle_count asm("r7");
25 #elif __x86_64__
26 register CpuState *state asm("r12");
27 register uint8_t *pc asm("r13");
28 register Flags flags asm("r14");
29 register uint32_t cycle_count asm("rbx");
30 #else
31 static CpuState *state;
32 static uint8_t *pc;
33 static Flags flags;
34 static uint32_t cycle_count;
35 #endif
36
37     extern void (*dispatch_table[])();
38
39     void op_return()
40     {
41         cycle_count += 1;
42         state->final_cycle_count = cycle_count;
43         return;
44     }
45
46     void op_add()
47     {
48         uint8_t reg = *pc++;
49         uint8_t dest = reg>>4, src = reg & 0xf;
50
51         int32_t v = state->regs[dest];
52         v += state->regs[src];
53
54         flags.zero = (v == 0);
55         flags.negative = (v < 0);
56         state->regs[dest] = v;
57         cycle_count += 2;
58
59         uint8_t opcode = *pc++;
60         dispatch_table[opcode]();
61     }
62
63     void op_sub()
64     {
65         uint8_t reg = *pc++;
66         uint8_t dest = reg>>4, src = reg & 0xf;
67
68         int32_t v = state->regs[dest];
69         v -= state->regs[src];
70
71         flags.zero = (v == 0);
72         flags.negative = (v < 0);
73         state->regs[dest] = v;
74         cycle_count += 2;
75
76         uint8_t opcode = *pc++;
77         dispatch_table[opcode]();
78     }
79
80     void op_mov()
81     {
82         uint8_t reg = *pc++;
83         uint8_t dest = reg>>4, src = reg & 0xf;
84
85         state->regs[dest] = state->regs[src];
86         cycle_count += 2;
87
88         uint8_t opcode = *pc++;
89         dispatch_table[opcode]();
90     }
91
92     void op_movi()
93     {
94         uint8_t reg = *pc++;
95         uint8_t dest = reg>>4;
96
97         int32_t imm = *(int32_t *)pc;
98         pc += 4;
99
100         state->regs[dest] = imm;
101         cycle_count += 6;
102
103         uint8_t opcode = *pc++;
104         dispatch_table[opcode]();
105     }
106
107     void op_b()
108     {
109         int8_t rel = *pc++;
110         pc += rel;
111         cycle_count += 2;
112
113         uint8_t opcode = *pc++;
114         dispatch_table[opcode]();
115     }
116
117     void op_bnz()
118     {
119         int8_t rel = *pc++;
120         if(!flags.zero)
121         {
122             pc += rel;
123         }
124         cycle_count += 2;
125
126         uint8_t opcode = *pc++;
127         dispatch_table[opcode]();
128     }
129
130     void (*dispatch_table[])() =
131     {
132         op_return,
133         op_add,
134         op_sub,
135         op_mov,
136         op_movi,
137         op_b,
138         op_bnz
139     };
140
141     std::pair<int32_t, uint32_t> interpreter_run(uint8_t *program, int32_t param)
142     {
143         // Save the previous value of our locked registers.
144         CpuState *save_state = state;
145         uint8_t *save_pc = pc;
146         Flags save_flags = {flags.zero, flags.negative};
147         uint32_t save_cycle_count = cycle_count;
148
149         CpuState local_state;
150         state = &local_state;
151         pc = program;
152         state->regs[X0] = param;
153         cycle_count = 0;
154         flags.zero = flags.negative = 0;
155
156         uint8_t opcode = *pc++;
157         dispatch_table[opcode]();
158
159         auto ret = std::make_pair(state->regs[X0], state->final_cycle_count);
160
161         // Restore locked registers. (Note that on 64-bit platforms, this will
162         // corrupt the high 32 bits of flags and cycle_count, so this is really
163         // only safe on 32-bit as it stands.)
164         state = save_state;
165         pc = save_pc;
166         flags.zero = save_flags.zero;
167         flags.negative = save_flags.negative;
168         cycle_count = save_cycle_count;
169
170         return ret;
171     }
172
173
174 }