1#include <stdlib.h>2#include <string.h>34#include <scc/mach.h>5#include <scc/scc.h>67#include "../as.h"8#include "proc.h"910/*11 * This implementation is based in:12 * - Zilog Z80 CPU Specifications by Sean Young13 * - Decoding Z80 opcodes - of use to disassembler and emulator14 * writers - by Cristian Dinu.15 */1617static int18getclass(Node *np)19{20 if (np->addr != AREG)21 return 0;2223 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}6667int68match(Op *op, Node **args)69{70 unsigned char *p;71 int arg, class, rep, opt;72 Node *np;7374 if (!op->args)75 return args == NULL;7677 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;8384 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 }207208 return *args == NULL;209}210211/*212 * (expr) -> ADIRECT213 * (REG) -> AINDIR214 * (REG + expr) -> AINDEX215 * (REG - expr) -> AINDEX216 * expr (REG) -> AINDEX217 */218Node *219moperand(void)220{221 int op;222 Node *np, *dir, *off, *reg;223224 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(')');246247 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}261262static int263reg2int(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}288289static int290cc2int(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}304305static int306ss2int(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}316317void318dir(Op *op, Node **args)319{320 Node *imm;321 unsigned char buf[4];322 unsigned val;323 int n = op->size;324325 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}333334void335ld8(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];341342 memcpy(buf, op->bytes, n);343344 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;350351 buf[--i] |= regval;352 emit(buf, n);353}354355void356alu16(Op *op, Node **args)357{358 Node *par;359 int n = op->size;360 unsigned val;361 unsigned char buf[4];362363 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}369370void371ld16(Op *op, Node **args)372{373 Node *dst, *src, *tmp;374 int n = op->size;375 unsigned val;376 unsigned char buf[4];377378 dst = args[0];379 src = args[1];380 if (!src) {381 alu16(op, args);382 return;383 }384385 if (dst->addr != AREG) {386 tmp = src;387 src = dst;388 dst = tmp;389 }390391 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}400401void402alu8(Op *op, Node **args)403{404 Node *par = args[1];405 unsigned char buf[4];406 int n = op->size, shift;407 unsigned val;408409 if (args[1]) {410 shift = 0;411 par = args[1];412 } else {413 shift = 3;414 par = args[0];415 }416417 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 }433434 memcpy(buf, op->bytes, n);435 buf[n-1] |= val;436 emit(buf, n);437}438439void440idx(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;445446 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;454455 if (args[1]->addr == AREG)456 reg = args[1];457 else458 imm = args[1];459460 memcpy(buf, op->bytes, n);461462 if (imm)463 buf[--i] = imm->sym->value;464 buf[--i] = idx->sym->value;465 if (reg)466 buf[--i] |= reg2int(reg) << shift;467468 emit(buf, n);469}470471void472inout(Op *op, Node **args)473{474 Node *port, *value;475 unsigned val;476 int n = op->size;477 unsigned char buf[5];478479 port = args[0];480 value = args[1];481 if (port->addr != ADIRECT && port->addr != AINDIR) {482 value = port;483 port = args[1];484 }485486 if (port->addr == ADIRECT)487 val = port->left->sym->value;488 else if (value->addr == AREG)489 val = reg2int(value) << 3;490 else491 val = 0;492493 memcpy(buf, op->bytes, n);494 buf[n-1] |= val;495 emit(buf, n);496}497498void499rot_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;505506 memcpy(buf, op->bytes, n);507508 par = args[0];509 if (par->addr == AIMM) {510 buf[n-1] |= par->sym->value << 3;511 par = args[npar = 1];512 }513514 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 }529530 emit(buf, n);531}532533void534im(Op *op, Node **args)535{536 unsigned val = args[0]->sym->value;537 unsigned char buf[4];538 int n = op->size;539540 if (val > 0)541 ++val;542543 memcpy(buf, op->bytes, n);544 buf[n-1] |= val << 3;545 emit(buf, n);546}547548void549branch(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 *);556557 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);565566 if (imm) {567 val = imm->sym->value;568 if (!relative)569 buf[--i] = val >> 8;570 else571 val -= getpc() - 2;572 buf[--i] = val;573574 }575 if (flag) {576 fun = (relative) ? ss2int : cc2int;577 buf[--i] |= (*fun)(flag) << 3;578 }579580581 emit(buf, n);582}583584void585jp(Op *op, Node **args)586{587 branch(0, op, args);588}589590void591jr(Op *op, Node **args)592{593 branch(1, op, args);594}595596void597rst(Op *op, Node **args)598{599 unsigned char buf[1];600601 buf[0] = op->bytes[0];602 buf[0] |= args[0]->sym->value;603 emit(buf, 1);604}