Xinu7/src/cmd/sub11/subDIV.c

Compare this file to the similar file:
Show the results in this format:

/*
 *      DIVISION CONVERSION ROUTINE
 *
 * TO COMPILE RUN cc -O subDIV.c
 *
 *   Given an LSI-11 division instruction
 *      div a,b
 * this program will generate assembly code that will produce the equivalent
 * result. Condition codes are properly set.
 *   The replacement is done in two phases. The first runs through the
 * assembly code, replacing each "l:div A,r0" line (for example) with:
 * l:   mfps    -(sp)                   / get psw
 *      mov     A,-(sp)                 / push divisor onto the stack
 *      mov     r0,-(sp)                / push high word of dividend onto the stack
 *      mov     r1,-(sp)                / push low word of dividend onto the stack
 *      jsr     pc,over2                / call the simulation routine
 *      mov     (sp)+,r1                / save the remainder
 *      mov     (sp)+,r0                / save the quotient
 *      tst     (sp)+                   / restore the stack
 *      mtps    (sp)+                   / put in the new psw
 * (Recall that the destination register nust be even.) In no case are comments
 * provided. This follows the UNIX philosophy of incomprehensibility above all
 * else in assembly language.)
 *
 * Program by Matt Bishop, Purdue University (October 28, 1981)
 * for Doug Comer's 690d microcomputer seminar
 *
 */

/*
 * usual include crud
 */
#include <stdio.h>
#include <ctype.h>

#define LEN 30          /* max length of label, opcode, or operand */
#define DIV "div"       /* instruction to be replaced */

char label[LEN];        /* label of current assembly code line */
char operator[LEN];     /* operator of current assembly code line */
char foperand[LEN];     /* first operand of current assembly code line */
char soperand[LEN];     /* second operand of current assembly code line */
int rn;                 /* number of destination register */
int flag;               /* 1 if any substitutions were made, 0 if not */
int linect;             /* current line number */
char *pgnm;             /* name of program */

main(argc, argv)
int argc;
char **argv;
{
        char line[BUFSIZ];      /* input line */

        /* Initialize everything */
        pgnm = argv[0];
        flag = 0;
        linect = 0;

        /* phase 1 - loop through the file, line by line */
        while (fgets(line, BUFSIZ, stdin) != NULL){
                /* new line number */
                linect++;

                /* is line is a "div" instruction */
                if (finddiv(line)){

                        /* yes - be sure dest is a legal register */
                        if ((rn = isregis(soperand)) < 0 || rn > 6 || (rn&01)){
                                fprintf(stderr, "%s, line %d: second operand ", pgnm, linect);
                                fprintf(stderr, "of div must be an even numbered");
                                fprintf(stderr, " register\n");
                                printf("%s", line);
                                continue;
                        }

                        /* phase 1 substitution - see header comments */
                        flag = 1;
                        if (*label)
                                printf("%s:\t", label);
                        else
                                printf("\t");
                        printf("mfps\t-(sp)\n");
                        printf("\tmov\t%s,-(sp)\n", foperand);
                        printf("\tmov\t%s,-(sp)\n", soperand);
                        printf("\tmov\tr%d,-(sp)\n", rn+1);
                        printf("\tjsr\tpc,over2\n");
                        printf("\tmov\t(sp)+,r%d\n", rn+1);
                        printf("\tmov\t(sp)+,%s\n", soperand);
                        printf("\ttst\t(sp)+\n");
                        printf("\tmtps\t(sp)+\n");
                }
                else    /* not a "div" instruction - print whatever's there */
                        printf("%s", line);
        }

}

/*
 * returns -1 if its arg is not a register, number if it is
 */
int isregis(s)
char *s;
{
        if (s[0] != 'r' || s[2] != '\0')
                return(-1);
        return(s[1] - '0');
}

/*
 * This parses the input line
 */
int finddiv(s)
char *s;
{
        /* get label and operator (if any) */
        getlabel(&s, label);
        getoper(&s, operator);

        /* if not DIV, don't go on */
        if (strcmp(operator, DIV) != 0)
                return(0);

        /* it's a DIV -- get the operands */
        getand(&s, foperand);
        getand(&s, soperand);

        /* be sure they're really there */
        if (*foperand == '\0' || *soperand == '\0'){
                fprintf(stderr, "%s, line %d: div takes 2 operands\n", pgnm, linect);
                return(0);
        }

        /* success */
        return(1);
}

/*
 * This gets a label (if any) from the input line
 * Legal label chars are alphanumerics and _.~
 */
getlabel(s, l)
char **s, *l;
{
        char *p, *lp;

        /* grab first identifier on line */
        for(p = *s, lp = l; isalnum(*p) || *p == '_' || *p == '.' || *p == '~'; p++, lp++)
                *lp = *p;
        /* it's a label */
        if (*p == ':'){
                *lp = '\0';
                for(p++; isspace(*p); p++);  /* eat trailing spaces */
                *s = p;
        }
        else    /* bullfeathers */
                *l = '\0';
        return;
}

/*
 * This gets an operator (if any) from the input line
 * Legal operator chars are alphanumerics
 */
getoper(s, l)
char **s, *l;
{
        char *p;

        /* grap next identifier */
        for(p = *s; isalnum(*p); p++, l++)
                *l = *p;

        /* eat trailing spaces */
        for(; isspace(*p); p++);

        *l = '\0';
        *s = p;
        return;
}

/*
 * This gets an operand (if any) from the input line
 * Legal operand chars are alphanumerics and $()+-_.
 */
getand(s, l)
char **s, *l;
{
        char *p;

        /* grab the identifier */
        for(p = *s; isalnum(*p) || *p == '$' || *p == '(' || *p == ')' || *p == '-' || *p == '+' || *p == '.' || *p == '_'; p++, l++)
                *l = *p;

        /* eat trailing comma, spaces */
        if (*p == ',')
                p++;
        for(; isspace(*p); p++);

        *l = '\0';
        *s = p;
        return;
}