/src/asm8080.pas
https://github.com/fitzer8/Z80Asm · Pascal · 1283 lines · 1007 code · 268 blank · 8 comment · 171 complexity · 8fec3d8b3935361b2002758cfd5a618f MD5 · raw file
- PROGRAM Asm8080;
-
- {R-}
- {$M 16384,0,655360}
-
- CONST
- maxSymLen = 16;
- maxOpcdLen = 4;
-
- alphaNumeric = '1234567890$ABCDEFGHIJKLMNOPQRSTUVWXYZ_';
- numeric = '1234567890';
- hex = '0123456789ABCDEF';
- white = #9' '; { A tab plus a space }
-
- o_Illegal = 0; { Opcode not found in FindOpcode }
- o_None = 1; { No operands }
- o_One = 2; { One byte immediate operand }
- o_Two = 3; { Two byte immediate operand }
- o_InrDcr = 4; { INR or DCR instruction }
- o_Arith = 5; { Register to accumulator arithmetic }
- o_MOV = 6; { MOV instruction }
- o_MVI = 7; { MVI instruction }
- o_LXI = 8; { LXI instruction }
- o_InxDcx = 9; { INX, DCX, and DAD instructions }
- o_PushPop = 10; { PUSH and POP instructions }
- o_StaxLdax = 11; { STAX and LDAX instructions }
- o_RST = 12; { RST instruction }
- o_DB = 13; { DB pseudo-op }
- o_DW = 14; { DW pseudo-op }
- o_DS = 15; { DS pseudo-op }
- o_EQU = -16; { EQU and SET pseudo-ops }
- o_ORG = -17; { ORG pseudo-op }
- o_END = 18; { END pseudo-op }
- o_LIST = -19; { LIST pseudo-op }
- o_OPT = -20; { OPT pseudo-op }
-
- regs = ' B C D E H L M A ';
- regVals = ' 0 1 2 3 4 5 6 7 ';
-
- regPairs = ' B D H SP BC DE HL ';
- regPairVals = ' 0 1 2 3 0 1 2 ';
-
- pushRegs = ' B D H PSW BC DE HL AF ';
- pushRegVals = ' 0 1 2 3 0 1 2 3 ';
-
- staxRegs = ' B D BC DE ';
- staxRegVals = ' 0 1 0 1 ';
-
- TYPE
- SymStr = String[maxSymLen];
-
- SymPtr = ^SymRec;
- SymRec = RECORD
- name: SymStr; { Symbol name }
- value: Integer; { Symbol value }
- next: SymPtr; { Pointer to next symtab entry }
- defined: Boolean; { TRUE if defined }
- multiDef: Boolean; { TRUE if multiply defined }
- isSet: Boolean; { TRUE if defined with SET pseudo }
- equ: Boolean; { TRUE if defined with EQU pseudo }
- END;
-
- OpcdStr = String[maxOpcdLen];
-
- OpcdPtr = ^OpcdRec;
- OpcdRec = RECORD
- name: OpcdStr; { Opcode name }
- typ: Integer; { Opcode type }
- parm: Integer; { Opcode parameter }
- next: OpcdPtr; { Pointer to next opcode entry }
- END;
-
- VAR
- symTab: SymPtr; { Pointer to first entry in symtab }
- opcdTab: OpcdPtr; { Opcode table }
-
- locPtr: Integer; { Current program address }
- pass: Integer; { Current assembler pass }
- errFlag: Boolean; { TRUE if error occurred this line }
- errCount: Integer; { Total number of errors }
-
- line: String; { Current line from input file }
- listLine: String; { Current listing line }
- listFlag: Boolean; { FALSE to suppress listing source }
- listThisLine: Boolean; { TRUE to force listing this line }
- sourceEnd: Boolean; { TRUE when END pseudo encountered }
-
- instr: ARRAY[1..3] OF Integer; { Current instruction word }
- instrLen: Integer; { Current instruction length }
-
- bytStr: String; { Buffer for long DB statements }
- showAddr: Boolean; { TRUE to show LocPtr on listing }
- xferAddr: Integer; { Transfer address from END pseudo }
- xferFound: Boolean; { TRUE if xfer addr defined w/ END }
-
- { Command line parameters }
- cl_SrcName: String; { Source file name }
- cl_ListName: String; { Listing file name }
- cl_ObjName: String; { Object file name }
- cl_Err: Boolean; { TRUE for errors to screen }
-
-
- source: Text;
- object: Text;
- listing: Text;
-
-
- FUNCTION Deblank(s: String): String;
- VAR
- i: Integer;
-
- BEGIN
- i := Length(s);
- WHILE (i>0) AND (s[i] IN [#9,' ']) DO
- Dec(i);
-
- s[0] := CHR(i);
-
- i := 1;
- WHILE (i<=Length(s)) AND (s[i] IN [#9,' ']) DO
- Inc(i);
- Delete(s,1,i-1);
-
- Deblank := s;
- END;
-
-
- FUNCTION UprCase(s: String): String;
- VAR
- i: Integer;
-
- BEGIN
- FOR i := 1 TO Length(s) DO
- IF s[i] IN ['a'..'z'] THEN
- s[i] := UpCase(s[i]);
-
- UprCase := s;
- END;
-
-
- FUNCTION Hex2(i: Integer): String;
- BEGIN
- i := i AND 255;
- Hex2 := Copy(hex,(i SHR 4)+1,1) + Copy(hex,(i AND 15)+1,1);
- END;
-
-
- FUNCTION Hex4(i: Integer): String;
- BEGIN
- Hex4 := Hex2(i SHR 8) + Hex2(i AND 255);
- END;
-
-
- PROCEDURE Error(message: String);
- BEGIN
- errFlag := TRUE;
- Inc(errCount);
-
- IF pass<>1 THEN BEGIN
- listThisLine := TRUE;
- WriteLn(listing,'*** Error: ',Message,' ***');
- IF cl_Err THEN WriteLn('*** Error: ',Message,' ***');
- END;
- END;
-
-
-
- PROCEDURE AddOpcode(name: OpcdStr; typ,parm: Integer);
- VAR
- p: OpcdPtr;
-
- BEGIN
- New(p);
-
- p^.name := name;
- p^.typ := typ;
- p^.parm := parm;
- p^.next := opcdTab;
-
- opcdTab := p;
- END;
-
-
- PROCEDURE FindOpcode(name: OpcdStr; VAR typ,parm: Integer);
- VAR
- p: OpcdPtr;
- found: Boolean;
-
- BEGIN
- found := FALSE;
- p := opcdTab;
-
- WHILE (p<>NIL) AND NOT found DO BEGIN
- found := (p^.name = name);
- IF NOT found THEN
- p := p^.next;
- END;
-
- IF NOT found THEN BEGIN
- typ := o_Illegal;
- parm := 0;
- END
- ELSE BEGIN
- typ := p^.typ;
- parm := p^.parm;
- END;
- END;
-
-
- PROCEDURE InitOpcodes;
- BEGIN
- opcdTab := NIL;
-
- AddOpcode('NOP' ,o_None,0);
- AddOpcode('RLC' ,o_None,7);
- AddOpcode('RRC' ,o_None,15);
- AddOpcode('RAL' ,o_None,23);
- AddOpcode('RAR' ,o_None,31);
- AddOpcode('DAA' ,o_None,39);
- AddOpcode('CMA' ,o_None,47);
- AddOpcode('RIM' ,o_None,48);
- AddOpcode('STC' ,o_None,55);
- AddOpcode('SIM' ,o_None,56);
- AddOpcode('CMC' ,o_None,63);
- AddOpcode('HLT' ,o_None,118);
- AddOpcode('RNZ' ,o_None,192);
- AddOpcode('RZ' ,o_None,200);
- AddOpcode('RET' ,o_None,201);
- AddOpcode('RNC' ,o_None,208);
- AddOpcode('RC' ,o_None,216);
- AddOpcode('RPO' ,o_None,224);
- AddOpcode('XTHL',o_None,227);
- AddOpcode('RPE' ,o_None,232);
- AddOpcode('PCHL',o_None,233);
- AddOpcode('XCHG',o_None,235);
- AddOpcode('RP' ,o_None,240);
- AddOpcode('DI' ,o_None,243);
- AddOpcode('RM' ,o_None,248);
- AddOpcode('SPHL',o_None,249);
- AddOpcode('EI' ,o_None,251);
-
- AddOpcode('ADI' ,o_One,198);
- AddOpcode('ACI' ,o_One,206);
- AddOpcode('OUT' ,o_One,211);
- AddOpcode('SUI' ,o_One,214);
- AddOpcode('IN' ,o_One,219);
- AddOpcode('SBI' ,o_One,222);
- AddOpcode('ANI' ,o_One,230);
- AddOpcode('XRI' ,o_One,238);
- AddOpcode('ORI' ,o_One,246);
- AddOpcode('CPI' ,o_One,254);
-
- AddOpcode('SHLD',o_Two,34);
- AddOpcode('LHLD',o_Two,42);
- AddOpcode('STA' ,o_Two,50);
- AddOpcode('LDA' ,o_Two,58);
- AddOpcode('JNZ' ,o_Two,194);
- AddOpcode('JMP' ,o_Two,195);
- AddOpcode('CNZ' ,o_Two,196);
- AddOpcode('JZ' ,o_Two,202);
- AddOpcode('CZ' ,o_Two,204);
- AddOpcode('CALL',o_Two,205);
- AddOpcode('JNC' ,o_Two,210);
- AddOpcode('CNC' ,o_Two,212);
- AddOpcode('JC' ,o_Two,218);
- AddOpcode('CC' ,o_Two,220);
- AddOpcode('JPO' ,o_Two,226);
- AddOpcode('CPO' ,o_Two,228);
- AddOpcode('JPE' ,o_Two,234);
- AddOpcode('CPE' ,o_Two,236);
- AddOpcode('JP' ,o_Two,242);
- AddOpcode('CP' ,o_Two,244);
- AddOpcode('JM' ,o_Two,250);
- AddOpcode('CM' ,o_Two,252);
-
- AddOpcode('INR' ,o_InrDcr,4);
- AddOpcode('DCR' ,o_InrDcr,5);
-
- AddOpcode('ADD' ,o_Arith,128);
- AddOpcode('ADC' ,o_Arith,136);
- AddOpcode('SUB' ,o_Arith,144);
- AddOpcode('SBB' ,o_Arith,152);
- AddOpcode('ANA' ,o_Arith,160);
- AddOpcode('XRA' ,o_Arith,168);
- AddOpcode('ORA' ,o_Arith,176);
- AddOpcode('CMP' ,o_Arith,184);
-
- AddOpcode('MOV' ,o_MOV,64);
-
- AddOpcode('MVI' ,o_MVI,6);
-
- AddOpcode('LXI' ,o_LXI,1);
-
- AddOpcode('INX' ,o_InxDcx,3);
- AddOpcode('DAD' ,o_InxDcx,9);
- AddOpcode('DCX' ,o_InxDcx,11);
-
- AddOpcode('POP' ,o_PushPop,193);
- AddOpcode('PUSH',o_PushPop,197);
-
- AddOpcode('STAX',o_StaxLdax,2);
- AddOpcode('LDAX',o_StaxLdax,10);
-
- AddOpcode('RST' ,o_RST,199);
-
- AddOpcode('DB' ,o_DB,0);
- AddOpcode('DW' ,o_DW,0);
- AddOpcode('DS' ,o_DS,0);
-
- AddOpcode('=' ,o_EQU,0);
- AddOpcode('EQU' ,o_EQU,0);
- AddOpcode('SET' ,o_EQU,1);
-
- AddOpcode('ORG' ,o_ORG,0);
- AddOpcode('END' ,o_END,0);
- AddOpcode('LIST',o_LIST,0);
- AddOpcode('OPT' ,o_OPT,0);
- END;
-
-
- FUNCTION FindSym(symName: SymStr): SymPtr;
- VAR
- p: SymPtr;
- found: Boolean;
-
- BEGIN
- found := FALSE;
- p := SymTab;
- WHILE (p<>NIL) AND NOT Found DO BEGIN
- found := (p^.name = symName);
- IF NOT found THEN
- p := p^.next;
- END;
-
- FindSym := p;
- END;
-
-
- FUNCTION AddSym(symName: SymStr): SymPtr;
- VAR
- p: SymPtr;
-
- BEGIN
- New(p);
-
- WITH p^ DO BEGIN
- name := SymName;
- value := 0;
- next := SymTab;
- defined := FALSE;
- multiDef := FALSE;
- isSet := FALSE;
- equ := FALSE;
- END;
-
- symTab := p;
-
- AddSym := p;
- END;
-
-
- FUNCTION RefSym(symName: SymStr): Integer;
- VAR
- p: SymPtr;
-
- BEGIN
- p := FindSym(symName);
- IF p=NIL THEN p := AddSym(symName);
-
- IF NOT p^.defined THEN
- Error('Symbol "' + symName + '" undefined');
-
- RefSym := p^.value;
- END;
-
-
- PROCEDURE DefSym(symName: SymStr; val: Integer; setSym,equSym: Boolean);
- VAR
- p: SymPtr;
-
- BEGIN
- IF Length(symName)<>0 THEN BEGIN
-
- p := FindSym(symName);
- IF p=NIL THEN p := AddSym(symName);
-
- IF (NOT p^.defined) OR (p^.isSet AND setSym) THEN BEGIN
- p^.value := val;
- p^.defined := TRUE;
- p^.isSet := setSym;
- p^.equ := equSym;
- END
- ELSE IF p^.value <> val THEN BEGIN
- p^.multiDef := TRUE;
- Error('Symbol "' + symName + '" multiply defined');
- END;
- END;
- END;
-
-
- FUNCTION GetWord: String;
- VAR
- word: String;
- done: Boolean;
-
- BEGIN
- line := Deblank(line);
- word := '';
-
- IF Length(line)>0 THEN
- IF (line[1]=#12) OR (line[1]=';') THEN
- line := '';
-
- IF Length(line)>0 THEN BEGIN
- IF Pos(Upcase(line[1]),alphaNumeric)=0 THEN BEGIN
- word := Copy(Line,1,1);
- Delete(line,1,1);
- END
- ELSE BEGIN
- done := FALSE;
- WHILE (Length(line)>0) AND NOT done DO BEGIN
- word := word + Upcase(line[1]);
- Delete(line,1,1);
- IF Length(line)>0 THEN
- done := Pos(Upcase(line[1]),AlphaNumeric)=0;
- END;
- END;
- END;
-
- GetWord := word;
- END;
-
-
- PROCEDURE Expect(expected: String);
- BEGIN
- IF GetWord<>expected THEN
- Error('"' + expected + '" expected');
- END;
-
-
- PROCEDURE Comma;
- BEGIN
- Expect(',');
- END;
-
-
- FUNCTION EvalOct(octStr: String): Integer;
- VAR
- octVal: Integer;
- evalErr: Boolean;
- i,n: Integer;
-
- BEGIN
- evalErr := FALSE;
- octVal := 0;
-
- FOR i := 1 TO Length(octStr) DO BEGIN
- n := Pos(octStr[i],'01234567');
- IF n=0 THEN evalErr := TRUE
- ELSE octVal := octVal*8 + n-1;
- END;
-
- IF evalErr THEN BEGIN
- octVal := 0;
- Error('Invalid octal number');
- END;
-
- EvalOct := octVal;
- END;
-
-
- FUNCTION EvalDec(decStr: String): Integer;
- VAR
- decVal: Integer;
- evalErr: Boolean;
- i,n: Integer;
-
- BEGIN
- evalErr := FALSE;
- decVal := 0;
-
- FOR i := 1 TO Length(decStr) DO BEGIN
- n := Pos(decStr[i],'0123456789');
- IF n=0 THEN evalErr := TRUE
- ELSE decVal := decVal*10 + n-1;
- END;
-
- IF evalErr THEN BEGIN
- decVal := 0;
- Error('Invalid decimal number');
- END;
-
- EvalDec := decVal;
- END;
-
-
- FUNCTION EvalHex(hexStr: String): Integer;
- VAR
- hexVal: Integer;
- evalErr: Boolean;
- i,n: Integer;
-
- BEGIN
- evalErr := FALSE;
- hexVal := 0;
-
- FOR i := 1 TO Length(hexStr) DO BEGIN
- n := Pos(Upcase(hexStr[i]),'0123456789ABCDEF');
- IF n=0 THEN evalErr := TRUE
- ELSE hexVal := hexVal*16 + n-1;
- END;
-
- IF evalErr THEN BEGIN
- hexVal := 0;
- Error('Invalid hexadecimal number');
- END;
-
- EvalHex := hexVal;
- END;
-
-
- FUNCTION Eval: Integer; FORWARD;
-
-
- FUNCTION Factor: Integer;
- VAR
- word: String;
- val: Integer;
-
- BEGIN
- word := GetWord;
- val := 0;
- IF Length(word)=0 THEN Error('Missing operand')
- ELSE IF (word='.') OR (word='*') THEN val := locPtr
- ELSE IF word='-' THEN val := -Factor
- ELSE IF word='+' THEN val := Factor
- ELSE IF word='~' THEN val := -Factor-1
- ELSE IF word='(' THEN BEGIN
- val := Eval;
- Expect(')');
- END
- ELSE IF word='''' THEN BEGIN
- IF Length(line)=0 THEN
- Error('Missing operand')
- ELSE BEGIN
- val := Ord(line[1]);
- Delete(line,1,1);
- Expect('''');
- END;
- END
- ELSE IF Pos(word[1],numeric)>0 THEN BEGIN
- CASE word[Length(word)] OF
- 'O': val := EvalOct(Copy(word,1,Length(word)-1));
- 'D': val := EvalDec(Copy(word,1,Length(word)-1));
- 'H': val := EvalHex(Copy(word,1,Length(word)-1));
- ELSE val := EvalDec(word);
- END;
- END
- ELSE val := RefSym(word);
-
- Factor := val;
- END;
-
-
- FUNCTION Term: Integer;
- VAR
- word: String;
- val: Integer;
- oldLine: String;
-
- BEGIN
- val := Factor;
-
- oldLine := line;
- word := GetWord;
- WHILE (word='*') OR (word='/') OR (word='%') DO BEGIN
- CASE word[1] OF
- '*': val := val * Factor;
- '/': val := val DIV Factor;
- '%': val := val MOD Factor;
- END;
- oldLine := line;
- word := GetWord;
- END;
- line := oldLine;
-
- Term := val;
- END;
-
-
- FUNCTION Eval: Integer;
- VAR
- word: String;
- val: Integer;
- oldLine: String;
-
- BEGIN
- val := Term;
-
- oldLine := line;
- word := GetWord;
- WHILE (word='+') OR (word='-') {OR (word='*') OR (word='/')} DO BEGIN
- CASE word[1] OF
- '+': val := val + Term;
- '-': val := val - Term;
- END;
- oldLine := line;
- word := GetWord;
- END;
- line := oldLine;
-
- Eval := val;
- END;
-
-
- FUNCTION EvalByte: Integer;
- VAR
- val: Integer;
-
- BEGIN
- val := Eval;
-
- IF (val<-128) OR (val>255) THEN
- Error('Byte out of range');
-
- EvalByte := val AND 255;
- END;
-
-
- FUNCTION FindReg(regName,regList,valList: String): Integer;
- VAR
- p: Integer;
- reg: Integer;
- code: Integer;
-
- BEGIN
- p := Pos(' ' + Deblank(regName) + ' ',regList);
-
- IF p=0 THEN BEGIN
- reg := 0;
- Error('Illegal register "' + Deblank(RegName) + '"');
- END
- ELSE
- Val(Copy(valList,p,2),reg,code);
-
- FindReg := reg;
- END;
-
-
- PROCEDURE CodeOut(byte: Integer);
- BEGIN
- IF pass=2 THEN
- WriteLn(object,Hex2(byte));
- END;
-
-
- PROCEDURE CodeOrg(addr: Integer);
- BEGIN
- locPtr := addr;
-
- IF pass=2 THEN
- WriteLn(object,':',Hex4(addr));
- END;
-
-
- PROCEDURE CodeFlush;
- BEGIN
- { Object file format does not use buffering; no flush needed }
- END;
-
-
- PROCEDURE CodeEnd;
- BEGIN
- CodeFlush;
-
- IF (pass=2) AND xferFound THEN BEGIN
- WriteLn(object,'$',Hex4(xferAddr));
- END;
- END;
-
-
- PROCEDURE CodeXfer(addr: Integer);
- BEGIN
- xferAddr := addr;
- xferFound := TRUE;
- END;
-
-
- PROCEDURE DoOpcode(typ,parm: Integer);
- VAR
- val: Integer;
- reg1: Integer;
- reg2: Integer;
- word: String;
- oldLine: String;
-
- BEGIN
- CASE typ OF
- o_None: BEGIN
- instr[1] := parm;
- instrLen := 1;
- END;
-
- o_One: BEGIN
- instr[1] := parm;
- instr[2] := EvalByte;
- instrLen := 2;
- END;
-
- o_Two: BEGIN
- val := Eval;
- instr[1] := parm;
- instr[2] := val AND 255;
- instr[3] := val SHR 8;
- instrLen := 3;
- END;
-
- o_InrDcr: BEGIN
- reg1 := FindReg(GetWord,regs,regVals);
- instr[1] := parm + reg1*8;
- instrLen := 1;
- END;
-
- o_Arith: BEGIN
- reg1 := FindReg(GetWord,regs,regVals);
- instr[1] := parm + reg1;
- instrLen := 1;
- END;
-
- o_MOV: BEGIN
- reg1 := FindReg(GetWord,regs,regVals);
- Comma;
- reg2 := FindReg(GetWord,regs,regVals);
- instr[1] := parm + reg1*8 + reg2;
- instrLen := 1;
- END;
-
- o_MVI: BEGIN
- reg1 := FindReg(GetWord,regs,regVals);
- Comma;
- instr[1] := parm + reg1*8;
- instr[2] := EvalByte;
- instrLen := 2;
- END;
-
- o_LXI: BEGIN
- reg1 := FindReg(GetWord,regPairs,regPairVals);
- Comma;
- val := Eval;
- instr[1] := parm + reg1*16;
- instr[2] := val AND 255;
- instr[3] := val SHR 8;
- instrLen := 3;
- END;
-
- o_InxDcx: BEGIN
- reg1 := FindReg(GetWord,regPairs,regPairVals);
- instr[1] := parm + reg1*16;
- instrLen := 1;
- END;
-
- o_PushPop: BEGIN
- reg1 := FindReg(GetWord,pushRegs,pushRegVals);
- instr[1] := parm + reg1*16;
- instrLen := 1;
- END;
-
- o_StaxLdax: BEGIN
- reg1 := FindReg(GetWord,staxRegs,staxRegVals);
- instr[1] := parm + reg1*16;
- instrLen := 1;
- END;
-
- o_RST: BEGIN
- val := Eval;
- CASE val OF
- 0,1,2,3,4,5,6,7: val := val * 8;
- 8,16,24,32,40,48,56: ;
- ELSE BEGIN
- Error('Illegal restart number');
- val := 0;
- END;
- END;
- instr[1] := parm + val;
- instrLen := 1;
- END;
-
- o_DB: BEGIN
- oldLine := line;
- word := GetWord;
- IF word='''' THEN BEGIN
- val := Pos('''',line);
- IF val=0 THEN BEGIN
- bytStr := line;
- line := '';
- END
- ELSE BEGIN
- bytStr := Copy(line,1,val-1);
- Delete(line,1,val);
- END;
- instrLen := -Length(bytStr);
- END
- ELSE BEGIN
- line := oldLine;
- instr[1] := EvalByte;
- instrLen := 1;
- END;
- END;
-
- o_DW: BEGIN
- val := Eval;
- instr[1] := val AND 255;
- instr[2] := val SHR 8;
- instrLen := 2;
- END;
-
- o_DS: BEGIN
- val := Eval;
-
- IF pass=2 THEN BEGIN
- showAddr := FALSE;
- Delete(listLine,1,13);
- listLine := Hex4(locPtr) + ': (' + Hex4(val) + ')'
- + listLine;
- END;
-
- val := val + locPtr;
- CodeOrg(val);
- END;
-
- o_END: BEGIN
- oldLine := line;
-
- IF Length(GetWord)<>0 THEN BEGIN
- line := oldLine;
- val := Eval;
- CodeXfer(val);
- line := Copy(line,1,7) + '(' + Hex4(val) + ')' +
- Copy(line,14,255);
- END;
-
- sourceEnd := TRUE;
- END;
-
- ELSE Error('Unknown opcode');
- END;
- END;
-
-
- PROCEDURE DoLabelOp(typ,parm: Integer; labl: SymStr);
- VAR
- val: Integer;
- word: String;
-
- BEGIN
- CASE typ OF
- o_EQU: BEGIN
- IF Length(labl)=0 THEN
- Error('Missing label')
- ELSE BEGIN
- val := Eval;
-
- listLine := Copy(listLine,1,6) + '= ' + Hex4(val) +
- Copy(listLine,13,255);
-
- DefSym(labl,val,parm=1,parm=0);
- END;
- END;
-
-
- o_ORG: BEGIN
- CodeOrg(Eval);
- DefSym(labl,locPtr,FALSE,FALSE);
- showAddr := TRUE;
- END;
-
- o_LIST: BEGIN
- listThisLine := TRUE;
-
- IF Length(labl)<>0 THEN
- Error('Label not allowed');
-
- word := GetWord;
- IF word='ON' THEN listFlag := TRUE
- ELSE IF word='OFF' THEN listFlag := FALSE
- ELSE Error('Illegal operand');
- END;
-
- o_OPT: BEGIN
- listThisLine := TRUE;
-
- IF Length(labl)<>0 THEN
- Error('Label not allowed');
-
- word := GetWord;
- IF word='LIST' THEN listFlag := TRUE
- ELSE IF word='NOLIST' THEN listFlag := FALSE
- ELSE Error('Illegal option');
- END;
-
- ELSE Error('Unknown opcode');
- END;
- END;
-
-
- PROCEDURE ListOut;
- VAR
- i: Integer;
-
- BEGIN
- IF Deblank(listLine) = #12 THEN
- WriteLn(listing,#12)
-
- ELSE IF Deblank(listLine)='' THEN
- WriteLn(listing)
-
- ELSE BEGIN
- i := Length(listLine);
- WHILE (i>0) AND (listLine[i]=' ') DO
- Dec(i);
- listLine[0] := CHR(i);
-
- WriteLn(listing,listLine);
- IF errFlag AND cl_Err THEN
- WriteLn(listLine);
- END;
- END;
-
-
- PROCEDURE DoPass;
- VAR
- labl: SymStr;
- opcode: OpcdStr;
- typ: Integer;
- parm: Integer;
- i: Integer;
- word: String;
-
- BEGIN
- Assign(source,cl_SrcName);
- Reset(source);
- sourceEnd := FALSE;
-
- WriteLn('Pass ',pass);
-
- CodeOrg(0);
- errCount := 0;
- listFlag := TRUE;
-
- WHILE (NOT Eof(source)) AND (NOT SourceEnd) DO BEGIN
- ReadLn(source,line);
-
- errFlag := FALSE;
- instrLen := 0;
- showAddr := FALSE;
- listThisLine := ListFlag;
- listLine := ' '; { 16 blanks }
-
- IF Pass=2 THEN listLine := Copy(listLine,1,16) + line;
-
- labl := '';
-
- IF Length(line)>0 THEN
- IF Pos(line[1],white)=0 THEN BEGIN
- labl := GetWord;
- showAddr := (Length(labl)<>0);
-
- IF Length(line)>0 THEN
- IF line[1]=':' THEN
- Delete(line,1,1);
-
- END;
-
- opcode := GetWord;
- IF Length(opcode)=0 THEN BEGIN
- typ := 0;
- DefSym(labl,locPtr,FALSE,FALSE);
- END
- ELSE BEGIN
- FindOpcode(opcode,typ,parm);
-
- IF typ=o_Illegal THEN Error('Illegal opcode "' +
- Deblank(opcode) + '"')
- ELSE IF typ<0 THEN BEGIN
- showAddr := FALSE;
- DoLabelOp(typ,parm,labl);
- END
- ELSE BEGIN
- showAddr := TRUE;
- DefSym(labl,locPtr,FALSE,FALSE);
- DoOpcode(typ,parm);
- END;
-
- IF typ<>o_Illegal THEN
- IF Length(GetWord)>0 THEN
- Error('Too many operands');
- END;
-
- IF Pass=2 THEN BEGIN
- IF ShowAddr THEN
- listLine := Hex4(locPtr) + ':' + Copy(listLine,6,255);
-
- IF instrLen>0 THEN
- FOR i := 1 TO instrLen DO BEGIN
- word := Hex2(instr[i]);
- listLine[i*3+4] := word[1];
- listLine[i*3+5] := word[2];
- CodeOut(instr[I]);
- END
- ELSE FOR i := 1 TO -instrLen DO BEGIN
- IF I<=3 THEN BEGIN
- word := Hex2(ORD(bytStr[i]));
- listLine[i*3+4] := word[1];
- listLine[i*3+5] := word[2];
- END;
- CodeOut(ORD(bytStr[i]));
- END;
-
- IF listThisLine THEN ListOut;
- END;
-
- locPtr := locPtr + ABS(instrLen);
- END;
-
- IF Pass=2 THEN CodeEnd;
-
- { Put the lines after the END statement into the listing file }
- { while still checking for listing control statements. Ignore }
- { any lines which have invalid syntax, etc., because whatever }
- { is found after an END statement should esentially be ignored. }
-
- IF Pass=2 THEN
- WHILE NOT Eof(source) DO BEGIN
- listThisLine := listFlag;
- listLine := ' ' + line; { 16 blanks }
-
- IF Length(line)>0 THEN
- IF Pos(line[1],white)<>0 THEN BEGIN
- word := GetWord;
- IF Length(word)<>0 THEN BEGIN
- IF word='LIST' THEN
- BEGIN
- listThisLine := TRUE;
- word := GetWord;
-
- IF word='ON' THEN listFlag := TRUE
- ELSE IF word='OFF' THEN listFlag := FALSE
- ELSE listThisLine := listFlag;
- END
-
- ELSE IF word='OPT' THEN
- BEGIN
- listThisLine := TRUE;
- word := GetWord;
-
- IF word='LIST' THEN listFlag := TRUE
- ELSE IF word='NOLIST' THEN listFlag := FALSE
- ELSE listThisLine := listFlag;
- END;
- END;
- END;
-
- IF listThisLine THEN ListOut;
- END;
-
- Close(source);
- END;
-
-
- PROCEDURE SortSymTab;
- VAR
- i,j,t: SymPtr;
- sorted: Boolean;
- temp: SymRec;
-
- BEGIN
- IF symTab<>NIL THEN BEGIN
-
- i := symTab;
- j := i^.next;
- WHILE (j<>NIL) DO BEGIN
- sorted := TRUE;
-
- WHILE (j<>NIL) DO BEGIN
- IF j^.name < i^.name THEN BEGIN
- temp := i^;
- i^ := j^;
- j^ := temp;
-
- t := i^.next;
- i^.next := j^.next;
- j^.next := t;
-
- sorted := FALSE;
- END;
- j := j^.next;
- END;
- i := i^.next;
- j := i^.next;
- END;
- END;
- END;
-
-
- PROCEDURE DumpSym(p: SymPtr);
- BEGIN
- Write(listing,p^.name:maxSymLen,' ',Hex4(p^.value));
-
- IF NOT p^.defined THEN Write(listing,' U');
- IF p^.multiDef THEN Write(listing,' M');
- IF p^.isSet THEN Write(listing,' S');
- IF p^.equ THEN Write(listing,' E');
-
- WriteLn(listing);
- END;
-
-
- PROCEDURE DumpSymTab;
- VAR
- p: SymPtr;
-
- BEGIN
- SortSymTab;
-
- p := symTab;
- WHILE (p<>NIL) DO BEGIN
- DumpSym(p);
- p := p^.next;
- END;
- END;
-
-
- PROCEDURE ShowOptions;
- BEGIN
- WriteLn;
- WriteLn(' Command line syntax:');
- WriteLn;
- WriteLn(' ASM8080 [options] src [options]');
- WriteLn;
- WriteLn(' Valid options:');
- WriteLn;
- WriteLn(' -E Show errors to screen');
- WriteLn(' -L Make a listing file to src.LIS');
- WriteLn(' -L=name');
- WriteLn(' -O Make an object file to src.OBJ');
- WriteLn(' -O=name');
- WriteLn;
- END;
-
-
- FUNCTION GetOption(VAR optStr: String): String;
- VAR
- option: String[80];
- p: Integer;
-
- BEGIN
- optStr := Deblank(optStr);
-
- p := Pos(' ',optStr);
-
- IF p=0 THEN BEGIN
- option := optStr;
- optStr := '';
- END
- ELSE BEGIN
- option := Copy(optStr,1,p-1);
- optStr := Copy(optStr,p+1,255);
- END;
-
- optStr := UprCase(Deblank(optStr));
-
- GetOption := option;
- END;
-
-
- FUNCTION GetOptions(VAR cl_SrcName, cl_ListName,cl_ObjName: String; VAR cl_Err: Boolean): Boolean;
- VAR
- s: String;
- len: Integer;
- optStr: String;
- option: String;
- optParm: String;
- prefix: String;
- p: Integer;
- err: Integer;
- optErr: Boolean;
- i: Integer;
-
- BEGIN
- cl_SrcName := '';
- cl_ListName := 'NUL';
- cl_ObjName := 'NUL';
- cl_Err := FALSE;
-
- optErr := FALSE;
- optStr := ParamStr(1);
- FOR i := 2 TO ParamCount DO
- optStr := optStr + ' ' + ParamStr(i);
-
- option := GetOption(optStr);
- WHILE Length(option)<>0 DO BEGIN
- optParm := '';
-
- p := Pos('=',option);
- IF p>0 THEN BEGIN
- optParm := Copy(option,p+1,255);
- option := Copy(option,1,p-1);
- END;
-
- IF option = '-L' THEN cl_ListName := optParm
- ELSE IF option = '-O' THEN cl_ObjName := optParm
- ELSE IF option = '-E' THEN cl_Err := TRUE
- ELSE IF option = '?' THEN optErr := TRUE
- ELSE BEGIN
- IF (Copy(option,1,1)='-') OR (Length(cl_SrcName)<>0) OR
- (Length(optParm)<>0) THEN BEGIN
- optErr := TRUE;
- WriteLn('Illegal command line option: ',option);
- END
- ELSE BEGIN
- cl_SrcName := option;
- IF Pos('.',cl_SrcName)=0 THEN
- IF p=0 THEN cl_SrcName := cl_SrcName + '.ASM';
-
- p := Pos('.',option);
- IF p=0 THEN prefix := option
- ELSE prefix := Copy(option,1,p-1);
- END;
- END;
-
- option := GetOption(optStr);
- END;
-
- IF cl_SrcName = '' THEN BEGIN
- optErr := TRUE;
- WriteLn('Source file not specified')
- END;
-
- IF cl_ListName = '' THEN cl_ListName := prefix + '.LIS';
- IF cl_ObjName = '' THEN cl_ObjName := prefix + '.DAT';
- IF Copy(cl_ListName,1,1)='.' THEN cl_ListName := prefix + cl_ListName;
- IF Copy(cl_ObjName ,1,1)='.' THEN cl_ObjName := prefix + cl_ObjName;
-
- GetOptions := optErr;
- END;
-
-
- BEGIN
- IF GetOptions(cl_SrcName,cl_ListName,cl_ObjName,cl_Err) THEN BEGIN
- ShowOptions;
- Halt;
- END;
-
- Assign(listing,cl_ListName);
- Rewrite(listing);
- Assign(object,cl_ObjName);
- Rewrite(object);
-
- symTab := NIL;
- xferAddr := 0;
- xferFound := FALSE;
- InitOpcodes;
-
- pass := 1;
- DoPass;
-
- pass := 2;
- DoPass;
-
- WriteLn(listing);
- WriteLn(listing,errCount:5,' Total Error(s)');
- WriteLn(listing);
-
- IF cl_Err THEN BEGIN
- WriteLn;
- WriteLn(errCount:5,' Total Error(s)');
- END;
-
- DumpSymTab;
-
- Close(listing);
- Close(object);
- END.