home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / sigm / vol140 / seg1x68.c < prev    next >
Encoding:
C/C++ Source or Header  |  1984-04-29  |  15.8 KB  |  675 lines

  1. /*    X68 Cross Assembler Overlay Segment SEG1    */
  2. /*    Pass One of assembly.                */
  3.  
  4. /*
  5.  *    PERMISSION IS GRANTED FOR THE PUBLIC DOMAIN
  6.  *    NON COMMERCIAL USE OF THIS SOFTWARE.
  7.  *
  8.  *    (C) CHRIS UNDERY 25th OCTOBER 1982
  9.  *    11 MARGARET ST NEWTOWN 2042
  10.  *    SYDNEY, AUSTRALIA
  11.  */
  12.  
  13. /*    NOTE
  14.  
  15.     Parts of this program were translated from a Reality
  16.     DATA/BASIC program .In particular, it was necessary 
  17.     to keep some `line numbers`. These are used as goto 
  18.     labels , passed to functions and returned as values
  19.     from functions. The latter useage is somewhat obscure
  20.     but should become apparent upon studying the functions.
  21.  
  22.     Major Changes from Data Basic Version
  23.  
  24.     1.    Allowed use of Tektronix mnemonics
  25.  
  26.     2.    Hash group linked symbol table (fast)
  27.  
  28.     3.    Expression evaluator
  29.  
  30.     4.    BIAS psuedo op for ROM system development
  31.  
  32.     5.    Origin of assembly can be set by console command
  33.  
  34.     6.    Symbol table dump to file and listing device
  35.  
  36.     7.    Intel hex output with adjustable address field
  37.  
  38.     8.    Optional pre-processor overlay
  39.  
  40.     9.    listing controls inlc titles 
  41.  
  42.     10.    single level include operation
  43.  
  44.     11.    symbol table can be purged of local symbols  
  45.  
  46. */
  47.  
  48. #include "x68.h"
  49. #define COMMENT ';'
  50.  
  51. main()
  52. {
  53.     char temp[150], ip_name[20], op_name[20];
  54.     int opc;            /* Result code */
  55.  
  56.     strcpy(title,"\t\t\t\t");
  57.     including = bias = 0;            /* clear rom bias */
  58.     printf("Pass one (Version A.1)\n");
  59.     strcpy(ip_name,filename);    /* Get input file name    */
  60.     if (index(ip_name,".") < 0 ) strcat(ip_name,".ASM");
  61.     strcpy(iname,ip_name);
  62.     if (fopen(ip_name,ibuf) == ERROR) {
  63.         printf("Cannot open: %s\007\n",ip_name);
  64.         exit();
  65.     }
  66.     strcpy(op_name,filename);    /* Create UFN.TMP    */
  67.     strcat(op_name,".TMP");
  68.     if (fcreat(op_name,obuf) == ERROR ) {
  69.         printf("DISK FULL: %s\007\n",op_name);
  70.         exit();
  71.     }
  72.     lineno = errors = 0;
  73. aloop:    if (!including) {        /* if doing single level include */
  74.                if (fgets(line,ibuf)) {
  75.             if (line[0] == '\n') {    /* cater for blank lines */
  76.                 fprintf(obuf,";\n");
  77.             }
  78.             else {
  79.                 opc = assemble();
  80.                 if (opc == 33) goto endop;
  81.                 if (opc != 10) fputs(line,obuf);
  82.                 numbytes += nb;
  83.             }
  84.             goto aloop;  /* get another load of code */
  85.         }
  86.         else goto endop;     /* have eof in primary source file */
  87.     }
  88.     else {            /* we are including */
  89.         while (fgets(line,ifile)) {
  90.             if (line[0] == '\n') {
  91.                 fprintf(obuf,";\n");
  92.             }
  93.             else {
  94.                 opc = assemble();
  95.                 numbytes += nb;
  96.                 if (opc == 33) goto incend;
  97.                 if (opc != 10) fputs(line,obuf);
  98.             }
  99.     
  100.         }
  101. incend:    including = 0;    /* no longer including */
  102.     fclose(ifile);    /* close the file buffer for next include */
  103.     goto aloop;    /* get next load from primary instead */
  104.     }
  105. endop:    numlines = lineno;        /* For statistics */
  106.     fclose(ibuf);
  107.     putc(0x1a,obuf);
  108.     fflush(obuf);            /* Flush all buffers    */
  109.     fclose(obuf);            /* And terminate pass1  */
  110.     return(1);
  111. }
  112.  
  113. /*    Assemble Next line of source code from LINE    */
  114. /*    placing output to UFN.TMP            */
  115.  
  116. assemble()
  117. {
  118.     int result;            /* Operation result handshake */
  119.     char c;
  120.     tokenise();            /* Next TOKENS please    */
  121.     c = label[0];            /* Test for comment and null */
  122.     if ( c == ';' || c == '*' ) return(1);
  123.     if (index(mnem,"END") >=0 ) return(33); /* End of processing */
  124.     if (index(mnem,"INCLUDE") >= 0) {
  125.         including = 1;        /* start including */
  126.         iname[0] = '\0';
  127.         strcat(iname,operand);    /* open file */
  128.         strcat(iname,".ASM");
  129.         printf("Including %s\n",iname);
  130.         if (fopen(iname,ifile) == ERROR) {
  131.             printf("\nCannot open include file\n");
  132.             exit();
  133.         }
  134.         label[0] = ';';        /* make into a comment */
  135.         return(10);
  136.     }
  137.     if (index(mnem,"SPACE") >= 0) return(1);
  138.     if (index(mnem,"NOLIST") >= 0) return(1);
  139.     if (index(mnem,"LIST") >= 0) return(1);
  140.     if (index(mnem,"PAGE") >= 0) return(1);
  141.     if (index(mnem,"TITLE") >= 0) return(1);
  142.     if (index(mnem,"PURGE") >= 0) { /* purge local symbols */
  143.         purge(operand);
  144.         return(10);        /* dont write to listing file */
  145.     }
  146.     blankem();            /* Initialise assy registers    */
  147.     if (newlab() == 90) {        /* New label handler    */
  148.         wrapup();
  149.         return(1);        /* error so write line as is */
  150.         }
  151.     if (index(mnem,"EQU") >= 0 ) {    /* Piss off easy ones    */
  152.         wrapup();
  153.         return(1);
  154.         }
  155.     if (index(mnem,"ORG") >= 0 ) {    /* set location counter */
  156.         wrapup();
  157.         return(1);
  158.         }
  159.     if (index(mnem,"BLOCK") >= 0 ) {    /* reserve memory space */
  160.         wrapup();
  161.         return(1);
  162.         }
  163.     if (index(mnem,"ASCII") >= 0 ) {    /* inline string */
  164.         return(fcc());
  165.         }
  166.     if (index(mnem,"BYTE") >= 0 ) {        /* form constant byte */
  167.         return(fcb('b'));
  168.         }
  169.     if (index(mnem,"HALT") >= 0 ) {    /* Do adm special instruction */
  170.         halt();
  171.         return(10);
  172.         }
  173.     if (index(mnem,"WORD") >= 0 ) {
  174.         return(fcb('w'));    /* word sized operation */
  175.         }
  176.     if (index(mnem,"BIAS") >=0 ) {    /* get prolog m980 buffer offset */
  177.         if (!evaluate(operand)) {
  178.             fault(600);
  179.         }
  180.         nb = 0;            /* Dont generate code */
  181.         bias = dec;
  182.         strcpy(i1,"  ");
  183.         wrapup();
  184.         return(1);
  185.     }        
  186.     idecode();            /* Do Instruction decode */
  187.     wrapup();            /* Create *.TMP record */
  188. }
  189.  
  190. newlab()    /* Extract label and put in symbol table    */
  191. {
  192.     struct nlist *sp, *lookup(), *install();
  193.     char ind_ref[16];        /* trick string */
  194.  
  195.     if (index(mnem,"ORG") >= 0) {    /* Handle new origin */
  196.         if (!evaluate(operand)) fault(600);
  197.         decad = dec;        /* get result */
  198.         nb = 0;
  199.         strcpy(i1,"  ");
  200.         }
  201.     tohex(hexad,decad);
  202.     if (label[0] == '\0') goto N15;    /* But must check for RMB */
  203.     if ((sp = lookup(label)) == NULL) goto N15; /* if new pass over here */
  204.     strcpy(labrec,sp->def);        /* Move out of dynamic store */
  205.     if (labrec[0] != '?') {        /* A duplicity of labels */
  206.         fault(14);
  207.         return(90);        /* Tell proc above we fucked out */
  208.         }
  209.     strcpy(labrec,hexad);        /* else copy address to symbol def */
  210.   N15:  if (index(mnem,"BLOCK") >= 0) {    /* reserve space operation */
  211.         if (!evaluate(operand)) fault(600);
  212.         nb = dec;        /* Get result */
  213.         strcpy(i1,"  ");    /* no machine code to generate */
  214.         }
  215.     if (label[0] == NULL ) return(1); /* Fix bug in original vers */
  216.     if (index(mnem,"EQU") < 0 ) {    /* Perform EQUATE operation */
  217.         strcpy(labrec,hexad);
  218.         goto N18;
  219.         }
  220.     if (evaluate(operand)) {    /* dont be fooled by this */
  221.         tohex(labrec,dec);    /* assume good operation */
  222.         getsub(operand);    /* if either = ?? ng */
  223.         if ((sp = lookup(xp1)) != NULL) {
  224.             if (index(sp->def,"??") >= 0) goto NG;
  225.         }
  226.         if ((sp = lookup(xp2)) != NULL) {
  227.             if (index(sp->def,"??") >= 0) goto NG;
  228.         }
  229.     }
  230.     else {                /* we have complex on pass 1 */
  231.     NG:    strcpy(labrec,"????");
  232.         strcpy(i1,"  ");
  233.         strcpy(i2,"??");
  234.         strcpy(i3,"??");    /* throw unresolved label into st */
  235.         if ((sp = install(label,labrec)) == NULL) {
  236.             printf("SYMBOL TABLE FULL\n");
  237.             exit();
  238.         }
  239.         nb = 0;            /* dont increment address cntr */
  240.         return(1);        /* dont install complex exp ! */
  241.     }
  242.   N16:  strcpy(i1,"  ");        /* Now fix up assy registers */
  243.     strcpy(brad,labrec);
  244.     nb = 0;
  245.     strcpy(hexad,"    ");
  246.   N18:    if ((sp = install(label,labrec)) == NULL ) {
  247.         printf("\nLine %d SYMBOL TABLE OVERFLOW\007\n",lineno);
  248.         exit();            /* TERMINATE OVERLAY */
  249.         }
  250.     return(1);            /* Else good result */
  251. }
  252.  
  253.  
  254. tokenise()    /* Break down line into TOKENS    */
  255. {
  256.     lineno++;
  257.     getok(label,line,1,8);    /* Parse input line */
  258.     getok(mnem,line,2,9);
  259.     getok(operand,line,3,16); /* Could be complex expr */
  260.     getcomment(line);
  261.     if (index(comment,"\n") < 0) strcpy(comment,"\n");
  262.     return(1);
  263. }
  264.  
  265. blankem()    /* Clear assembler registers */
  266. {
  267.     strcpy(i1,"??");    /* Indicate unresolved instruction */
  268.     strcpy(i2,"  ");    /* and clear other registers    */
  269.     strcpy(i3,"  ");
  270.     strcpy(brad,"    ");
  271.     nb = 3;            /* Assume 3 byte instruction    */
  272. }
  273.  
  274. wrapup()    /* Recombine Tokens and new data for output line */
  275. {
  276.     tohex(hexad,decad);    /* Calculate HEXaddress */
  277.     strcpy(line,hexad);    /* Hex address first */
  278.     strcat(line," ");
  279.     strcat(line,i1);    /* Machine instruction 1 */
  280.     strcat(line," ");
  281.     strcat(line,i2);    /* Machine instruction 2 */
  282.     strcat(line,i3);    /* Machine instruction 3 */
  283.     strcat(line," ");
  284.     strcat(line,brad);    /* Branch address */
  285.     strcat(line," ");
  286.     strcat(line,label);    /* Label must LEFT JUSTIFY IT LATER */
  287.     strcat(line,"\t");    /* TAB will do just fine */
  288.     strcat(line,mnem);    /* Mnemonic */
  289.     strcat(line,"\t");
  290.     strcat(line,operand);    /* Operand */
  291.     strcat(line,"\t");
  292.     strcat(line,comment);    /* Comments fill up remainder */
  293.     decad += nb;        /* Adjust PC for next line through */
  294. }
  295.  
  296. idecode()    /* INSTRUCTION DECODER LOGIC    */
  297. {
  298.     char x;
  299.  
  300.     if (!binary(mnem)) {    /* Mnemonic not found in table */
  301.         fault(20);    /* Error code 20 */
  302.         return(90);    /* Indicate error to procs above */
  303.     }
  304.     strcpy(i1,inst);    /* Get instruction from table */
  305.     
  306.     switch(dest[0])    {    /* Use steering logic from table */
  307.  
  308.         case '1': { 
  309.             if (operand[0] != '\0') {
  310.                 strcpy(temp," ");
  311.                 strcat(temp,operand);
  312.                 strcat(temp,comment);
  313.                 strcpy(comment,temp); /* moove it back */
  314.                 operand[0] = '\0';
  315.                 } /* Second space forgotten */
  316.             nb = 1; /* Single byte instruction */
  317.             return(45);
  318.             }
  319.         case '2': return(regadr(200)); /* Register and address */
  320.         case '3':
  321.             case '4': {
  322.     I24:        if (operand[0] == '#' ) {
  323.                 fault(23);
  324.                 return(90);
  325.                 }
  326.             return(regadr(200));   /* Register etc */
  327.             }
  328.         case '5': {
  329.             strcpy(m4,"A");
  330.             return(regadr(200));   /* Reg decode */
  331.             }
  332.         case '6': {
  333.             strcpy(m4,"B");
  334.             return(regadr(200));   /* Reg decode */
  335.             }
  336.         case '7': {
  337.             strcpy(m4,"A");
  338.             return(regadr(200));
  339.             }
  340.         case '8': {
  341.             strcpy(m4,"B");
  342.             return(regadr(200));
  343.             }
  344.         case '9': return(regadr(201));    /* Branch instruction */
  345.  
  346.         }    /* End case switch */
  347.  
  348.     printf("\"Opcodes\" file is corrupted\7\n");
  349.  
  350. }    /* End Instruction Decoder Logic */
  351.  
  352.  
  353. /* Regadr is passed the old DATA BASIC line number in order */
  354. /* to force entry at the correct point */
  355.  
  356. regadr(n)    /* Register and Address decoder */
  357. int n;                    /* DATA BASIC line number */
  358. {
  359.     struct nlist *symptr, *lookup(), *install();
  360.  
  361.     if (n == 201) goto R201;    /* Its the only way */
  362.     if (operand[0] == '#') goto R210;
  363.     if (operand[0] == 'X') {
  364.         if (!isalpha(operand[1])) goto R230;
  365.     }
  366.     if (index(operand,",X") >= 0 ) goto R230; /* Index inst */
  367.  
  368.  R201:    if ((symptr = lookup(operand)) == NULL) goto R202;
  369.     strcpy(labrec,symptr->def);    /* Get definition */
  370.     if (labrec[0] == '?') goto R203;
  371.     goto R205;            /* This really sucks badly */
  372.  R202:    if (!evaluate(operand)) {       /* might just be num literal */
  373.         strcpy(labrec,"????");    /* nope.. stash it charlie */
  374.         goto R203;
  375.     }
  376.     else {
  377.         tohex(labrec,dec);
  378.     }
  379.     goto R205;
  380.  R203:    strcpy(i2,"??");
  381.  R204:    if ((symptr = install(operand,labrec)) == NULL) {
  382.         printf("SYMBOL TABLE OVERFLOW\007\n");
  383.         exit();            /* ABORT ABORT ABORT ABORT */
  384.         }
  385.  noput:    if (dest[0] == '9') {
  386.         nb = 2;
  387.         return(45);        /* Another line number */
  388.         }
  389.     strcpy(i3,"??");
  390.     goto R241;
  391.   R205:    if ((symptr = install(operand,labrec)) == NULL) {
  392.         printf("SYMBOL TABLE OVERFLOW\007\n");
  393.         exit();
  394.         }
  395.     smov(labad,labrec,4);        /* get first 4 bytes of labrec */
  396.     dlabad = todec(labad,16);    /* Convert to decimal */
  397.     if (dest[0] == '9') goto R250;    /* Relative address */
  398.     if (dest[0] == '3') goto R240;    /* Extended */
  399.     if (m4[0] == SP) goto R240;    /* Extended */
  400.     if (dest[0] == '7') goto R240;    /* cannot have 2byte jsr */
  401.     if (dlabad > 256 || dlabad < 0) goto R240;    /* Extended */
  402.     if (m4[0] == '\0') goto R240;    /* Hope to trap nasties */
  403.     goto R220;            /* Direct addressing */
  404.  R210:    nb = 2;
  405.     class[0] = operand[1];    /* Determine operand class */
  406.     if (m4[0] == 'A') insert(i1,'8');
  407.     if (m4[0] == 'B') insert(i1,'C');
  408.     if (dest[0] > '4') goto R215;    /* CPX LDX or LDS */
  409.     if (!evaluate(operand)) {
  410.         fault(210);
  411.         return(90);
  412.     }
  413.     tohex(hex,dec);            /* Convert result to hex */
  414.     smov(i2,&hex[2],2);
  415.     return(45);
  416.  R215:    nb = 3;
  417.     strcpy(i3,"  ");
  418.     if (!evaluate(operand)) {    /* assume pass 2 will fix it */
  419.         strcpy(i2,"??");strcpy(i3,"??");
  420.         return(90);
  421.     }
  422.     tohex(hex,dec);        /* Get result of op */
  423.     smov(i2,&hex[0],2);
  424.     smov(i3,&hex[2],2);    /* fix bug with lds ldx etc vers a.1 */
  425.     return(45);
  426.  R220:    nb = 2;
  427.     smov(i2,&labad[2],2);
  428.      if (m4[0] == 'A') {
  429.         insert(i1,'9');
  430.         return(45);
  431.         }
  432.     if (m4[0] == 'B') {
  433.         insert(i1,'D');
  434.         return(45);
  435.         }
  436.     fault(220);
  437.     return(90);
  438.  R230:    nb = 2;
  439.     if (!getexp(temp,operand)) dec = 0;
  440.     else evaluate(temp);
  441.     tohex(hex,dec);
  442.     smov(i2,&hex[2],2);
  443.     if (m4[0] == '\0') {
  444.         insert(i1,'6');
  445.         return(45);
  446.         }
  447.     if (m4[0] == 'A') {
  448.         insert(i1,'A');
  449.         return(45);
  450.         }
  451.     if (m4[0] == 'B') {
  452.         insert(i1,'E');
  453.         return(45);
  454.         }
  455.     fault(231);
  456.     return(90);
  457.  R240:    strcpy(i2,labad);
  458.     i3[0] = '\0';
  459.  R241:    if (m4[0] == '\0') {        /* Label not known */
  460.         insert(i1,'7');
  461.         return(45);
  462.         }
  463.     if (m4[0] == 'A') {
  464.         insert(i1,'B');
  465.         return(45);
  466.         }
  467.     if (m4[0] == 'B') {
  468.         insert(i1,'F');
  469.         return(45);
  470.         }
  471.     fault(241);
  472.     return(90);
  473.  R250:    dec = dlabad - decad + 254;    /* Label known */
  474.     if (dec < 128 ) {
  475.         fault(250);
  476.         return(90);
  477.         }
  478.     if (dec > 383) {
  479.         fault(251);
  480.         return(90);
  481.         }
  482.     tohex(hex,dec);
  483.     smov(i2,&hex[2],2);
  484.     nb = 2;
  485.     strcpy(brad,labad);
  486.     return(45);
  487. }
  488.  
  489. getexp(to,from)        /* Get expression delimted by COMMA */
  490. char *to, *from;
  491. {
  492.     while (*to = *from) {    /* Move characters */
  493.         if (*to == COMMA) {
  494.             *++to = NULL;
  495.             return(1);
  496.         }
  497.         to++;
  498.         from++;
  499.     }
  500.     return(0);
  501. }
  502.  
  503. getnxtp(to, from, n)
  504. char *to, *from;
  505. int n;
  506. {
  507.     int count;
  508.     count = 0;
  509.     while (count != n) {
  510.         if (*from == COMMA) count++;
  511.         if (*from == NULL) {
  512.             *to = NULL;
  513.             return(0);
  514.         }
  515.         from++;
  516.     }
  517.     getexp(to, from);
  518. }
  519.  
  520.  
  521. insert(s,c)    /* Insert character in front of string */
  522. char s[], c;
  523. {
  524.     s[1] = s[0];    /* move first character back one space */
  525.     s[0] = c;    /* plonk character in front */
  526.     s[2] = '\0';    /* terminate the string */
  527. }
  528.  
  529. fcc()        /* STRING psuedo op */
  530. {
  531.     int byteno, i;
  532.     int j;
  533.     char up;
  534.     int commacnt;
  535.     up = 1;
  536.      commacnt = 0;
  537.     byteno = j = 0;
  538.     while (up) {
  539.         if ((operand[j] == 0x22) || (operand[j] == 0x27)) {
  540.             j++;
  541.             commacnt++;
  542.             if (commacnt == 2) up = 0;
  543.         }
  544.         else {
  545.             temp[0] = 0x22;
  546.             temp[1] = operand[j];
  547.             temp[2] = '\0';
  548.             evaluate(temp);
  549.             tohex(hex,dec);
  550.             smov(i1,&hex[2],2);
  551.             buildline(++byteno,'b');
  552.             j++;
  553.         }
  554.     }
  555.     return(10);
  556. }
  557.  
  558. fcb(n)        /* byte or word psuedo operations */
  559. char n;
  560. {
  561.     int byteno, i, j;
  562.  
  563.     indx1 = indx2 = 0;
  564.     i = byteno = 0;        /* Assume no bytes ! */
  565.     j = numargs(operand);
  566.     while (i++ < j) {    /* Loop through arguments */
  567.         movenxt();
  568.         if (n == 'b') {    /* do byte specifics */
  569.             if (!evaluate(temp)) {
  570.                  strcpy(i1,"??");
  571.             }
  572.             else {
  573.                 tohex(hex,dec);    /* Extract value */
  574.                 smov(i1,&hex[2],2);
  575.             }
  576.         }
  577.         else {     /* word operation */
  578.             if (!evaluate(temp)) {
  579.                 strcpy(i1,"   ");
  580.                 strcpy(i2,"??");
  581.                 strcpy(i3,"??");
  582.             }
  583.             else {
  584.                 tohex(hex,dec);
  585.                 smov(i2,&hex[0],2);
  586.                 smov(i3,&hex[2],2);
  587.             }
  588.         }
  589.     buildline(++byteno,n);
  590.     }
  591.     return(10);
  592. }
  593.  
  594. movenxt()        /* Move next argument into temp string */
  595. {
  596.     int i;        /* String index */
  597.     char movf;    /* boolean control flg */
  598.  
  599.     i =  0;
  600.     movf = 1;
  601.     while (movf)    {
  602.         temp[i] = operand[indx1];    /* Use global for memory */
  603.         if ((temp[i] == NULL) || (temp[i] == ',')) {
  604.             indx1++;    /* Crank index for next */
  605.             temp[i] = NULL;
  606.             movf = 0;    /* Make flag false */
  607.         }
  608.         else {
  609.             i++;    /* BUmp pointers */
  610.             indx1++;
  611.         }
  612.     }
  613. }    
  614.  
  615. buildline(bn,n)        /* Build output line for BYTE, STRING */
  616. int bn,n;
  617. {
  618.     if (bn == 1) {    /* First time into this shit */
  619.         tohex(hexad,decad);
  620.         strcpy(line,hexad);    /* wish I had good cat function */
  621.         strcat(line," ");
  622.         if (n == 'b') {
  623.             strcat(line,i1);
  624.                 strcat(line,"           ");
  625.         }
  626.         else {
  627.             strcat(line,"   ");
  628.             strcat(line,i2);
  629.             strcat(line,i3);
  630.             strcat(line,"       ");
  631.         }
  632.         strcat(line,label);
  633.         strcat(line,"\t");
  634.         strcat(line,mnem);
  635.         strcat(line,"\t");
  636.         strcat(line,operand);
  637.         strcat(line,"\t");
  638.         strcat(line,comment);
  639.     }
  640.     else {
  641.         tohex(hexad,decad);    /* Bump address */
  642.         strcpy(line,hexad);
  643.         strcat(line," ");
  644.         if (n != 'b') {
  645.             strcat(line,"   ");
  646.             strcat(line,i2);
  647.             strcat(line,i3);
  648.         }
  649.         else strcat(line,i1);
  650.         strcat(line,"\n");    /* Add newline character */
  651.     }
  652.     fputs(line,obuf);        /* Internal write */
  653.     if (n == 'b') decad += 1;
  654.     else decad += 2; /* for word operation */
  655. }
  656.  
  657. /* this function handles the macro instruction HALT which */
  658. /* is used by the ADM31/32 firmware. The instruction is added */
  659. /* as a `built-in' */
  660.  
  661. halt()        
  662. {
  663.     tohex(hexad,decad);
  664.     strcpy(line,hexad);
  665.     strcat(line,"+B7 7000 ####\tHALT\t");
  666.     fputs(line,obuf);
  667.     fputs(comment,obuf);        /* for user noise */
  668.     decad += 3;
  669.     tohex(hexad,decad);
  670.     strcpy(line,hexad);
  671.     strcat(line,"+01      ####\n");
  672.     fputs(line,obuf);
  673.     decad++;
  674. }
  675.