PROGRAM ASSEM8086 (TTY); (*** ASSMML.PAS -- MAIN LINE AND UTILITIES ***) (* THIS IS 8086 CROSS ASSEMBLER THAT RUNS ON PDP-11 AND GENERATES CODE FOR THE INTEL 8086 MICROPROCESSOR. AUTHOR: T.J. MATHIEU. BATTELLE NORTHWEST, RICHLAND, WASH. 509-946-3711 prepared for the US Dept of Energy under contract EY-76-C-06-1830 VERSION DATE DESCRIPTION ------- ----- ----------- V1.0 11/78 BASIC ASSEMBLER, NO RELOCATION, FULL EXPRESSIONS, NO MACROS. WITH TKB EXTTSK=4000, ROOM FOR 667. SYMBOLS. V2.0 2/79 PRIMITIVE MACROS, SEPARATE ASSEMBLY (LINKER) V2.1 4/79 MACRO PARAMETERS, NO NESTING. *) (*$R-*) (*$I+ASSMHD.PAS*) (*************************************************************** UTILILTY PROCEDURES ***************************************************************) PROCEDURE ENTERSYMB(S,L : SYMPTR); (* ENTER SYMBOL POINTED AT BY S INTO SYMBOL TABLE AFTER SYMBOL POINTED AT BY L. *) BEGIN NSYMBS := SUCC(NSYMBS); IF L = NIL THEN BEGIN S^.SNXT := SYMTOP; SYMTOP := S END ELSE BEGIN S^.SNXT := L^.SNXT; L^.SNXT := S END; END; (* OF ENTERSYMB *) PROCEDURE NEWSYMB(N:NAME; V:INTEGER; T:SYMTYP; VAR S:SYMPTR); BEGIN (*** CREATE NEW SYMBOL ENTRY ***) NEW(S); WITH S^ DO BEGIN SNAME := N; SVAL := V; STYP := T; SNXT := NIL; END; END; PROCEDURE FINDSYMB (S:NAME; VAR L:SYMPTR; VAR B:BOOLEAN); (* SEARCH SYMBOL TABLE FOR SYMBOL NAMED S. RETURN 1. (B=TRUE, L POINTS AT SYMBOL) IF SYMBOL IN TABLE. 2. (B=FALSE, L POINTS AT SYMBOL S GOES AFTER) IF SYMBOL NOT IN TABLE. *) VAR S1:SYMPTR; BEGIN B := FALSE; L := NIL; (* ASSUME NOT THERE *) S1 := SYMTOP; IF SYMTOP <> NIL THEN IF S >= S1^.SNAME THEN BEGIN (* FIND THE SYMBOL *) REPEAT L := S1; S1 := S1^.SNXT; B := (L^.SNAME = S) OR (S1 = NIL); IF NOT B THEN B := S < S1^.SNAME; UNTIL B; B := S = L^.SNAME; END; END; (* FINDSYMB *) PROCEDURE ADDSYMB (N:NAME; T:SYMTYP; V:INTEGER); (* ADD A NEW SYMBOL TO SYMBOL TABLE *) VAR S,L:SYMPTR; B:BOOLEAN; BEGIN NEWSYMB(N,V,T,S); FINDSYMB(N,L,B); ENTERSYMB(S,L); END; PROCEDURE SKIPBLANKS(VAR N : INTEGER); BEGIN WITH STATEMENTS^ DO WHILE (STMNT[N]=' ') AND (N=10 THEN J := J + ORD('A') - 10 ELSE J := J + ORD('0'); W[I] := CHR(J) END END; FUNCTION NEOLINE(K:INTEGER) : BOOLEAN; (** TRUE IF NOT END OF STATEMENT **) BEGIN WITH STATEMENTS^ DO NEOLINE := (K<>STMLEN) AND (STMNT[K] <> ';') END; PROCEDURE LOADSYMB (VAR N:INTEGER); (*** LOAD SYMBOL POINTED AT BY N INTO GLOBAL GSYM ***) VAR J:INTEGER; BEGIN J := N; WITH STATEMENTS^ DO IF STMNT[N] = '$' THEN BEGIN N := SUCC(N); GSYM[1] := '$'; END ELSE WHILE (STMNT[N] IN LABCH) AND (N-J+1<=NAMELEN) DO BEGIN GSYM[N-J+1] := STMNT[N]; N := SUCC(N); END; FOR J := N-J+1 TO NAMELEN DO GSYM[J] := ' '; WITH STATEMENTS^ DO WHILE (STMNT[N] IN LABCH) AND (N',') END; (*$Y+*) PROCEDURE INITIALIZE; VAR OP : INSTR; FN : ARRAY[1..13] OF CHAR; J : INTEGER; PROCEDURE SETOPN(OP:TWOCHAR; PREC:INTEGER); BEGIN WITH EXOPS[J] DO BEGIN OPTR:=OP; OPREC:=PREC END; J := SUCC(J) END; PROCEDURE INITTAB; EXTERN; BEGIN INITTAB; (** SET UP OP CODE TABLE **) NSYMBS := 0; (** ENTER DEFAULT SYMBOLS INTO SYMBOL TABLE **) ADDSYMB('AX ',REGNM,0); ADDSYMB('CX ',REGNM,1); ADDSYMB('DX ',REGNM,2); ADDSYMB('BX ',REGNM,3); ADDSYMB('SP ',REGNM,4); ADDSYMB('BP ',REGNM,5); ADDSYMB('SI ',REGNM,6); ADDSYMB('DI ',REGNM,7); ADDSYMB('AL ',REGNM,8); ADDSYMB('CL ',REGNM,9); ADDSYMB('DL ',REGNM,10); ADDSYMB('BL ',REGNM,11); ADDSYMB('AH ',REGNM,12); ADDSYMB('CH ',REGNM,13); ADDSYMB('DH ',REGNM,14); ADDSYMB('BH ',REGNM,15); ADDSYMB('ES ',REGNM,16); ADDSYMB('CS ',REGNM,17); ADDSYMB('SS ',REGNM,18); ADDSYMB('DS ',REGNM,19); ADDSYMB('$ ',MEMR,0); (*** SET THE EXPR OPS AND PRECEDENCE ***) J := 1; SETOPN('( ',0); SETOPN(') ',0); SETOPN('* ',7); SETOPN('/ ',7); SETOPN('% ',7); SETOPN('<-',7); SETOPN('->',7); SETOPN('+ ',6); SETOPN('- ',6); SETOPN('= ',5); SETOPN('< ',5); SETOPN('<=',5); SETOPN('> ',5); SETOPN('>=',5); SETOPN('<>',5); SETOPN('--',4); SETOPN('& ',3); SETOPN('! ',2); SETOPN('# ',2); SETOPN('HI',1); SETOPN('LO',1); (*** INIT CHAR SCAN CONTROL SETS ***) OP1 := ['(',')','*','/','%','<','>','-','+','=','&','!','#']; OP2 := ['-','>','=']; LABCH := ['A'..'Z','0'..'9','@']; (* VALID SYMBOL CHARS *) EXPTERM := [ ';', ',', '.', ':', '[' ]; (** EXPRESSION TERMINATORS **) HASSBTL := FALSE; (** NO SUBTITLES, YET *) IFLEV := 0; TTL := ' '; STTL := TTL; FIRSTSEG := TRUE; END; (* OF INITIALIZATION *) PROCEDURE OPENFILES; (* GET AND OPEN SOURCE, OBJECT, AND LISTING FILES *) VAR F:NAME; PROCEDURE SETFILE (VAR FN : FILENAME); VAR I,J : INTEGER; FL:BOOLEAN; BEGIN I := 1; LOOP FL := I>NAMELEN; IF NOT FL THEN FL := FN.FNAME[I] = ' '; EXIT IF FL; TFN[I] := FN.FNAME[I]; I := SUCC(I); END; FOR J := 1 TO NAMELEN DO TFN[I+J-1] := FN.SUFFX[J]; FOR J := I+NAMELEN+1 TO 2*NAMELEN DO TFN[J] := ' '; END; BEGIN (* OPENFILES *) WRITELN(TTY,ASSMID); WRITE(TTY,'FILE? '); BREAK; READLN; READ(F); WITH LFN DO BEGIN FNAME := F; SUFFX := '.LIS '; DEV := 'SY: ' END; WITH OFN DO BEGIN FNAME := F; SUFFX := '.OBJ '; DEV := 'SY: ' END; WITH SFN DO BEGIN FNAME := F; SUFFX := '.ASM '; DEV := 'SY: ' END; SETFILE(OFN); REWRITE(OBJ ,TFN,,OFN.DEV); SETFILE(SFN); RESET(SOURCE,TFN,,SFN.DEV); IF IORESULT(SOURCE) <> 1 THEN BEGIN WRITELN(TTY,'FILE NOT FOUND'); ERRINPROG:= TRUE END ELSE ERRINPROG := FALSE; SETFILE(LFN); (** OPEN IT AFTER PASS 1 **) END; (* **) PROCEDURE WRITEMESS; (** DEBUG AID **) VAR I : INTEGER; BEGIN WITH STATEMENTS^ DO FOR I := 1 TO 20 DO WRITE(TTY,STMNT[I]); WRITELN(TTY,' '); END; (* *) (****************************************************** PASS ONE -- SYMBOL DEFINITION ******************************************************) PROCEDURE PASSONE; EXTERN; (********************************************************** PASS TWO -- CODE GENERATION **********************************************************) PROCEDURE PASSTWO; EXTERN; PROCEDURE EVALOPND(VAR N:INTEGER; VAR O:OPERAND); EXTERN; PROCEDURE DELETF; EXTERN; (*$Y+*********************************************************** PASS 1.5 (MIDDLE) -- SHORTEN CODE FOR FORWARD JMP/CALLS ***************************************************************) PROCEDURE PASSMID; VAR J,NRK,SHORTEN,SH1,K : INTEGER; O:OPERAND; CHG,SFND:BOOLEAN; BEGIN K := 0; REPEAT (** CHECK EACH CODE LINE **) SHORTEN := 0; SH1:=0; NRK := 1; WHILE NRK<=NRC DO BEGIN GET(STATEMENTS,NRK); CHG := FALSE; WITH STATEMENTS^ DO BEGIN IF (SHORTEN>0) THEN (** CHANGE THIS LINE'S ADDRESS **) IF (OPERATIONS[ST].OPTYP <> PSEUD) OR (ST=DB) OR (ST=DW) OR (ST=ENDD) OR (ST=DSB) OR (ST=DSW) THEN BEGIN ADDR := ADDR-SHORTEN; IF HASLBL THEN BEGIN J := LABSTR; LOADSYMB(J); FINDSYMB(GSYM,GS,SFND); GS^.SVAL := GS^.SVAL - SHORTEN; END; END ELSE IF (ST = ORG) OR (ST = CSEG) OR (ST = DSEG) THEN BEGIN SH1:=SH1+SHORTEN; SHORTEN:=0 END; IF (ST=JMP) AND (MRLN=109) AND (OPDSTR<>0) THEN (** IT MIGHT SHORTEN **) BEGIN J := OPDSTR; EVALOPND(J,O); J := O.OPV - ADDR - 2; IF (J<=128) AND (J>-129) AND (O.OPTP<>FREF) THEN BEGIN SHORTEN := SHORTEN+1; MRLN := 77; END; END; (*** JUMP FIX ***) IF (MRLN=133) OR (MRLN=143) THEN BEGIN (** FORWARD IMMED REF **) J := OPDSTR; EVALOPND(J,O); CHG := TRUE; IF (O.OPTP<>FREF) AND (O.OTP=1) THEN SHORTEN := SHORTEN+1; MRLN := MRLN - 32; END; END; (*** WITH ***) IF CHG OR (SHORTEN>0) THEN PUT(STATEMENTS,NRK); NRK := SUCC(NRK); END; (*** OF WHILE ***) K := SUCC(K); UNTIL (SHORTEN=0) AND (SH1=0) OR (K=3); WRITELN(TTY,K:3,' CODE OPTIMIZATION PASSES'); END; (*********************************************************** SYMBOL TABLE LIST ***********************************************************) PROCEDURE STBLIST; CONST SPPG=280; (* SYMBOLS PER PAGE *) VAR NP,NSL : INTEGER; W : WORD; STPR : ARRAY [1..5,1..56] OF SYMPTR; J : INTEGER; PROCEDURE SLPG(NS:INTEGER); (** OUPUT ONE PAGE OF SYMBOLS **) VAR NSPL,I,J,K : INTEGER; BEGIN NSPL := (NS+4) DIV 5; (** NUMBER SYMBS PER COLUMN **) FOR J := 1 TO 5 DO FOR K := 1 TO NSPL DO BEGIN STPR[J,K] := GS; IF GS <> NIL THEN GS := GS^.SNXT; END; (*** HEADING ***) PAGE(LIST); WRITELN(LIST,'SYMBOL TABLE LIST':63); WRITELN(LIST); FOR I:= 1 TO 5 DO WRITE(LIST,'SYMBOL VALUE TYPE SIZE '); WRITELN(LIST); FOR I:= 1 TO 5 DO WRITE(LIST,'------ ----- ---- ---- '); WRITELN(LIST); FOR J := 1 TO NSPL DO BEGIN (** OUTPUT EACH ROW **) FOR K := 1 TO 5 DO IF STPR[K,J] <> NIL THEN WITH STPR[K,J]^ DO BEGIN WRITE(LIST,SNAME); HEXLY(SVAL,W); WRITE(LIST,W:6); CASE STYP OF REGNM : WRITE(LIST,' REG '); CHBL,PERM : WRITE(LIST,' CNST'); SEGNM : WRITE(LIST,' SEGN'); XTLB,XTLW,XTLS : WRITE(LIST,' XTRN'); OTHERS : WRITE(LIST,' ADDR') END; IF (STYP=XTLB) OR (STYP=MBYTE) OR (STYP=REGNM) AND ((SVAL>=8) OR (SVAL<=15)) THEN WRITE(LIST,' BYTE') ELSE WRITE(LIST,' WORD'); WRITE(LIST,' ':4); END; (** WITH **) WRITELN(LIST); END; (** OF FOR **) END; BEGIN NP := NSYMBS DIV SPPG + 1; (** NUMBER OF PAGES **) NSL := NSYMBS MOD SPPG; IF NSL=0 THEN BEGIN NP := NP-1; NSL := SPPG END; GS := SYMTOP; FOR J := 2 TO NP DO SLPG(SPPG); SLPG(NSL); END; (*$P+*) (**********************************************************) BEGIN (* MAIN LINE *) OPENFILES; IF NOT ERRINPROG THEN BEGIN EC:=0; INITIALIZE; STIME := RUNTIME; PASSONE; WRITELN(TTY,NSYMBS,' SYMBOLS IN PROGRAM'); WRITELN(TTY,'PASS ONE COMPLETE'); PASSMID; IF HASSBTL THEN (** NEED TWO FILES -- ONE FOR CONTENTS, ONE FOR LISTING **) BEGIN REWRITE(LIST,'SC2.TMP'); REWRITE(SOURCE,TFN); WRITELN(SOURCE,'TABLE OF CONTENTS FOR PROGRAM ',SFN.FNAME); WRITELN(SOURCE); WRITELN(SOURCE,'LINE PAGE':56); WRITELN(SOURCE,'---- ----':56); END ELSE REWRITE(LIST,TFN); (** ONLY ONE FILE **) PASSTWO; IF ERRINPROG THEN WRITELN(TTY,EC,' ERROR(S) IN PROGRAM'); STBLIST; WRITELN(LIST); WRITELN(LIST); WRITELN(LIST); WRITELN(LIST); WRITELN(LIST,EC,' ERROR(S) IN PROGRAM'); WRITELN(LIST,NSYMBS,' SYMBOLS IN PROGRAM'); IF HASSBTL THEN (** APPEND LISTING TO TABLE OF CONTENTS **) BEGIN PAGE(SOURCE); RESET(LIST,'SC2.TMP'); WHILE NOT EOF(LIST) DO BEGIN WHILE NOT EOLN(LIST) DO BEGIN READ(LIST,STRING[1]); WRITE(SOURCE,STRING[1]); END; WRITELN(SOURCE); READLN(LIST); END; CLOSEF(LIST); DELETF; END; WRITELN(TTY,RUNTIME-STIME,' SECONDS TO ASSEMBLE') END END.