forked from jdah/jdh-8
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathasm.h
255 lines (204 loc) · 6.01 KB
/
asm.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
#ifndef ASM_H
#define ASM_H
#include "../common/util.h"
#include "../common/jdh8.h"
#include "lex.h"
// checks buffer _b, asmrealloc-ing it/doubling its size if necessary to add a
// new element
#define BUFCHK(_b) \
if ((_b).buffer == NULL || (_b).size + 1 > (_b).capacity) { \
(_b).capacity = (_b).capacity == 0 ? \
(_b).capacity_min : \
(_b).capacity * 2; \
(_b).buffer = asmrealloc( \
(_b).buffer, \
(_b).capacity * sizeof((_b).buffer[0]) \
); \
}
// appends new *element _p to buffer _b, checking if it can be added first and
// creating the buffer if it does not already exist
#define BUFADDP(_b, _p) do { \
BUFCHK((_b)); \
(_b).buffer[(_b).size++] = *(_p); \
} while (0);
// BUFPADD, but not a pointer
#define BUFADD(_b, _e) do { \
__typeof__(_e) __e = (_e), *_p = &__e; \
BUFADDP((_b), (_p)); \
} while (0);
#define BUFPUSH(_b, _e) BUFADD((_b), (_e))
#define BUFPUSHP(_b, _p) BUFADDP((_b), (_p))
#define BUFPOP(_b) ({ \
if ((_b).size == 0) warn("Empty buffer %p", &(_b)); \
(_b).buffer[--(_b).size]; \
})
#define BUFPEEKP(_b) ({ \
if ((_b).size == 0) warn("Empty buffer %p", &(_b)); \
&(_b).buffer[(_b).size - 1]; \
})
#define BUFPEEK(_b) (*BUFPEEKP((_b)))
// value for Context::org indicating not set in program text
#define ORG_UNSET ((u16) 0xFFFF)
// undefined in the context of expression evaluation (see eval.c)
#define EVAL_EXP_UNDEFINED LONG_MAX
struct Input {
char name[256];
const char *data, *current, *line;
usize line_no;
struct Input *parent;
};
// token flags
enum TokenFlags {
// indicates a symbol (label) is a sublabel
TF_SUB = 0,
// indicates a token should be ignored
TF_IGNORE = 1
};
#define A_IMM8_REG (A_IMM8 | A_REG)
#define A_IMM16_HL (A_IMM16 | A_HL | A_ADDR)
#define A_IMM (A_IMM16 | A_IMM8)
enum Arg {
A_REG = (1 << 0),
A_IMM8 = (1 << 1),
A_IMM16 = (1 << 2),
A_ADDR = (1 << 3),
A_HL = (1 << 4)
};
struct Op {
char name[16];
usize num_args;
enum Arg args[8];
bool macro;
union {
// instruction
struct {
enum Instruction instruction;
};
// macro
struct {
char arg_names[8][16];
struct Token *start, *end;
};
};
};
struct Define {
char *name, *value;
struct Define *next;
};
struct Label {
char *name;
bool sub;
u16 value;
struct Label *prev, *next;
};
struct Patch {
struct Token *symbol;
struct Label *label;
u16 location;
struct Patch *next;
};
// defined in microcode.c
struct MicrocodeContext;
struct Context {
// current input
struct Input *input;
// always points into input->data, backed up in input->current on push
const char *current;
// @define'd values
struct Define *defines;
// labels
struct Label *labels;
// patches
struct Patch *patches;
struct {
struct Op *buffer;
usize size, capacity, capacity_min;
} ops;
// output
struct {
u8 *buffer;
usize size, capacity, capacity_min;
} out;
// preprocessor ifs
struct {
#define IFF_SUCCESS 1
#define IFF_FAILURE 2
#define IFF_PARENT_FAILURE 3
u8 *buffer;
usize size, capacity, capacity_min;
} ifs;
// origin of output
u16 org;
struct MicrocodeContext *mctx;
// flags
struct {
bool macro: 1;
bool microcode: 1;
bool verbose: 1;
};
};
#define asmwrn(ctx, token, m, ...)\
asmprint( \
(ctx), (token), ANSI_YELLOW "WARN", \
__FILE__, __LINE__, (m), ##__VA_ARGS__ \
);
#define asmchk(e, ctx, token, m, ...) if (!(e)) { \
asmprint( \
(ctx), (token), ANSI_RED "ERROR", \
__FILE__, __LINE__, (m), ##__VA_ARGS__ \
); \
exit(1); \
}
#define asmdbg(ctx, token, m, ...)\
asmprint((ctx), (token), "DEBUG", __FILE__, __LINE__, (m), ##__VA_ARGS__)
void asmprint(
const struct Context *ctx,
const struct Token *token,
const char *tag,
const char *filename,
usize line,
const char *fmt,
...
);
void *asmalloc(usize n);
void *asmrealloc(void *ptr, usize n);
int push_input_buffer(struct Context *ctx, const char *name, const char *buf);
int push_input(struct Context *ctx, const char *filename);
void pop_input(struct Context *ctx);
void eval_labels(
struct Context *ctx,
struct Token *start,
struct Token *end
);
// directive.c
void directive(
struct Context *ctx,
struct Token *first,
bool lex
);
// eval.c
i64 eval_exp(struct Context *ctx, struct Token *start, struct Token *end);
struct Token *eval_between(
struct Context *ctx,
struct Token *start,
struct Token *end
);
// macro.c
void parse_macro(
struct Context *ctx,
struct Token *start,
struct Token *end
);
struct Token *expand_macro(
struct Context *ctx,
struct Op *op,
struct Token *start,
struct Token *end,
enum Arg *args,
struct Token **arg_tokens,
usize num_args
);
// microcode.c
struct Token *microcode_parse(struct Context *, struct Token *);
void microcode_emit(struct Context *);
#endif