home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 6 / FreshFish_September1994.bin / new / dev / c / hce / hcesource / top / source / inst.c < prev    next >
C/C++ Source or Header  |  1992-09-02  |  8KB  |  443 lines

  1. /* Copyright (c) 1988,1991 by Sozobon, Limited.  Author: Tony Andrews
  2.  *
  3.  * Permission is granted to anyone to use this software for any purpose
  4.  * on any computer system, and to redistribute it freely, with the
  5.  * following restrictions:
  6.  * 1) No charge may be made other than reasonable charges for reproduction.
  7.  * 2) Modified versions must be clearly marked as such.
  8.  * 3) The authors are not responsible for any harmful consequences
  9.  *    of using this software, even if they result from defects in it.
  10.  *
  11.  * Modified by Detlef Wuerkner for AMIGA
  12.  * Changes marked with TETISOFT
  13.  */
  14.  
  15. /*
  16.  * Routines dealing with the parsing and output of instructions.
  17.  */
  18.  
  19. #include "top.h"
  20.  
  21. static    void    getarg();
  22. static    int    isreg();
  23.  
  24. /*
  25.  * addinst(bp, op, args) - add an instruction to block 'bp'
  26.  */
  27. void
  28. addinst(bp, op, args)
  29. register BLOCK    *bp;
  30. char    *op, *args;
  31. {
  32.     register INST    *ni;
  33.     register int    i;
  34.     register char    *s;
  35.     char    *arg2 = "";
  36.  
  37.     if (*op == '\0')    /* no instruction there */
  38.         return;
  39.  
  40.     ni = (INST *) alloc(sizeof(INST));
  41.  
  42.     ni->flags = 0;
  43.     ni->opcode = -1;
  44.     ni->next = NULL;
  45.     ni->prev = NULL;
  46.     ni->live = 0;
  47.     ni->rref = ni->rset = 0;
  48.  
  49.     ni->src.areg = ni->dst.areg = 0;
  50.     ni->src.ireg = ni->dst.ireg = 0;
  51.     ni->src.disp = ni->dst.disp = 0;
  52.     ni->src.amode = ni->dst.amode = NONE;
  53.  
  54.     /*
  55.      * Link into the block appropriately
  56.      */
  57.     if (bp->first == NULL) {
  58.         bp->first = bp->last = ni;
  59.     } else {
  60.         bp->last->next = ni;
  61.         ni->prev = bp->last;
  62.  
  63.         bp->last = ni;
  64.     }
  65.  
  66.     for (s = op; *s ;s++) {
  67.         /*
  68.          * Pseudo-ops start with a period, so the length
  69.          * specifier can't be the first character.
  70.          */
  71.         if (*s == '.' && s != op) {    /* length specifier */
  72.             *s++ = '\0';
  73.             switch (*s) {
  74.             case 'b':
  75.                 ni->flags |= LENB;
  76.                 break;
  77.             case 'w':
  78.                 ni->flags |= LENW;
  79.                 break;
  80. /* ADDED BY TETISOFT */
  81.             case 'L':
  82.  
  83.             case 'l':
  84.                 ni->flags |= LENL;
  85.                 break;
  86.             default:
  87.                 fprintf(stderr, "Bad length spec '%c'\n", *s);
  88.  
  89. /* CHANGED BY TETISOFT */
  90. /*                exit(1); */
  91.                 exit(EXIT_FAILURE);
  92.  
  93.             }
  94.         }
  95.     }
  96.  
  97.     for (i=0; opnames[i] ;i++) {
  98.         if (strcmp(op, opnames[i]) == 0) {
  99.             ni->opcode = i;
  100.             break;
  101.         }
  102.     }
  103.  
  104.     if (ni->opcode < 0) {
  105.         fprintf(stderr, "Unknown op '%s'\n", op);
  106.  
  107. /* CHANGED BY TETISOFT */
  108. /*        exit(1); */
  109.         exit(EXIT_FAILURE);
  110.  
  111.     }
  112.  
  113.     /*
  114.      * Look for the split between the first and second operands.
  115.      */
  116.     for (s = args; *s ;s++) {
  117.         /*
  118.          * skip chars in parens, since an operand split can't
  119.          * occur within.
  120.          */
  121.         if (*s == '(') {
  122.             while (*s != ')')
  123.                 s++;
  124.         }
  125.         if (*s == ',') {
  126.             *s++ = '\0';
  127.             arg2 = s;
  128.             break;
  129.         }
  130.     }
  131.  
  132.     getarg(&ni->src, args);
  133.     getarg(&ni->dst, arg2);
  134. }
  135.  
  136. /*
  137.  * delinst(bp, ip) - delete instruction 'ip' in block 'bp'
  138.  */
  139. void
  140. delinst(bp, ip)
  141. BLOCK    *bp;
  142. register INST    *ip;
  143. {
  144.     register INST    *pi, *ni;    /* previous and next instructions */
  145.  
  146.     pi = ip->prev;
  147.     ni = ip->next;
  148.  
  149.     if (pi != NULL)
  150.         pi->next = ni;
  151.     else
  152.         bp->first = ni;
  153.  
  154.     if (ni != NULL)
  155.         ni->prev = pi;
  156.     else
  157.         bp->last = pi;
  158.  
  159.     /*
  160.      * Free space used by the instruction.
  161.      */
  162.     freeop(&ip->src);
  163.     freeop(&ip->dst);
  164.     free(ip);
  165.  
  166.     s_idel++;
  167. }
  168.  
  169. /*
  170.  * getarg(op, s) - parse string 's' into the operand structure 'op'
  171.  *
  172.  * Hack alert!! The following code parses the operands only to the
  173.  * extent needed by the optimizer. We're primarily interested in
  174.  * details about addressing modes used, not in any expressions that
  175.  * might be present. This code is highly tuned to the output of the
  176.  * compiler.
  177.  */
  178. static    void
  179. getarg(op, s)
  180. register struct    opnd    *op;
  181. register char    *s;
  182. {
  183.     extern    long    atol();
  184.     register int    reg;
  185.     register char    *p;
  186.  
  187.     if (*s == '\0') {
  188.         op->amode = NONE;
  189.         return;
  190.     }
  191.  
  192.     if (*s == '#') {                /* immediate data */
  193.         op->amode = IMM;
  194.         s += 1;
  195.         if (isdigit(s[0]) || s[0] == '-')
  196.             op->disp  = atol(s);
  197.         else {
  198.             op->amode |= SYMB;
  199.             op->astr = strsave(s);
  200.         }
  201.         return;
  202.     } else if ((reg = isreg(s)) >= 0) {        /* reg. direct */
  203.         op->amode = REG;
  204.         op->areg = reg;
  205.     } else if (s[0] == '(' || (s[0] == '-' && s[1] == '(')) {
  206.         op->amode = REGI;
  207.         if (s[0] == '-') {
  208.             op->amode |= DEC;
  209.             s++;
  210.         }
  211.         s++;        /* skip the left paren */
  212.         if ((op->areg = isreg(s)) < 0) {
  213.             fprintf(stderr, "bad reg. '%s'\n", s);
  214.  
  215. /* CHANGED BY TETISOFT */
  216. /*            exit(1); */
  217.             exit(EXIT_FAILURE);
  218.  
  219.         }
  220.         s += 3;        /* skip the register and right paren */
  221.  
  222.         if (s[0] == '+')
  223.             op->amode |= INC;
  224.     } else if (!isdigit(s[0]) && (s[0] != '-')) {
  225.         op->amode = ABS;
  226.         op->astr = strsave(s);
  227.     } else {
  228.         for (p=s; isdigit(*p) || *p == '-' ;p++)
  229.             ;
  230.         if (*p != '(') {
  231.             /*
  232.              * Must have been absolute, but with an
  233.              * address instead of a symbol.
  234.              */
  235.             op->amode = ABS;
  236.             op->astr = strsave(s);
  237.             return;
  238.         }
  239.         *p++ = '\0';
  240.         op->disp = atol(s);
  241.         s = p;
  242.         if (s[0] == 'p' && s[1] == 'c') {    /* PC relative */
  243.             if (s[2] == ')') {
  244.                 op->amode = PCD;
  245.                 return;
  246.             }
  247.             op->amode = PCDX;
  248.             op->ireg = isreg(s+3);
  249.             if (s[6] == 'l')
  250.                 op->amode |= XLONG;
  251.         } else if ((reg = isreg(s)) >= 0) {
  252.             op->areg = reg;
  253.             if (s[2] == ')') {
  254.                 op->amode = REGID;
  255.                 return;
  256.             }
  257.             op->amode = REGIDX;
  258.             op->ireg = isreg(s+3);
  259.             if (s[6] == 'l')
  260.                 op->amode |= XLONG;
  261.         } else {
  262.             fprintf(stderr, "bad reg. '%s' after disp\n", s);
  263.  
  264. /* CHANGED BY TETISOFT */
  265. /*            exit(1); */
  266.             exit(EXIT_FAILURE);
  267.  
  268.         }
  269.     }
  270. }
  271.  
  272. /*
  273.  * characters that can terminate a register name
  274.  */
  275. #define    isterm(c) ((c) == '\0' || (c) == ')' || (c) == ',' || (c) == '.')
  276.  
  277. static    int
  278. isreg(s)
  279. register char    *s;
  280. {
  281.     if (s[0] == 'd' && isdigit(s[1]) && isterm(s[2]))
  282.         return D0 + (s[1] - '0');
  283.     if (s[0] == 'a' && isdigit(s[1]) && isterm(s[2]))
  284.         return A0 + (s[1] - '0');
  285.     if (s[0] == 's' && s[1] == 'p' && isterm(s[2]))
  286.         return SP;
  287.  
  288.     return -1;
  289. }
  290.  
  291.  
  292. /*
  293.  * Routines for printing out instructions
  294.  */
  295.  
  296. static    char    *rstr();
  297. static    void    putop();
  298.  
  299. void
  300. putinst(ip)
  301. register INST    *ip;
  302. {
  303.     char    c;
  304.  
  305.     fprintf(ofp, "\t%s", opnames[ip->opcode]);
  306.  
  307.     switch (ip->flags) {
  308.     case LENB:
  309.         c = 'b';
  310.         break;
  311.     case LENW:
  312.         c = 'w';
  313.         break;
  314.     case LENL:
  315.         c = 'l';
  316.         break;
  317.     default:
  318.         c = '\0';
  319.         break;
  320.     }
  321.     if (c)
  322.         fprintf(ofp, ".%c", c);
  323.  
  324.     if (ip->src.amode != NONE) {
  325.         fprintf(ofp, "\t");
  326.         putop(&ip->src);
  327.     }
  328.  
  329.     if (ip->dst.amode != NONE) {
  330.         fprintf(ofp, ",");
  331.         putop(&ip->dst);
  332.     }
  333. #ifdef    DEBUG
  334.     if (debug)
  335.         fprintf(ofp, "\t\t* ref(%04x), set(%04x), live(%04x)",
  336.             reg_ref(ip), reg_set(ip), ip->live);
  337. #endif
  338.     fprintf(ofp, "\n");
  339. }
  340.  
  341. static    void
  342. putop(op)
  343. register struct    opnd    *op;
  344. {
  345.     switch (op->amode & MMASK) {
  346.     case NONE:
  347.         break;
  348.     case REG:
  349.         fprintf(ofp, "%s", rstr(op->areg));
  350.         break;
  351.     case IMM:
  352.         if (op->amode & SYMB)
  353.             fprintf(ofp, "#%s", op->astr);
  354.         else
  355.             fprintf(ofp, "#%ld", op->disp);
  356.         break;
  357.     case ABS:
  358.         fprintf(ofp, "%s", op->astr);
  359.         break;
  360.     case REGI:
  361.         if (op->amode & DEC)
  362.             fprintf(ofp, "-");
  363.         fprintf(ofp, "(%s)", rstr(op->areg));
  364.         if (op->amode & INC)
  365.             fprintf(ofp, "+");
  366.         break;
  367.     case REGID:
  368.         fprintf(ofp, "%ld(%s)", op->disp, rstr(op->areg));
  369.         break;
  370.     case REGIDX:
  371.         fprintf(ofp, "%ld(%s,", op->disp, rstr(op->areg));
  372.         fprintf(ofp, "%s.%c)", rstr(op->ireg),
  373.             (op->amode & XLONG) ? 'l' : 'w');
  374.         break;
  375.     case PCD:
  376.         fprintf(ofp, "%ld(pc)", op->disp);
  377.         break;
  378.     case PCDX:
  379.         fprintf(ofp, "%ld(pc,%s.%c)", op->disp, rstr(op->ireg),
  380.             (op->amode & XLONG) ? 'l' : 'w');
  381.         break;
  382.     default:
  383.         fprintf(stderr, "bad addr. mode in putop: %d\n", op->amode);
  384.  
  385. /* CHANGED BY TETISOFT */
  386. /*        exit(1); */
  387.         exit(EXIT_FAILURE);
  388.  
  389.     }
  390. }
  391.  
  392. static    char *
  393. rstr(r)
  394. register char    r;
  395. {
  396.     static    char    buf[3];
  397.  
  398.     if (r == SP) {
  399.         buf[0] = 's';
  400.         buf[1] = 'p';
  401.     } else if (r >= A0 && r <= A6) {
  402.         buf[0] = 'a';
  403.         buf[1] = '0' + (r - A0);
  404.     } else {
  405.         buf[0] = 'd';
  406.         buf[1] = '0' + (r - D0);
  407.     }
  408.     buf[2] = '\0';
  409.  
  410.     return buf;
  411. }
  412.  
  413. /*
  414.  * opeq(op1, op2) - test equality of the two instruction operands
  415.  */
  416. bool
  417. opeq(op1, op2)
  418. register struct    opnd    *op1, *op2;
  419. {
  420.     if (op1->amode != op2->amode || op1->areg != op2->areg ||
  421.         op1->ireg  != op2->ireg)
  422.         return FALSE;
  423.  
  424.     /*
  425.      * Depending on the addressing mode, we either need to
  426.      * compare the "astr" strings, or the displacements.
  427.      */
  428.     if ((op1->amode == ABS) || (op1->amode == (IMM|SYMB))) {
  429.         /* compare strings */
  430.         if (op1->astr == NULL)
  431.             return (op2->astr == NULL);
  432.         else {
  433.             if (op2->astr == NULL)
  434.                 return FALSE;
  435.     
  436.             return (strcmp(op1->astr, op2->astr) ==