Home
       ins.c - scc - simple c99 compiler
  HTML git clone git://git.simple-cc.org/scc
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
   DIR README
   DIR LICENSE
       ---
       ins.c (9691B)
       ---
            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 }