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