Mercurial > hg > Members > kono > os9 > sbc09
view a09.c @ 0:9a224bd9b45f
os9 emulation
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 02 Jul 2018 02:12:31 +0900 |
parents | |
children | 3c736a81b886 |
line wrap: on
line source
/* A09, 6809 Assembler. created 1993,1994 by L.C. Benschop. copyleft (c) 1994-2014 by the sbc09 team, see AUTHORS for more details. license: GNU General Public License version 2, see LICENSE for more details. THERE IS NO WARRANTY ON THIS PROGRAM. Generates binary image file from the lowest to the highest address with actually assembled data. Machine dependencies: char is 8 bits. short is 16 bits. integer arithmetic is twos complement. syntax a09 [-o filename] [-l filename] sourcefile. Options -o filename name of the output file (default name minus a09 suffix) -s filename name of the s-record output file (default its a binary file) -l filename list file name (default no listing) -d enable debugging recognized pseudoops: extern public macro endm if else endif org equ set setdp fcb fcw fdb fcc rmb end include title Not all of these are actually IMPLEMENTED!!!!!! Revisions: 1993-11-03 v0.1 Initial version. 1994/03/21 v0.2 Fixed PC relative addressing bug Added SET, SETDP, INCLUDE. IF/ELSE/ENDIF No macros yet, and no separate linkable modules. 2012-06-04 j at klasek at New: debugging parameter/option. Fixed additional possible issue PC relative addressing. Compatibility: Octal number prefix "&". 2014-07-15 j at klasek at Fixed usage message. */ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <ctype.h> #define NLABELS 2048 #define MAXIDLEN 16 #define MAXLISTBYTES 8 #define FNLEN 30 #define LINELEN 128 static int debug=0; struct oprecord{char * name; unsigned char cat; unsigned short code;}; /* Instruction categories: 0 one byte oprcodes NOP 1 two byte opcodes SWI2 2 opcodes w. imm byte ANDCC 3 LEAX etc. 4 short branches. BGE 5 long branches 2byte opc LBGE 6 long branches 1byte opc LBRA 7 accumulator instr. ADDA 8 double reg instr 1byte opc LDX 9 double reg instr 2 byte opc LDY 10 single address instrs NEG 11 TFR, EXG 12 push,pull 13 pseudoops */ struct oprecord optable[]={ {"ABX",0,0x3a},{"ADCA",7,0x89},{"ADCB",7,0xc9}, {"ADDA",7,0x8b},{"ADDB",7,0xcb},{"ADDD",8,0xc3}, {"ANDA",7,0X84},{"ANDB",7,0xc4},{"ANDCC",2,0x1c}, {"ASL",10,0x08},{"ASLA",0,0x48},{"ASLB",0,0x58}, {"ASR",10,0x07},{"ASRA",0,0x47},{"ASRB",0,0x57}, {"BCC",4,0x24},{"BCS",4,0x25},{"BEQ",4,0x27}, {"BGE",4,0x2c},{"BGT",4,0x2e},{"BHI",4,0x22}, {"BHS",4,0x24},{"BITA",7,0x85},{"BITB",7,0xc5}, {"BLE",4,0x2f},{"BLO",4,0x25},{"BLS",4,0x23}, {"BLT",4,0x2d},{"BMI",4,0x2b},{"BNE",4,0x26}, {"BPL",4,0x2a},{"BRA",4,0x20},{"BRN",4,0x21}, {"BSR",4,0x8d}, {"BVC",4,0x28},{"BVS",4,0x29}, {"CLC",1,0x1cfe},{"CLF",1,0x1cbf},{"CLI",1,0x1cef}, {"CLIF",1,0x1caf}, {"CLR",10,0x0f},{"CLRA",0,0x4f},{"CLRB",0,0x5f}, {"CLV",1,0x1cfd}, {"CMPA",7,0x81},{"CMPB",7,0xc1},{"CMPD",9,0x1083}, {"CMPS",9,0x118c},{"CMPU",9,0x1183},{"CMPX",8,0x8c}, {"CMPY",9,0x108c}, {"COM",10,0x03},{"COMA",0,0x43},{"COMB",0,0x53}, {"CWAI",2,0x3c},{"DAA",0,0x19}, {"DEC",10,0x0a},{"DECA",0,0x4a},{"DECB",0,0x5a}, {"DES",1,0x327f},{"DEU",1,0x335f},{"DEX",1,0x301f}, {"DEY",1,0x313f}, {"ELSE",13,1}, {"EMOD",13,25}, {"END",13,2}, {"ENDC",13,3}, {"ENDIF",13,3}, {"ENDM",13,4}, {"EORA",7,0x88},{"EORB",7,0xc8}, {"EQU",13,5},{"EXG",11,0x1e},{"EXTERN",13,6}, {"FCB",13,7},{"FCC",13,8}, {"FCS",13,23}, {"FCW",13,9}, {"FDB",13,9}, {"IF",13,10}, {"IFEQ",13,29}, {"IFGT",13,30}, {"IFNE",13,28}, {"IFP1",13,21}, {"INC",10,0x0c},{"INCA",0,0x4c},{"INCB",0,0x5c}, {"INCLUDE",13,16}, {"INS",1,0x3261},{"INU",1,0x3341},{"INX",1,0x3001}, {"INY",1,0x3121},{"JMP",10,0x0e},{"JSR",8,0x8d}, {"LBCC",5,0x1024},{"LBCS",5,0x1025},{"LBEQ",5,0x1027}, {"LBGE",5,0x102c},{"LBGT",5,0x102e},{"LBHI",5,0x1022}, {"LBHS",5,0x1024}, {"LBLE",5,0x102f},{"LBLO",5,0x1025},{"LBLS",5,0x1023}, {"LBLT",5,0x102d},{"LBMI",5,0x102b},{"LBNE",5,0x1026}, {"LBPL",5,0x102a},{"LBRA",6,0x16},{"LBRN",5,0x1021}, {"LBSR",6,0x17}, {"LBVC",5,0x1028},{"LBVS",5,0x1029}, {"LDA",7,0x86},{"LDB",7,0xc6},{"LDD",8,0xcc}, {"LDS",9,0x10ce},{"LDU",8,0xce},{"LDX",8,0x8e}, {"LDY",9,0x108e},{"LEAS",3,0x32}, {"LEAU",3,0x33},{"LEAX",3,0x30},{"LEAY",3,0x31}, {"LSL",10,0x08},{"LSLA",0,0x48},{"LSLB",0,0x58}, {"LSR",10,0x04},{"LSRA",0,0x44},{"LSRB",0,0x54}, {"MACRO",13,11}, {"MOD",13,24}, {"MUL",0,0x3d}, {"NAM",13,26}, {"NEG",10,0x00},{"NEGA",0,0x40},{"NEGB",0,0x50}, {"NOP",0,0x12}, {"OPT",13,19}, {"ORA",7,0x8a},{"ORB",7,0xca},{"ORCC",2,0x1a}, {"ORG",13,12}, {"OS9",13,32}, {"PAG",13,20}, {"PAGE",13,20}, {"PSHS",12,0x34},{"PSHU",12,0x36},{"PUBLIC",13,13}, {"PULS",12,0x35},{"PULU",12,0x37},{"RMB",13,0}, {"ROL",10,0x09},{"ROLA",0,0x49},{"ROLB",0,0x59}, {"ROR",10,0x06},{"RORA",0,0x46},{"RORB",0,0x56}, {"RTI",0,0x3b},{"RTS",0,0x39}, {"SBCA",7,0x82},{"SBCB",7,0xc2}, {"SEC",1,0x1a01},{"SEF",1,0x1a40},{"SEI",1,0x1a10}, {"SEIF",1,0x1a50},{"SET",13,15}, {"SETDP",13,14},{"SEV",1,0x1a02},{"SEX",0,0x1d}, {"STA",7,0x87},{"STB",7,0xc7},{"STD",8,0xcd}, {"STS",9,0x10cf},{"STU",8,0xcf},{"STX",8,0x8f}, {"STY",9,0x108f}, {"SUBA",7,0x80},{"SUBB",7,0xc0},{"SUBD",8,0x83}, {"SWI",0,0x3f},{"SWI2",1,0x103f},{"SWI3",1,0x113f}, {"SYNC",0,0x13},{"TFR",11,0x1f}, {"TITLE",13,18}, {"TST",10,0x0d},{"TSTA",0,0x4d},{"TSTB",0,0x5d}, {"TTL",13,18}, {"USE",13,27}, }; struct symrecord{char name[MAXIDLEN+1]; char cat; unsigned short value; }; int symcounter=0; /* Symbol categories. 0 Constant value (from equ). 1 Variable value (from set) 2 Address within program module (label). 3 Variable containing address. 4 Adress in other program module (extern) 5 Variable containing external address. 6 Unresolved address. 7 Variable containing unresolved address. 8 Public label. 9 Macro definition. 10 Public label (yet undefined). 11 parameter name. 12 local label. 13 empty. */ struct symrecord symtable[NLABELS]; void processfile(char *name); struct oprecord * findop(char * nm) /* Find operation (mnemonic) in table using binary search */ { int lo,hi,i,s; lo=0;hi=sizeof(optable)/sizeof(optable[0])-1; do { i=(lo+hi)/2; s=strcmp(optable[i].name,nm); if(s<0) lo=i+1; else if(s>0) hi=i-1; else break; } while(hi>=lo); if (s) return NULL; return optable+i; } struct symrecord * findsym(char * nm) /* finds symbol table record; inserts if not found uses binary search, maintains sorted table */ { int lo,hi,i,j,s; lo=0;hi=symcounter-1; s=1;i=0; while (hi>=lo) { i=(lo+hi)/2; s=strcmp(symtable[i].name,nm); if(s<0) lo=i+1; else if(s>0) hi=i-1; else break; } if(s) { i=(s<0?i+1:i); if(symcounter==NLABELS) { fprintf(stderr,"Sorry, no storage for symbols!!!"); exit(4); } for(j=symcounter;j>i;j--) symtable[j]=symtable[j-1]; symcounter++; strcpy(symtable[i].name,nm); symtable[i].cat=13; } return symtable+i; } FILE *listfile,*objfile; char *listname,*objname,*srcname,*curname; int lineno; void outsymtable() { int i,j=0; fprintf(listfile,"\nSYMBOL TABLE"); for(i=0;i<symcounter;i++) if(symtable[i].cat!=13) { if(j%4==0)fprintf(listfile,"\n"); fprintf(listfile,"%10s %02d %04x",symtable[i].name,symtable[i].cat, symtable[i].value); j++; } fprintf(listfile,"\n"); } struct regrecord{char *name;unsigned char tfr,psh;}; struct regrecord regtable[]= {{"D",0x00,0x06},{"X",0x01,0x10},{"Y",0x02,0x20}, {"U",0x03,0x40},{"S",0x04,0x40},{"PC",0x05,0x80}, {"A",0x08,0x02},{"B",0x09,0x04},{"CC",0x0a,0x01}, {"CCR",0x0a,0x01},{"DP",0x0b,0x08},{"DPR",0x0b,0x08}}; struct regrecord * findreg(char *nm) { int i; for(i=0;i<12;i++) { if(strcmp(regtable[i].name,nm)==0) return regtable+i; } return 0; } char pass; /* Assembler pass=1 or 2 */ char listing; /* flag to indicate listing */ char relocatable; /* flag to indicate relocatable object. */ char terminate; /* flag to indicate termination. */ char generating; /* flag to indicate that we generate code */ unsigned short loccounter,oldlc; /* Location counter */ char inpline[128]; /* Current input line (not expanded)*/ char srcline[128]; /* Current source line */ char * srcptr; /* Pointer to line being parsed */ char unknown; /* flag to indicate value unknown */ char certain; /* flag to indicate value is certain at pass 1*/ int error; /* flags indicating errors in current line. */ int errors; /* number of errors */ char exprcat; /* category of expression being parsed, eg. label or constant, this is important when generating relocatable object code. */ char namebuf[MAXIDLEN+1]; void err(int er) { error |= er ; } void scanname() { int i=0; char c; while(1) { c=*srcptr++; if(c>='a'&&c<='z')c-=32; if(c!='.'&&c!='$'&&(c<'0'||c>'9')&&(c<'A'||c>'Z'))break; if(i<MAXIDLEN)namebuf[i++]=c; } namebuf[i]=0; srcptr--; } void skipspace() { char c; do { c=*srcptr++; } while(c==' '||c=='\t'); srcptr--; } short scanexpr(int); short scandecimal() { char c; short t=0; c=*srcptr++; while(isdigit(c)) { t=t*10+c-'0'; c=*srcptr++; } srcptr--; return t; } short scanhex() { short t=0,i=0; srcptr++; scanname(); while(namebuf[i]>='0'&&namebuf[i]<='F') { t=t*16+namebuf[i]-'0'; if(namebuf[i]>'9')t-=7; i++; } if(i==0)error|=1; return t; } short scanchar() { short t; srcptr++; t=*srcptr; if(t)srcptr++; if (*srcptr=='\'')srcptr++; return t; } short scanbin() { char c; short t=0; srcptr++; c=*srcptr++; while(c=='0'||c=='1') { t=t*2+c-'0'; c=*srcptr++; } srcptr--; return t; } short scanoct() { char c; short t=0; srcptr++; c=*srcptr++; while(c>='0'&&c<='7') { t=t*8+c-'0'; c=*srcptr++; } srcptr--; return t; } short scanlabel() { struct symrecord * p; scanname(); p=findsym(namebuf); if(p->cat==13) { p->cat=6; p->value=0; } if(p->cat==9||p->cat==11)error|=1; exprcat=p->cat&14; if(exprcat==6||exprcat==10)unknown=1; if(((exprcat==2||exprcat==8) && (unsigned short)(p->value)>(unsigned short)loccounter)|| exprcat==4) certain=0; if(exprcat==8||exprcat==6||exprcat==10)exprcat=2; return p->value; } /* expression categories... all zeros is ordinary constant. bit 1 indicates address within module. bit 2 indicates external address. bit 4 indicates this can't be relocated if it's an address. bit 5 indicates address (if any) is negative. */ short scanfactor() { char c; short t; skipspace(); c=*srcptr; if(isalpha(c))return scanlabel(); else if(isdigit(c))return scandecimal(); else switch(c) { case '.' : case '*' : srcptr++;exprcat|=2;return loccounter; case '$' : return scanhex(); case '%' : return scanbin(); case '&' : /* compatibility */ case '@' : return scanoct(); case '\'' : return scanchar(); case '(' : srcptr++;t=scanexpr(0);skipspace(); if(*srcptr==')')srcptr++;else error|=1; return t; case '-' : srcptr++;exprcat^=32;return -scanfactor(); case '+' : srcptr++;return scanfactor(); case '!' : srcptr++;exprcat|=16;return !scanfactor(); case '^' : case '~' : srcptr++;exprcat|=16;return ~scanfactor(); } error|=1; return 0; } #define EXITEVAL {srcptr--;return t;} #define RESOLVECAT if((oldcat&15)==0)oldcat=0;\ if((exprcat&15)==0)exprcat=0;\ if((exprcat==2&&oldcat==34)||(exprcat==34&&oldcat==2)) {\ exprcat=0;\ oldcat=0;}\ exprcat|=oldcat;\ /* resolve such cases as constant added to address or difference between two addresses in same module */ short scanexpr(int level) /* This is what you call _recursive_ descent!!!*/ { short t,u; char oldcat,c; exprcat=0; if(level==10)return scanfactor(); t=scanexpr(level+1); while(1) { skipspace(); c=*srcptr++; switch(c) { case '*':oldcat=exprcat; t*=scanexpr(10); exprcat|=oldcat|16; break; case '/':oldcat=exprcat; u=scanexpr(10); if(u)t/=u;else error|=1; exprcat|=oldcat|16; break; case '%':oldcat=exprcat; u=scanexpr(10); if(u)t%=u;else error|=1; exprcat|=oldcat|16; break; case '+':if(level==9)EXITEVAL oldcat=exprcat; t+=scanexpr(9); RESOLVECAT break; case '-':if(level==9)EXITEVAL oldcat=exprcat; t-=scanexpr(9); exprcat^=32; RESOLVECAT break; case '<':if(*(srcptr)=='<') { if(level>=8)EXITEVAL srcptr++; oldcat=exprcat; t<<=scanexpr(8); exprcat|=oldcat|16; break; } else if(*(srcptr)=='=') { if(level>=7)EXITEVAL srcptr++; oldcat=exprcat; t=t<=scanexpr(7); exprcat|=oldcat|16; break; } else { if(level>=7)EXITEVAL oldcat=exprcat; t=t<scanexpr(7); exprcat|=oldcat|16; break; } case '>':if(*(srcptr)=='>') { if(level>=8)EXITEVAL srcptr++; oldcat=exprcat; t>>=scanexpr(8); exprcat|=oldcat|16; break; } else if(*(srcptr)=='=') { if(level>=7)EXITEVAL srcptr++; oldcat=exprcat; t=t>=scanexpr(7); exprcat|=oldcat|16; break; } else { if(level>=7)EXITEVAL oldcat=exprcat; t=t>scanexpr(7); exprcat|=oldcat|16; break; } case '!':if(level>=6||*srcptr!='=')EXITEVAL srcptr++; oldcat=exprcat; t=t!=scanexpr(6); exprcat|=oldcat|16; break; case '=':if(level>=6)EXITEVAL if(*srcptr=='=')srcptr++; oldcat=exprcat; t=t==scanexpr(6); exprcat|=oldcat|16; break; case '&':if(level>=5)EXITEVAL oldcat=exprcat; t&=scanexpr(5); exprcat|=oldcat|16; break; case '^':if(level>=4)EXITEVAL oldcat=exprcat; t^=scanexpr(4); exprcat|=oldcat|16; break; case '|':if(level>=3)EXITEVAL oldcat=exprcat; t|=scanexpr(3); exprcat|=oldcat|16; default: EXITEVAL } } } char mode; /* addressing mode 0=immediate,1=direct,2=extended,3=postbyte 4=pcrelative(with postbyte) 5=indirect 6=pcrel&indirect*/ char opsize; /*desired operand size 0=dunno,1=5,2=8,3=16*/ short operand; unsigned char postbyte; int dpsetting; int scanindexreg() { char c; c=*srcptr; if(islower(c))c-=32; if (debug) fprintf(stderr,"DEBUG: scanindexreg: indexreg=%d, mode=%d, opsize=%d, error=%d, postbyte=%02X\n",c,mode,opsize,error,postbyte); switch(c) { case 'X':return 1; case 'Y':postbyte|=0x20;return 1; case 'U':postbyte|=0x40;return 1; case 'S':postbyte|=0x60;return 1; default: return 0; } } void set3() { if(mode<3)mode=3; } void scanspecial() { set3(); skipspace(); if(*srcptr=='-') { srcptr++; if(*srcptr=='-') { srcptr++; postbyte=0x83; } else postbyte=0x82; if(!scanindexreg())error|=2;else srcptr++; } else { postbyte=0x80; if(!scanindexreg())error|=2;else srcptr++; if(*srcptr=='+') { srcptr++; if(*srcptr=='+') { srcptr++; postbyte+=1; } } else postbyte+=4; } } void scanindexed() { set3(); postbyte=0; if(scanindexreg()) { srcptr++; if(opsize==0) { if(unknown||!certain)opsize=3; else if(operand>=-16&&operand<16&&mode==3)opsize=1; else if(operand>=-128&&operand<128)opsize=2; else opsize=3; } switch(opsize) { case 1:postbyte+=(operand&31);opsize=0;break; case 2:postbyte+=0x88;break; case 3:postbyte+=0x89;break; } } else { /*pc relative*/ if(toupper(*srcptr)!='P')error|=2; else { srcptr++; if(toupper(*srcptr)!='C')error|=2; else { srcptr++; if(toupper(*srcptr)=='R')srcptr++; } } mode++;postbyte+=0x8c; if(opsize==1)opsize=2; } } #define RESTORE {srcptr=oldsrcptr;c=*srcptr;goto dodefault;} void scanoperands() { char c,d,*oldsrcptr; unknown=0; opsize=0; certain=1; skipspace(); c=*srcptr; mode=0; if(c=='[') { srcptr++; c=*srcptr; mode=5; } if (debug) fprintf(stderr,"DEBUG: scanoperands: c=%c (%02X)\n",c,c); switch(c) { case 'D': case 'd': oldsrcptr=srcptr; srcptr++; skipspace(); if(*srcptr!=',')RESTORE else { postbyte=0x8b; srcptr++; if(!scanindexreg())RESTORE else {srcptr++;set3();} } break; case 'A': case 'a': oldsrcptr=srcptr; srcptr++; skipspace(); if(*srcptr!=',')RESTORE else { postbyte=0x86; srcptr++; if(!scanindexreg())RESTORE else {srcptr++;set3();} } break; case 'B': case 'b': oldsrcptr=srcptr; srcptr++; skipspace(); if(*srcptr!=',')RESTORE else { postbyte=0x85; srcptr++; if (debug) fprintf(stderr,"DEBUG: scanoperands: breg preindex: c=%c (%02X)\n",*srcptr,*srcptr); if(!scanindexreg())RESTORE else {srcptr++;set3();} if (debug) fprintf(stderr,"DEBUG: scanoperands: breg: postindex c=%c (%02X)\n",*srcptr,*srcptr); } break; case ',': srcptr++; scanspecial(); break; case '#': if(mode==5)error|=2;else mode=0; srcptr++; operand=scanexpr(0); break; case '<': srcptr++; if(*srcptr=='<') { srcptr++; opsize=1; } else opsize=2; goto dodefault; case '>': srcptr++; opsize=3; default: dodefault: operand=scanexpr(0); skipspace(); if(*srcptr==',') { srcptr++; scanindexed(); } else { if(opsize==0) { if(unknown||!certain||dpsetting==-1|| (unsigned short)(operand-dpsetting*256)>=256) opsize=3; else opsize=2; } if(opsize==1)opsize=2; if(mode==5){ postbyte=0x8f; opsize=3; } else mode=opsize-1; } } if (debug) fprintf(stderr,"DEBUG: scanoperands: mode=%d, error=%d, postbyte=%02X\n",mode,error,postbyte); if(mode>=5) { skipspace(); postbyte|=0x10; if(*srcptr!=']')error|=2;else srcptr++; } if(pass==2&&unknown)error|=4; } unsigned char codebuf[128]; int codeptr; /* byte offset within instruction */ int suppress; /* 0=no suppress 1=until ENDIF 2=until ELSE 3=until ENDM */ int ifcount; /* count of nested IFs within suppressed text */ unsigned char outmode; /* 0 is binary, 1 is s-records */ unsigned short hexaddr; int hexcount; unsigned char hexbuffer[16]; unsigned int chksum; extern int os9crc(unsigned char c, int crcp); int crc; void reset_crc() { crc = -1; } void flushhex() { int i; if(hexcount){ fprintf(objfile,"S1%02X%04X",(hexcount+3)&0xff,hexaddr&0xffff); for(i=0;i<hexcount;i++)fprintf(objfile,"%02X",hexbuffer[i]); chksum+=(hexaddr&0xff)+((hexaddr>>8)&0xff)+hexcount+3; fprintf(objfile,"%02X\n",0xff-(chksum&0xff)); hexaddr+=hexcount; hexcount=0; chksum=0; } } void outhex(unsigned char x) { if(hexcount==16)flushhex(); hexbuffer[hexcount++]=x; chksum+=x; } void outbuffer() { int i; for(i=0;i<codeptr;i++) { crc = os9crc(codebuf[i],crc); if(!outmode)fputc(codebuf[i],objfile);else outhex(codebuf[i]); } } char *errormsg[]={"Error in expression", "Illegal addressing mode", "Undefined label", "Multiple definitions of label", "Relative branch out of range", "Missing label", "","","","","","","","","", "Illegal mnemonic" }; void report() { int i; fprintf(stderr,"File %s, line %d:%s\n",curname,lineno,srcline); for(i=0;i<16;i++) { if(error&1) { fprintf(stderr,"%s\n",errormsg[i]); if(pass==2&&listing)fprintf(listfile,"**** %s\n",errormsg[i]); } error>>=1; } errors++; } void outlist() { int i; fprintf(listfile,"%04X: ",oldlc); for(i=0;i<codeptr&&i<MAXLISTBYTES;i++) fprintf(listfile,"%02X",codebuf[i]); for(;i<=MAXLISTBYTES;i++) fprintf(listfile," "); fprintf(listfile,"%s\n",srcline); while(i<codeptr) { fprintf(listfile,"%04X: ",oldlc + i); for(int j=0;i<codeptr&&j<MAXLISTBYTES;j++) { fprintf(listfile,"%02X",codebuf[i]); i++; } fprintf(listfile,"\n"); } } void setlabel(struct symrecord * lp) { if(lp) { if(lp->cat!=13&&lp->cat!=6) { if(lp->cat!=2||lp->value!=loccounter) error|=8; } else { lp->cat=2; lp->value=loccounter; } } } void putbyte(unsigned char b) { codebuf[codeptr++]=b; } void putword(unsigned short w) { codebuf[codeptr++]=w>>8; codebuf[codeptr++]=w&0x0ff; } void doaddress() /* assemble the right addressing bytes for an instruction */ { int offs; switch(mode) { case 0: if(opsize==2)putbyte(operand);else putword(operand);break; case 1: putbyte(operand);break; case 2: putword(operand);break; case 3: case 5: putbyte(postbyte); switch(opsize) { case 2: putbyte(operand);break; case 3: putword(operand); } break; case 4: case 6: offs=(unsigned short)operand-loccounter-codeptr-2; if(offs<-128||offs>=128||opsize==3||unknown||!certain) { if((!unknown)&&opsize==2&&(offs<-128||offs>=128) ) error|=16; offs--; opsize=3; postbyte++; } putbyte(postbyte); if (debug) fprintf(stderr,"DEBUG: doaddress: mode=%d, opsize=%d, error=%d, postbyte=%02X, operand=%04X offs=%d\n",mode,opsize,error,postbyte,operand,offs); if(opsize==3)putword(offs); else putbyte(offs); } } void onebyte(int co) { putbyte(co); } void twobyte(int co) { putword(co); } void oneimm(int co) { scanoperands(); if(mode>=3)error|=2; putbyte(co); putbyte(operand); } void lea(int co) { putbyte(co); scanoperands(); if(mode==0) error|=2; if(mode<3) { opsize=3; postbyte=0x8f; mode=3; } if (debug) fprintf(stderr,"DEBUG: lea: mode=%d, opsize=%d, error=%d, postbyte=%02X, *src=%c\n",mode,opsize,error,postbyte,*srcptr); doaddress(); } void sbranch(int co) { int offs; scanoperands(); if(mode!=1&&mode!=2)error|=2; offs=(unsigned short)operand-loccounter-2; if(!unknown&&(offs<-128||offs>=128))error|=16; if(pass==2&&unknown)error|=4; putbyte(co); putbyte(offs); } void lbra(int co) { scanoperands(); if(mode!=1&&mode!=2)error|=2; putbyte(co); putword(operand-loccounter-3); } void lbranch(int co) { scanoperands(); if(mode!=1&&mode!=2)error|=2; putword(co); putword(operand-loccounter-4); } void arith(int co) { scanoperands(); switch(mode) { case 0:opsize=2;putbyte(co);break; case 1:putbyte(co+0x010);break; case 2:putbyte(co+0x030);break; default:putbyte(co+0x020); } doaddress(); } void darith(int co) { scanoperands(); switch(mode) { case 0:opsize=3;putbyte(co);break; case 1:putbyte(co+0x010);break; case 2:putbyte(co+0x030);break; default:putbyte(co+0x020); } doaddress(); } void d2arith(int co) { scanoperands(); switch(mode) { case 0:opsize=3;putword(co);break; case 1:putword(co+0x010);break; case 2:putword(co+0x030);break; default:putword(co+0x020); } doaddress(); } void oneaddr(int co) { scanoperands(); switch(mode) { case 0: error|=2;break; case 1: putbyte(co);break; case 2: putbyte(co+0x70);break; default: putbyte(co+0x60);break; } doaddress(); } void tfrexg(int co) { struct regrecord * p; putbyte(co); skipspace(); scanname(); if((p=findreg(namebuf))==0)error|=2; else postbyte=(p->tfr)<<4; skipspace(); if(*srcptr==',')srcptr++;else error|=2; skipspace(); scanname(); if((p=findreg(namebuf))==0)error|=2; else postbyte|=p->tfr; putbyte(postbyte); } void pshpul(int co) { struct regrecord *p; putbyte(co); postbyte=0; do { if(*srcptr==',')srcptr++; skipspace(); scanname(); if((p=findreg(namebuf))==0)error|=2; else postbyte|=p->psh; skipspace(); }while (*srcptr==','); putbyte(postbyte); } void skipComma() { while(*srcptr && *srcptr!='\n' && *srcptr!=',')srcptr++; if (*srcptr==',') { srcptr++; } else { error|=1; } } int modStart; void os9begin() { generating=1; modStart = loccounter; reset_crc(); putword(0x87cd); putword(scanexpr(0)-loccounter); // module size skipComma(); putword(scanexpr(0)-loccounter); // offset to module name skipComma(); putbyte(scanexpr(0)); // type / language skipComma(); putbyte(scanexpr(0)); // attribute int parity=0; for(int i=0; i< 8; i++) parity^=codebuf[i]; putbyte(parity^0xff); // header parity skipspace(); while (*srcptr==',') { // there are some more srcptr++; putword(scanexpr(0)); skipspace(); } } void os9end() { crc = crc ^ 0xffffff; putbyte((crc>>16)&0xff); putbyte((crc>>8)&0xff); putbyte(crc&0xff); } void pseudoop(int co,struct symrecord * lp) { int i; char c; char *fname; int locsave; switch(co) { case 0:/* RMB */ setlabel(lp); operand=scanexpr(0); if(unknown)error|=4; loccounter+=operand; if(generating&&pass==2) { if(!outmode)for(i=0;i<operand;i++)fputc(0,objfile); else flushhex(); } hexaddr=loccounter; break; case 5:/* EQU */ operand=scanexpr(0); if(!lp)error|=32; else { if(lp->cat==13||lp->cat==6|| (lp->value==(unsigned short)operand&&pass==2)) { if(exprcat==2)lp->cat=2; else lp->cat=0; lp->value=operand; } else error|=8; } break; case 7:/* FCB */ setlabel(lp); generating=1; do { if(*srcptr==',')srcptr++; skipspace(); if(*srcptr=='\"') { srcptr++; while(*srcptr!='\"'&&*srcptr) putbyte(*srcptr++); if(*srcptr=='\"')srcptr++; } else { putbyte(scanexpr(0)); if(unknown&&pass==2)error|=4; } skipspace(); } while(*srcptr==','); break; case 8:/* FCC */ setlabel(lp); skipspace(); c=*srcptr++; while(*srcptr!=c&&*srcptr) putbyte(*srcptr++); if(*srcptr==c)srcptr++; break; case 9:/* FDB */ setlabel(lp); generating=1; do { if(*srcptr==',')srcptr++; skipspace(); putword(scanexpr(0)); if(unknown&&pass==2)error|=4; skipspace(); } while(*srcptr==','); break; case 23 :/* FCS */ setlabel(lp); generating=1; skipspace(); int sep = *srcptr; if(sep=='\"' || sep=='/') { srcptr++; while(*srcptr!=sep&&*srcptr) putbyte(*srcptr++); if(*srcptr==sep)srcptr++; codebuf[codeptr-1] |= 0x80; // os9 string termination } break; case 1: /* ELSE */ suppress=1; break; case 21: /* IFP1 */ if(pass==2)suppress=2; break; case 29: /* IFGT */ operand=scanexpr(0); if(unknown)error|=4; if(operand>0)suppress=2; break; case 31: /* IFLT */ operand=scanexpr(0); if(unknown)error|=4; if(operand<0)suppress=2; break; case 28: /* IFNE */ operand=scanexpr(0); if(unknown)error|=4; if(operand==0)suppress=2; break; case 30: /* IFEQ */ case 10: /* IF */ operand=scanexpr(0); if(unknown)error|=4; if(!operand)suppress=2; break; case 12: /* ORG */ operand=scanexpr(0); if(unknown)error|=4; if(generating&&pass==2) { for(i=0;i<(unsigned short)operand-loccounter;i++) if(!outmode)fputc(0,objfile);else flushhex(); } loccounter=operand; hexaddr=loccounter; break; case 14: /* SETDP */ operand=scanexpr(0); if(unknown)error|=4; if(!(operand&255))operand=(unsigned short)operand>>8; if((unsigned)operand>255)operand=-1; dpsetting=operand; break; case 15: /* SET */ operand=scanexpr(0); if(!lp)error|=32; else { if(lp->cat&1||lp->cat==6) { if(exprcat==2)lp->cat=3; else lp->cat=1; lp->value=operand; } else error|=8; } break; case 2: /* END */ terminate=1; break; case 27: /* USE */ locsave = loccounter ; case 16: /* INCLUDE */ skipspace(); if(*srcptr=='"')srcptr++; i = 0; for(i=0; !(srcptr[i]==0||srcptr[i]=='"'); i++); int len = i; fname = calloc(1,len); for(i=0;i<len;i++) { if(*srcptr==0||*srcptr=='"')break; fname[i]=*srcptr++; } fname[i]=0; processfile(fname); codeptr=0; srcline[0]=0; if (co==27) loccounter = locsave; break; case 24: /* MOD */ loccounter = 0; setlabel(lp); os9begin(); break; case 25: /* EMOD */ os9end(); break; case 32: /* OS9 */ setlabel(lp); putword(0x103f); // SWI2 putbyte(scanexpr(0)); break; case 18: /* TTL */ break; case 19: /* OPT */ case 26: /* NAM */ case 20: /* PAG */ case 3: /* ENDIF/ENDC */ break; } } void processline() { struct symrecord * lp; struct oprecord * op; int co; char c; srcptr=srcline; oldlc=loccounter; error=0; unknown=0;certain=1; lp=0; codeptr=0; if(isalnum(*srcptr)) { scanname();lp=findsym(namebuf); if(*srcptr==':') srcptr++; } skipspace(); if(isalnum(*srcptr)) { scanname(); op=findop(namebuf); if(op) { if(op->cat!=13){ setlabel(lp); generating=1; } co=op->code; switch(op->cat) { case 0:onebyte(co);break; case 1:twobyte(co);break; case 2:oneimm(co);break; case 3:lea(co);break; case 4:sbranch(co);break; case 5:lbranch(co);break; case 6:lbra(co);break; case 7:arith(co);break; case 8:darith(co);break; case 9:d2arith(co);break; case 10:oneaddr(co);break; case 11:tfrexg(co);break; case 12:pshpul(co);break; case 13:pseudoop(co,lp); } c=*srcptr; if (debug) fprintf(stderr,"DEBUG: processline: mode=%d, opsize=%d, error=%d, postbyte=%02X c=%c\n",mode,opsize,error,postbyte,c); if(c!=' '&&*(srcptr-1)!=' '&&c!=0&&c!=';')error|=2; } else error|=0x8000; }else setlabel(lp); if(pass==2) { outbuffer(); if(listing)outlist(); } if(error)report(); loccounter+=codeptr; } void suppressline() { struct oprecord * op; srcptr=srcline; oldlc=loccounter; codeptr=0; if(isalnum(*srcptr)) { scanname(); if(*srcptr==':')srcptr++; } skipspace(); scanname();op=findop(namebuf); if(op && op->cat==13) { if(op->code==10||op->code==13||op->code==29||op->code==28||op->code==21||op->code==30) ifcount++; else if(op->code==3) { if(ifcount>0)ifcount--;else if(suppress==1|suppress==2)suppress=0; } else if(op->code==1) { if(ifcount==0 && suppress==2)suppress=0; } } if(pass==2&&listing)outlist(); } void usage(char*nm) { fprintf(stderr,"Usage: %s [-o objname] [-l listname] [-s srecord-file] srcname\n",nm); exit(2); } char * strconcat(char *s,int spos,char *d) { int slen = strlen(s); int dlen = strlen(d); if ( spos == 0) spos = slen; char *out = calloc(1,spos+dlen+1); int i = 0; for(; i< spos; i++ ) out[i] = s[i]; for(; i< spos+dlen+1; i++ ) out[i] = *d++; return out; } void getoptions(int c,char*v[]) { int i=0; if(c==1)usage(v[0]); if(strcmp(v[1],"-d")==0) { debug=1; i++; } if(strcmp(v[1],"-o")==0) { if(c<4)usage(v[0]); objname = v[2]; i+=2; } if(strcmp(v[i+1],"-s")==0) { if(c<4+i)usage(v[0]); objname=v[i+2]; outmode=1; i+=2; } if(strcmp(v[i+1],"-l")==0) { if(c<4+i)usage(v[0]); listname=v[2+i]; i+=2; } srcname=v[1+i]; if(objname==0) { for(i=0;srcname[i]!='.' && srcname[i]!=0 ;i++) ; objname = strconcat(srcname,i,".b"); } listing=(listname!=0); } void expandline() { int i=0,j=0,k,j1; for(i=0;i<128&&j<128;i++) { if(inpline[i]=='\n') { srcline[j]=0;break; } if(inpline[i]=='\t') { j1=j; for(k=0;k<8-j1%8 && j<128;k++)srcline[j++]=' '; }else srcline[j++]=inpline[i]; } srcline[127]=0; } void processfile(char *name) { char *oldname; int oldno; FILE *srcfile; oldname=curname; curname=name; oldno=lineno; lineno=0; if((srcfile=fopen(name,"r"))==0) { int i = strlen(oldname); while(i>0 && oldname[i]!='/') i--; if (i>0) { char *next = strconcat(oldname,i+1,name); if((srcfile=fopen(next,"r"))==0) { fprintf(stderr,"Cannot open source file %s\n",next); exit(4); } curname = next; } else { fprintf(stderr,"Cannot open source file %s\n",name); exit(4); } } while(!terminate&&fgets(inpline,128,srcfile)) { expandline(); lineno++; srcptr=srcline; if(suppress)suppressline(); else processline(); } fclose(srcfile); if(suppress) { fprintf(stderr,"improperly nested IF statements in %s",curname); errors++; suppress=0; } lineno=oldno; curname=oldname; } int main(int argc,char *argv[]) { char c; getoptions(argc,argv); pass=1; errors=0; generating=0; terminate=0; processfile(srcname); if(errors) { fprintf(stderr,"%d Pass 1 Errors, Continue?",errors); c=getchar(); if(c=='n'||c=='N') exit(3); } pass=2; loccounter=0; errors=0; generating=0; terminate=0; if(listing&&((listfile=fopen(listname,"w"))==0)) { fprintf(stderr,"Cannot open list file"); exit(4); } if((objfile=fopen(objname,outmode?"w":"wb"))==0) { fprintf(stderr,"Cannot write object file\n"); exit(4); } processfile(srcname); fprintf(stderr,"%d Pass 2 errors.\n",errors); if(listing) { fprintf(listfile,"%d Pass 2 errors.\n",errors); outsymtable(); fclose(listfile); } if(outmode){ flushhex(); fprintf(objfile,"S9030000FC\n"); } fclose(objfile); return 0; }