Mercurial > hg > Members > kono > os9 > sbc09
diff 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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/a09.c Mon Jul 02 02:12:31 2018 +0900 @@ -0,0 +1,1544 @@ +/* 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; +} +