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