/*************************************************************************** * Copyright (C) 2004 by Charles Crayne * * chuck@heimdall * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "asm8008.h" int main(int argc, char *argv[]) { int actr = 0; // address counter int octr = 0; // offset counter int entrypt = 0; // entry point int loc, page, tloc, tpage, taddr, pgmlength, opcode, port, i, data1, data2; char *ofname; /* check for input parms */ if (argc < 2) { printf("Version 0.2.0 Usage: asm8008 asmfile\n"); return EXIT_FAILURE; } else { /* process input parms */ } /* load op code table */ sprintf(parse,"%s/bin/opcodes.8008",getenv("HOME")); if ((opcodefp = fopen(parse,"r")) == NULL) { printf("Opcode table not found in %s\n",parse); return EXIT_FAILURE; } else { /* Initialize null entry to handle blank lines & various errors */ optbl[opcodeCount].opsym = NULL; optbl[opcodeCount].opcode = 0; optbl[opcodeCount].ilength = 0; while (!(items = fscanf(opcodefp,"%s %3o %d", line,&optbl[opcodeCount].opcode,&optbl[opcodeCount].ilength) == EOF)) { lp = (char *) malloc(strlen(line)); strcpy(lp,line); optbl[opcodeCount].opsym = lp; opcodeCount++; } fclose(opcodefp); /* open input file */ if ((infp = fopen(argv[1],"r")) == NULL) { printf("Input file not found\n"); return EXIT_FAILURE; } else { /* Pass 1 - Build Symbol Table */ while (fgets(line,MAXLINE,infp)) { inx = parseLine(); len = optbl[inx].ilength; if (!len) { // directive switch (optbl[inx].opcode) { case 0: // RADIX if (imm) defrad = asctoi(imm); if ((defrad < 2) || (defrad > 36)) defrad = 8; break; case 1: // ORG if (!actr) { if (imm && pg) actr = (asctoi(imm) + (asctoi(pg) << 8)); } else if (imm && pg) { len = (asctoi(imm) + (asctoi(pg) << 8)) - actr; } break; case 2: // LDR if (!octr) { loader = true; } break; case 3: // ENTRY if (!octr) { loader = true; entry = true; } break; case 4: // EQU directive if (imm) addLabel(tgt,asctoi(imm)); break; case 6: // DS directive if (tic1 && tic2) len = tic2 - tic1; else if (imm) len = evalExpr(imm); else len = 0; break; case 7: // DB directive len = oprndcnt; break; case 8: // DW directive len = 2*oprndcnt; break; } } if (lbl) addLabel(lbl,actr); actr += len; octr += len; } } /* Pass 2 - Generate code and listing */ fseek(infp,0,SEEK_SET); actr = 0; pgmlength = octr; octr = 0; errcnt = 0; pass = 2; defrad = 8; /* open object file */ ofname = (char *) malloc(strlen(argv[1])+4); strcpy(ofname,argv[1]); if (lp = strchr(ofname,'.')) { lp[0] = 0; } if (loader) strcat(ofname,".ldr"); else strcat(ofname,".bin"); if ((outfp = fopen(ofname,"w")) == NULL) { printf("Failure creating output file\n"); return EXIT_FAILURE; } while (fgets(line,MAXLINE,infp)) { inx = parseLine(2); len = optbl[inx].ilength; loc = actr & 0377; page = (actr & 037400) >> 8; if (loader && (len || (optbl[inx].opcode >= 6))) { if (!entry) entrypt = actr; putc(entrypt & 0377,outfp); putc((entrypt & 037400) >> 8,outfp); putc(actr & 0377,outfp); putc((actr & 037400) >> 8,outfp); putc(pgmlength & 0377,outfp); putc((pgmlength & 037400) >> 8,outfp); loader = false; } switch (len) { case 0: // Directives and comment lines switch (optbl[inx].opcode) { case 1: // ORG if (!actr) { if (imm && pg) actr = ((int) asctoi(imm) + ((int) asctoi(pg) << 8)); } else if (imm && pg) { len = (asctoi(imm) + (asctoi(pg) << 8)) - actr; tloc = 0; if (len) { for (i=0;i 36)) defrad = 8; break; case 4: // EQU case 5: // END break; case 6: // DS if (imm) len = evalExpr(imm); if (!tic1) { // check for fill char if (tic2) tloc = evalExpr(tic2); else tloc = 0; if (len) { for (i=0;i> 8; putc(data1,outfp); putc(data2,outfp); if (i < 2) printf(" %.3o %.3o",data1,data2); } } else { errcnt++; printf("Missing operand\n"); } break; default: // Invalid directive printf("Invalid directive: %s\n",op); errcnt++; break; } printf(" %s",line); break; case 1: // single byte instructions opcode = optbl[inx].opcode; if ((port = byteOperand()) == -1) port = 0377; if (opcode == 0101) { // INP if (port > 7) { errcnt++; printf("Invalid input port number\n"); } else opcode |= (port << 1); } else if (opcode == 0121) { //OUT if ((port < 8) || (port > 31)) { errcnt++; printf("Invalid output port number\n"); } else opcode = (port << 1) | 0101; } else if (opcode == 005) { //RST if (port > 7) { errcnt++; printf("Invalid RST address\n"); } else opcode |= (port << 3); } putc(opcode,outfp); printf("%.2o %.3o %.3o %-s", page,loc,opcode,line); break; case 2: // immediate instructions if ((tloc = byteOperand()) == -1) tloc = 0; putc(optbl[inx].opcode,outfp); putc(tloc,outfp); printf("%.2o %.3o %.3o %.3o %-s", page,loc,optbl[inx].opcode,tloc,line); break; case 3: // instructions with target address if ((taddr = wordOperand()) == -1) taddr = 0; tloc = taddr & 0377; tpage = (taddr & 037400) >> 8; putc(optbl[inx].opcode,outfp); putc(tloc,outfp); putc(tpage,outfp); printf("%.2o %.3o %.3o %.3o %.3o %-s", page,loc,optbl[inx].opcode,tloc,tpage,line); break; default: break; } actr += len; octr += len; } } printLabel(); if (!errcnt) printf("No errors were flagged in this assembly\n"); else if (errcnt == 1) printf("1 error was flagged in this assembly\n",errcnt); else printf("%d errors were flagged in this assembly\n",errcnt); return EXIT_SUCCESS; } /* Parse input line */ int parseLine() { int i, oct; char wsp[] = " \t\n\r"; char wspc[] = " \t\n\r,"; char eol[] = "\n\r"; i = 0; while ((parse[i] = toupper(line[i]))) i++; //copy to parse buffer as upper case lbl = tgt = pn = imm = pg = tic1 = tic2 = cmt = NULL; // clear token pointers op = strtok(parse,wsp); //find first token if (!op) return 0; // blank line if (op[0] == '/' || (op[0] == ';')) { // comment only line cmt = op; op = NULL; return 0; } /* Test for Label */ if ((lp = strchr(op,',')) || (lp = strchr(op,':'))) { lp[0] = 0; // remove delimiter lbl = op; op = strtok(NULL,wsp); } if (!op) return 0; // label only line /* Test for Symbolic Op Code */ if (isdigit(op[0])) { // hard coded op code oct = (int) asctoi(op); for (i = 1; i < opcodeCount; i++) { if (oct == optbl[i].opcode) break; } if (i == opcodeCount) if (pass == 2) { errcnt++; printf("Unknown opcode: %.3o\n",oct); } } else { // symbolic op code for (i = 1; i < opcodeCount; i++) { if (!strcmp(op,optbl[i].opsym)) break; } if (i == opcodeCount) { if (pass == 2) { printf("Unknown opcode: %s\n",op); errcnt++; } return 0; } } switch (optbl[i].ilength) { case 3: // Need either symbolic target, or hard coded address & page tgt = strtok(NULL, wsp); if ((!tgt) || (tgt[0] == '/') || (tgt[0] == ';')) { if (pass == 2) { errcnt++; printf("Missing target address\n"); } return i; } if (isdigit(tgt[0])) { // hard coded imm = tgt; tgt = NULL; pg = strtok(NULL, wsp); } break; case 2: // Need immediate byte tgt = strtok(NULL, wsp); if ((!tgt) || (tgt[0] == '/') || (tgt[0] == ';')) { if (pass == 2) { errcnt++; printf("Missing immediate value\n"); } return i; } if (isdigit(tgt[0])) { // hard coded imm = tgt; tgt = NULL; } break; case 1: // Need immediate byte for special cases if ((!strcmp(op,"INP")) || (!strcmp(op,"OUT")) || (!strcmp(op,"RST"))) { tgt = strtok(NULL, wsp); if ((!tgt) || (tgt[0] == '/') || (tgt[0] == ';')) { if (pass == 2) { errcnt++; printf("Missing immediate value\n"); } return i; } if (isdigit(tgt[0])) { // hard coded imm = tgt; tgt = NULL; } } break; case 0: // comment or directive switch (optbl[i].opcode) { case 0: // RADIX need immediate value imm = strtok(NULL, wsp); if ((!imm) || (imm[0] == '/') || (imm[0] == ';')) { if (pass == 2) { errcnt++; printf("Missing operand\n"); } return i; } break; case 1: // ORG Need hard coded page & address pg = strtok(NULL, wsp); if ((!pg) || (pg[0] == '/') || (pg[0] == ';')) { if (pass == 2) { errcnt++; printf("Missing page value\n"); } return i; } imm = strtok(NULL, wsp); if ((!imm) || (imm[0] == '/') || (imm[0] == ';')) { if (pass == 2) { errcnt++; printf("Missing address value\n"); } return i; } break; case 2: // HDR need nothing break; case 3: // ENTRY Need either symbolic target, or hard coded address & page tgt = strtok(NULL, wsp); if ((!tgt) || (tgt[0] == '/' || (tgt[0] == ';'))) { if (pass == 2) { errcnt++; printf("Missing target address\n"); } return i; } if (isdigit(tgt[0])) { // hard coded imm = tgt; tgt = NULL; pg = strtok(NULL, wsp); if ((!pg) || (pg[0] == '/' || (pg[0] == ';'))) { if (pass == 2) { errcnt++; printf("Missing page value\n"); } return i; } } break; case 4: // EQU need symbolic target & immediate value tgt = strtok(NULL, wsp); if ((!tgt) || (tgt[0] == '/') || (tgt[0] == ';')) { if (pass == 2) { errcnt++; printf("Missing target address\n"); } return i; } imm = strtok(NULL, wsp); if ((!imm) || (imm[0] == '/') || (imm[0] == ';')) { if (pass == 2) { errcnt++; printf("Missing immediate value\n"); } return i; } break; case 5: // END and other ignored directives break; case 6: // DS need immediate value [with optional // fill char], or string constant lp = op+3; //point past DS directive if (lp[strspn(lp," ")] == '\'') // start of string constant; { tic1 = strtok(lp,"'"); imm = NULL; tic2 = tic1 + strlen(tic1); } else { imm = strtok(NULL, wspc); // find length token if ((!imm) || (imm[0] == '/') || (imm[0] == ';')) { if (pass == 2) { errcnt++; printf("Missing length value\n"); } return i; } tic2 = strtok(NULL, wsp); if ((!tic2) || (tic2[0] == '/') || (tic2[0] == ';')) tic2 = NULL; } break; case 7: // DB need one or more byte values case 8: // DW need one or more word values oprndcnt = 0; while (1) { imm = strtok(NULL, wspc); if ((!imm) || (imm[0] == '/') || (imm[0] == ';')) break; oprnds[oprndcnt] = imm; oprndcnt++; } break; default: // invalid directive if (pass == 2) { errcnt++; printf("Invalid Directive\n"); } break; } break; default: if (pass == 2) { errcnt++; printf("Invalid length for op code %s\n",optbl[i].opsym); } break; } /* Check for optional comment */ if (!cmt) cmt = strtok(NULL, eol); return i; } void addLabel(char *newlabel, int addr) { lp = (char *) malloc(strlen(newlabel)); strcpy(lp,newlabel); lbltbl[labelCount].lblsym = lp; lbltbl[labelCount].lbladdr = addr; labelCount++; } int getLabel(char *label) { int i; for (i = 0; i < labelCount; i++) { if (!strcmp(label,lbltbl[i].lblsym)) break; } if (i == labelCount) { if (pass == 2) { printf("Unknown label: %s\n",label); errcnt++; } return 0; } else return lbltbl[i].lbladdr; } void printLabel() { int i; printf("Symbol Table\n"); for (i = 0; i < labelCount; i++) { printf("%s %.2o %.3o\n",lbltbl[i].lblsym,(lbltbl[i].lbladdr & 037400) >> 8,lbltbl[i].lbladdr & 0377); } } int asctoi(char *ptr) { int result; if (strchr(ptr,'H')) result = (int) strtol(ptr,&lp,16); else if (strchr(ptr,'D')) result = (int) strtol(ptr,&lp,10); else if (strchr(ptr,'O')) result = (int) strtol(ptr,&lp,8); else if (strchr(ptr,'Q')) result = (int) strtol(ptr,&lp,8); else if (strchr(ptr,'B')) result = (int) strtol(ptr,&lp,2); else result = (int) strtol(ptr,&lp,defrad); if (isdigit(lp[0]) && (pass == 2)) { errcnt++; printf("Invalid digit for current base at: %s\n",lp); } return result; } int byteOperand() { if (tgt) return (evalExpr(tgt) & 0377); else if (imm) return (int) asctoi(imm); else return -1; } int wordOperand() { if (tgt) return evalExpr(tgt); else if (imm && pg) return (int) asctoi(imm) + ((int) asctoi(pg) << 8); else return -1; } int evalExpr(char *pstart) { char *pwork, *pparm; int symbol, value; char work[64]; if ((pwork = strpbrk(pstart,"+-*/")) == NULL) { if (isdigit(pstart[0])) return asctoi(pstart); else if ((pstart[0] == '\'') && (pstart[2] == '\'')) return pstart[1]; else return getLabel(pstart); } else { memset(work,'\0',64); strncpy(work, pstart,pwork-pstart); if (isdigit(work[0])) symbol = asctoi(work); else if ((work[0] == '\'') && (work[2] == '\'')) symbol = work[1]; else symbol = getLabel(work); value = asctoi(pwork+1); if (*pwork == '+') return symbol + value; if (*pwork == '-') return symbol - value; if (*pwork == '*') return symbol * value; if (*pwork == '/') return symbol / value; } }