ins.c - scc - simple c99 compiler
(HTM) git clone git://git.simple-cc.org/scc
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) Submodules
(DIR) README
(DIR) LICENSE
---
ins.c (9688B)
---
1 #include <stdlib.h>
2 #include <string.h>
3
4 #include <scc/mach.h>
5 #include <scc/scc.h>
6
7 #include "../as.h"
8 #include "proc.h"
9
10 /*
11 * This implementation is based in:
12 * - Zilog Z80 CPU Specifications by Sean Young
13 * - Decoding Z80 opcodes - of use to disassembler and emulator
14 * writers - by Cristian Dinu.
15 */
16
17 static int
18 getclass(Node *np)
19 {
20 if (np->addr != AREG)
21 return 0;
22
23 switch (np->sym->value) {
24 case AREG_C:
25 return RCLASS | PCLASS | QCLASS | CCCLASS | SSCLASS;
26 case AREG_A:
27 case AREG_B:
28 case AREG_D:
29 case AREG_E:
30 return RCLASS | PCLASS | QCLASS;
31 case AREG_H:
32 case AREG_L:
33 return RCLASS;
34 case AREG_IXL:
35 case AREG_IXH:
36 return PCLASS;
37 case AREG_IYL:
38 case AREG_IYH:
39 return QCLASS;
40 case AREG_HL:
41 return DDCLASS | QQCLASS;
42 case AREG_BC:
43 case AREG_DE:
44 return DDCLASS | QQCLASS | PPCLASS | RRCLASS;
45 case AREG_SP:
46 return DDCLASS | PPCLASS | RRCLASS;
47 case AREG_AF:
48 return QQCLASS;
49 case AREG_IX:
50 return PPCLASS;
51 case AREG_IY:
52 return RRCLASS;
53 case AREG_PO:
54 case AREG_PE:
55 case AREG_P:
56 case AREG_M:
57 return CCCLASS;
58 case AREG_NZ:
59 case AREG_Z:
60 case AREG_NC:
61 return CCCLASS | SSCLASS;
62 default:
63 return 0;
64 }
65 }
66
67 int
68 match(Op *op, Node **args)
69 {
70 unsigned char *p;
71 int arg, class, rep, opt;
72 Node *np;
73
74 if (!op->args)
75 return args == NULL;
76
77 opt = rep = 0;
78 for (p = op->args; arg = *p; ++p) {
79 if (rep)
80 --p;
81 if ((np = *args++) == NULL)
82 return (rep|opt) != 0;
83
84 switch (arg) {
85 case AOPT:
86 opt = 1;
87 break;
88 case AREP:
89 rep = 1;
90 break;
91 case AINDER_C:
92 arg = AREG_C;
93 goto indirect;
94 case AINDER_HL:
95 arg = AREG_HL;
96 goto indirect;
97 case AINDER_DE:
98 arg = AREG_DE;
99 goto indirect;
100 case AINDER_BC:
101 arg = AREG_BC;
102 goto indirect;
103 case AINDER_IX:
104 arg = AREG_IX;
105 goto indirect;
106 case AINDER_IY:
107 arg = AREG_IY;
108 goto indirect;
109 case AINDER_SP:
110 arg = AREG_SP;
111 indirect:
112 if (np->addr != AINDIR)
113 return 0;
114 np = np->left;
115 case AREG_A:
116 case AREG_I:
117 case AREG_R:
118 case AREG_F:
119 case AREG_HL:
120 case AREG_BC:
121 case AREG_DE:
122 case AREG_IY:
123 case AREG_IX:
124 case AREG_SP:
125 case AREG_AF:
126 case AREG_AF_:
127 if (np->addr != AREG || np->sym->value != arg)
128 return 0;
129 break;
130 case AREG_RCLASS:
131 class = RCLASS;
132 goto check_class;
133 case AREG_PCLASS:
134 class = PCLASS;
135 goto check_class;
136 case AREG_QCLASS:
137 class = QCLASS;
138 goto check_class;
139 case AREG_QQCLASS:
140 class = QQCLASS;
141 goto check_class;
142 case AREG_PPCLASS:
143 class = PPCLASS;
144 goto check_class;
145 case AREG_RRCLASS:
146 class = RRCLASS;
147 goto check_class;
148 case AREG_CCCLASS:
149 class = CCCLASS;
150 goto check_class;
151 case AREG_SSCLASS:
152 class = SSCLASS;
153 goto check_class;
154 case AREG_DDCLASS:
155 class = DDCLASS;
156 check_class:
157 if ((getclass(np) & class) == 0)
158 return 0;
159 break;
160 case AINDEX_IY:
161 arg = AREG_IY;
162 goto index_address;
163 case AINDEX_IX:
164 arg = AREG_IX;
165 index_address:
166 if (np->addr != AINDEX)
167 return 0;
168 np = np->left->left;
169 if (np->sym->value != arg)
170 return 0;
171 if (toobig(np, AIMM8))
172 error("overflow in index");
173 break;
174 case ARST:
175 if (np->addr != AIMM)
176 return 0;
177 if ((np->sym->value & ~0x38) != 0)
178 return 0;
179 break;
180 case AZERO:
181 if (np->addr != AIMM)
182 return 0;
183 break;
184 case AIMM3:
185 case AIMM8:
186 case AIMM16:
187 case AIMM32:
188 case AIMM64:
189 if (np->addr != AIMM)
190 return 0;
191 if (toobig(np, arg))
192 error("overflow in immediate operand");
193 break;
194 case ASYM:
195 if (np->op != IDEN)
196 return 0;
197 break;
198 case ADIRECT:
199 case ASTR:
200 if (np->addr != arg)
201 return 0;
202 break;
203 default:
204 abort();
205 }
206 }
207
208 return *args == NULL;
209 }
210
211 /*
212 * (expr) -> ADIRECT
213 * (REG) -> AINDIR
214 * (REG + expr) -> AINDEX
215 * (REG - expr) -> AINDEX
216 * expr (REG) -> AINDEX
217 */
218 Node *
219 moperand(void)
220 {
221 int op;
222 Node *np, *dir, *off, *reg;
223
224 dir = off = reg = NULL;
225 if (accept('(')) {
226 if (yytoken != REG) {
227 dir = expr();
228 } else {
229 reg = getreg();
230 switch (yytoken) {
231 case '+':
232 case '-':
233 off = expr();
234 case ')':
235 break;
236 default:
237 unexpected();
238 }
239 }
240 } else {
241 off = expr();
242 expect('(');
243 reg = getreg();
244 }
245 expect(')');
246
247 if (dir) {
248 op = ADIRECT;
249 np = dir;
250 } else if (off) {
251 np = node(AREG_OFF, reg, off);
252 op = AINDEX;
253 } else {
254 np = reg;
255 op = AINDIR;
256 }
257 np = node(op, np, NULL);
258 np->addr = op;
259 return np;
260 }
261
262 static int
263 reg2int(Node *np)
264 {
265 switch (np->sym->value) {
266 case AREG_F:
267 case AREG_B: return 0;
268 case AREG_C: return 1;
269 case AREG_D: return 2;
270 case AREG_E: return 3;
271 case AREG_IXH:
272 case AREG_IYH:
273 case AREG_H: return 4;
274 case AREG_IXL:
275 case AREG_IYL:
276 case AREG_L: return 5;
277 case AREG_A: return 7;
278 case AREG_BC: return 0;
279 case AREG_DE: return 1;
280 case AREG_HL:
281 case AREG_IX:
282 case AREG_IY: return 2;
283 case AREG_AF:
284 case AREG_SP: return 3;
285 default: abort();
286 }
287 }
288
289 static int
290 cc2int(Node *np)
291 {
292 switch (np->sym->value) {
293 case AREG_NZ: return 0;
294 case AREG_Z: return 1;
295 case AREG_NC: return 2;
296 case AREG_C: return 3;
297 case AREG_PO: return 4;
298 case AREG_PE: return 5;
299 case AREG_P: return 6;
300 case AREG_M: return 7;
301 default: abort();
302 }
303 }
304
305 static int
306 ss2int(Node *np)
307 {
308 switch (np->sym->value) {
309 case AREG_NZ: return 4;
310 case AREG_Z: return 5;
311 case AREG_NC: return 6;
312 case AREG_C: return 7;
313 default: abort();
314 }
315 }
316
317 void
318 dir(Op *op, Node **args)
319 {
320 Node *imm;
321 unsigned char buf[4];
322 unsigned val;
323 int n = op->size;
324
325 imm = (args[1]->addr == ADIRECT) ? args[1] : args[0];
326 imm = imm->left;
327 memcpy(buf, op->bytes, n);
328 val = imm->sym->value;
329 buf[n-1] = val >> 8;
330 buf[n-2] = val;
331 emit(buf, n);
332 }
333
334 void
335 ld8(Op *op, Node **args)
336 {
337 Node *par1 = args[0], *par2 = args[1];
338 int n = op->size, i = n;
339 unsigned regval = 0;
340 unsigned char buf[4];
341
342 memcpy(buf, op->bytes, n);
343
344 if (par1->addr == AREG)
345 regval |= reg2int(par1) << 3;
346 if (par2->addr == AREG)
347 regval |= reg2int(par2);
348 else if (par2->addr == AIMM)
349 buf[--i] = par2->sym->value;
350
351 buf[--i] |= regval;
352 emit(buf, n);
353 }
354
355 void
356 alu16(Op *op, Node **args)
357 {
358 Node *par;
359 int n = op->size;
360 unsigned val;
361 unsigned char buf[4];
362
363 par = (args[1]) ? args[1] : args[0];
364 val = reg2int(par);
365 memcpy(buf, op->bytes, n);
366 buf[n-1] |= val << 4;
367 emit(buf, n);
368 }
369
370 void
371 ld16(Op *op, Node **args)
372 {
373 Node *dst, *src, *tmp;
374 int n = op->size;
375 unsigned val;
376 unsigned char buf[4];
377
378 dst = args[0];
379 src = args[1];
380 if (!src) {
381 alu16(op, args);
382 return;
383 }
384
385 if (dst->addr != AREG) {
386 tmp = src;
387 src = dst;
388 dst = tmp;
389 }
390
391 memcpy(buf, op->bytes, n);
392 if (src->addr == ADIRECT)
393 src = src->left;
394 val = src->sym->value;
395 buf[n-1] = val >> 8;
396 buf[n-2] = val;
397 buf[n-3] |= reg2int(dst) << 4;
398 emit(buf, n);
399 }
400
401 void
402 alu8(Op *op, Node **args)
403 {
404 Node *par = args[1];
405 unsigned char buf[4];
406 int n = op->size, shift;
407 unsigned val;
408
409 if (args[1]) {
410 shift = 0;
411 par = args[1];
412 } else {
413 shift = 3;
414 par = args[0];
415 }
416
417 switch (par->addr) {
418 case AIMM:
419 val = par->sym->value;
420 break;
421 case AREG:
422 val = reg2int(par) << shift;
423 break;
424 case AINDEX:
425 val = par->left->right->sym->value;
426 break;
427 case AINDIR:
428 val = 0;
429 break;
430 default:
431 abort();
432 }
433
434 memcpy(buf, op->bytes, n);
435 buf[n-1] |= val;
436 emit(buf, n);
437 }
438
439 void
440 idx(Op *op, Node **args)
441 {
442 Node *tmp, *idx, *imm, *reg;
443 unsigned char buf[4];
444 int n = op->size, i = n, shift = 0;
445
446 imm = reg = NULL;
447 if (args[0]->addr != AINDEX) {
448 shift = 3;
449 tmp = args[0];
450 args[0] = args[1];
451 args[1] = tmp;
452 }
453 idx = args[0]->left->right;
454
455 if (args[1]->addr == AREG)
456 reg = args[1];
457 else
458 imm = args[1];
459
460 memcpy(buf, op->bytes, n);
461
462 if (imm)
463 buf[--i] = imm->sym->value;
464 buf[--i] = idx->sym->value;
465 if (reg)
466 buf[--i] |= reg2int(reg) << shift;
467
468 emit(buf, n);
469 }
470
471 void
472 inout(Op *op, Node **args)
473 {
474 Node *port, *value;
475 unsigned val;
476 int n = op->size;
477 unsigned char buf[5];
478
479 port = args[0];
480 value = args[1];
481 if (port->addr != ADIRECT && port->addr != AINDIR) {
482 value = port;
483 port = args[1];
484 }
485
486 if (port->addr == ADIRECT)
487 val = port->left->sym->value;
488 else if (value->addr == AREG)
489 val = reg2int(value) << 3;
490 else
491 val = 0;
492
493 memcpy(buf, op->bytes, n);
494 buf[n-1] |= val;
495 emit(buf, n);
496 }
497
498 void
499 rot_bit(Op *op, Node **args)
500 {
501 Node *par = args[0];
502 unsigned char buf[5];
503 int n = op->size;
504 unsigned val, npar = 0;
505
506 memcpy(buf, op->bytes, n);
507
508 par = args[0];
509 if (par->addr == AIMM) {
510 buf[n-1] |= par->sym->value << 3;
511 par = args[npar = 1];
512 }
513
514 switch (par->addr) {
515 case AINDEX:
516 val = par->left->right->sym->value;
517 buf[n-2] = val;
518 par = args[npar+1];
519 if (!par)
520 break;
521 case AREG:
522 val = reg2int(par);
523 buf[n-1] |= val;
524 case AINDIR:
525 break;
526 default:
527 abort();
528 }
529
530 emit(buf, n);
531 }
532
533 void
534 im(Op *op, Node **args)
535 {
536 unsigned val = args[0]->sym->value;
537 unsigned char buf[4];
538 int n = op->size;
539
540 if (val > 0)
541 ++val;
542
543 memcpy(buf, op->bytes, n);
544 buf[n-1] |= val << 3;
545 emit(buf, n);
546 }
547
548 void
549 branch(int relative, Op *op, Node **args)
550 {
551 unsigned char buf[4];
552 Node *flag, *imm;
553 int n = op->size, i = n;
554 unsigned val;
555 int (*fun)(Node *);
556
557 flag = imm = NULL;
558 if (args[0]->addr == AREG) {
559 flag = args[0];
560 imm = args[1];
561 } else if (args[0]->addr == AIMM) {
562 imm = args[0];
563 }
564 memcpy(buf, op->bytes, n);
565
566 if (imm) {
567 val = imm->sym->value;
568 if (!relative)
569 buf[--i] = val >> 8;
570 else
571 val -= getpc() - 2;
572 buf[--i] = val;
573
574 }
575 if (flag) {
576 fun = (relative) ? ss2int : cc2int;
577 buf[--i] |= (*fun)(flag) << 3;
578 }
579
580
581 emit(buf, n);
582 }
583
584 void
585 jp(Op *op, Node **args)
586 {
587 branch(0, op, args);
588 }
589
590 void
591 jr(Op *op, Node **args)
592 {
593 branch(1, op, args);
594 }
595
596 void
597 rst(Op *op, Node **args)
598 {
599 unsigned char buf[1];
600
601 buf[0] = op->bytes[0];
602 buf[0] |= args[0]->sym->value;
603 emit(buf, 1);
604 }