brownc@utah-cs.UUCP (Eric C. Brown) (05/03/85)
# Due to overwhelming demand, (15 requests in 3 days), here is the 6502 # assembler in C: #!/bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #!/bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # assmtest # assmtest.l # makefile # user.nr # This archive created: Tue Apr 2 14:21:42 1985 # By: James Van Ornum (AT&T-Bell Laboratories) export PATH; PATH=/bin:$PATH if test -f 'assmtest' then echo shar: over-writing existing file "'assmtest'" fi cat << \SHAR_EOF > 'assmtest' ;****************************************** ; Test file for the 6502 assembler - as6502 ; assemble as ; as6502 -nisv assmtest ; and compare output with assmtest.l ;****************************************** ;; comment treatment ;****************************************** aa = $10; ';' immediately after the '0' B = $20 space to comment subfield C = $30 tab to comment subfield DEFGHIjkl = $FFEE D =DEFGHIjkl ;****************************************** ; Number formats ;****************************************** start *= $4 ; location counter adjust .byte %0101 ; binary number .byte 022,@22 ; octal numbers - two forms .byte 22 ; decimal number .byte $22,$ff,$FF ; hex - upper/lower case .byte 'a,'b ; single ASCII characters ;****************************************** ;; ASCII character string ;****************************************** .byte "abcd\t\n",0 ; tab and new line escaped ;****************************************** ; Operation checks ;****************************************** .word aa+B ; addition .word aa-B ; subtraction .word aa*B ; multiplication .word B/aa ; division .word C%B ; modulo .word B^C ; exclusive OR .word ~C ; one's complement .word B&C ; logical AND .word aa|B ; logical OR .word <D ; low byte .word >D ; high byte .word * ; current location .word aa,B,C .word B*[aa+C] ; one level of parenthesis .dbyt D ; high byte-low byte word .word D/256,D%256 ;****************************************** ; Addressing Mode Check ;****************************************** *=$0100 lda =aa ; immediate addressing lda #aa ; immediate addressing, alternate lda D ; direct addessing LDA aa ; page zero addressing, aa < 256 a1 = 512 a2 = 500 lda a1-a2 ; also page zero asl A ; accumulator addressing AsL a ; accumulator addressing also brk ; implied addressing lda (aa,X) ; indirect,X addressing lda (aa),Y ; indirect,Y addressing lda aa,X ; zero page,X addressing lda D,X ; absolute,X addressing lda D,Y ; absolute,Y addressing bcc *-$10 ; relative addressing jmp (D) ; indirect addressing ldx aa,Y ; zero page,Y addressing ldx aa,y ; alternate index name .nlst ;****************************************** ; opcode check ;****************************************** adc =01 and =01 asl A bcc *+2 bcs *+2 beq *+2 bit $01 bmi *+2 bne *+2 bpl *+2 brk bvc *+2 bvs *+2 clc cld cli clv cmp =01 cpx =01 cpy =01 dec $01 dex dey eor =01 inc $01 inx iny jmp *+3 jsr *+3 lda =01 ldx =01 ldy =01 lsr A nop ora =01 pha php pla plp rol A ror A rti rts sbc =01 sec sed sei sta $01 stx $01 sty $01 tax tay tsx txa txs tya SHAR_EOF if test -f 'assmtest.l' then echo shar: over-writing existing file "'assmtest.l'" fi cat << \SHAR_EOF > 'assmtest.l' as6502 - version 4.1 - 11/5/84 - JHV 1 ;****************************************** 2 ; Test file for the 6502 assembler - as6502 3 ; assemble as 4 ; as6502 -nisv assmtest 5 ; and compare output with assmtest.l 6 ;****************************************** 7 ; ; comment treatment 8 ;****************************************** 9 0010 aa = $10 ; ';' immediately after the '0' 10 0020 B = $20 space to comment subfield 11 0030 C = $30 tab to comment subfield 12 FFEE DEFGHIjkl = $FFEE 13 FFEE D =DEFGHIjkl 14 ;****************************************** 15 ; Number formats 16 ;****************************************** 17 0004 start *= $4 ; location counter adjust 18 0004 05 .byte %0101 ; binary number 19 0005 12 12 .byte 022,@22 ; octal numbers - two forms 20 0007 16 .byte 22 ; decimal number 21 0008 22 FF FF .byte $22,$ff,$FF ; hex - upper/lower case 22 000B 61 62 .byte 'a,'b ; single ASCII characters 23 ;****************************************** 24 ; ; ASCII character string 25 ;****************************************** 26 000D 61 62 63 .byte "abcd\t\n",0 ; tab and new line escaped 0010 64 09 0A 0013 00 27 ;****************************************** 28 ; Operation checks 29 ;****************************************** 30 0014 30 00 .word aa+B ; addition 31 0016 F0 FF .word aa-B ; subtraction 32 0018 00 02 .word aa*B ; multiplication 33 001A 02 00 .word B/aa ; division 34 001C 10 00 .word C%B ; modulo 35 001E 10 00 .word B^C ; exclusive OR 36 0020 CF FF .word ~C ; one's complement 37 0022 20 00 .word B&C ; logical AND 38 0024 30 00 .word aa|B ; logical OR 39 0026 EE 00 .word <D ; low byte 40 0028 FF 00 .word >D ; high byte 41 002A 2A 00 .word * ; current location 42 002C 10 00 .word aa,B,C 002E 20 00 0030 30 00 43 0032 00 08 .word B*[aa+C] ; one level of parenthesis 44 0034 FF EE .dbyt D ; high byte-low byte word 45 0036 FF 00 .word D/256,D%256 0038 EE 00 46 ;****************************************** 47 ; Addressing Mode Check 48 ;****************************************** 49 0100 *=$0100 50 0100 A9 10 lda =aa ; immediate addressing 51 0102 A9 10 lda #aa ; immediate addressing, alternate 52 0104 AD EE FF lda D ; direct addessing 53 0107 A5 10 LDA aa ; page zero addressing, aa < 256 54 0200 a1 = 512 55 01F4 a2 = 500 56 0109 A5 0C lda a1-a2 ; also page zero 57 010B 0A asl A ; accumulator addressing 58 010C 0A AsL a ; accumulator addressing also 59 010D 00 brk ; implied addressing 60 010E A1 10 lda (aa,X) ; indirect,X addressing 61 0110 B1 10 lda (aa),Y ; indirect,Y addressing 62 0112 B5 10 lda aa,X ; zero page,X addressing 63 0114 BD EE FF lda D,X ; absolute,X addressing 64 0117 B9 EE FF lda D,Y ; absolute,Y addressing 65 011A 90 EE bcc *-$10 ; relative addressing 66 011C 6C EE FF jmp (D) ; indirect addressing 67 011F B6 10 ldx aa,Y ; zero page,Y addressing 68 0121 B6 10 ldx aa,y ; alternate index name 70 ;****************************************** 71 ; opcode check 72 ;****************************************** 73 0123 69 01 adc =01 74 0125 29 01 and =01 75 0127 0A asl A 76 0128 90 00 bcc *+2 77 012A B0 00 bcs *+2 78 012C F0 00 beq *+2 79 012E 24 01 bit $01 80 0130 30 00 bmi *+2 81 0132 D0 00 bne *+2 82 0134 10 00 bpl *+2 83 0136 00 brk 84 0137 50 00 bvc *+2 85 0139 70 00 bvs *+2 86 013B 18 clc 87 013C D8 cld 88 013D 58 cli 89 013E B8 clv 90 013F C9 01 cmp =01 91 0141 E0 01 cpx =01 92 0143 C0 01 cpy =01 93 0145 C6 01 dec $01 94 0147 CA dex 95 0148 88 dey 96 0149 49 01 eor =01 97 014B E6 01 inc $01 98 014D E8 inx 99 014E C8 iny 100 014F 4C 52 01 jmp *+3 101 0152 20 55 01 jsr *+3 102 0155 A9 01 lda =01 103 0157 A2 01 ldx =01 104 0159 A0 01 ldy =01 105 015B 4A lsr A 106 015C EA nop 107 015D 09 01 ora =01 108 015F 48 pha 109 0160 08 php 110 0161 68 pla 111 0162 28 plp 112 0163 2A rol A 113 0164 6A ror A 114 0165 40 rti 115 0166 60 rts 116 0167 E9 01 sbc =01 117 0169 38 sec 118 016A F8 sed 119 016B 78 sei 120 016C 85 01 sta $01 121 016E 86 01 stx $01 122 0170 84 01 sty $01 123 0172 AA tax 124 0173 A8 tay 125 0174 BA tsx 126 0175 8A txa 127 0176 9A txs 128 0177 98 tya aa 10:00 0010 B 20:00 0020 C 30:00 0030 DEFGHIjkl EE:FF FFEE D EE:FF FFEE start 04:00 0004 a1 00:02 0200 a2 F4:01 01F4 SHAR_EOF if test -f 'makefile' then echo shar: over-writing existing file "'makefile'" fi cat << \SHAR_EOF > 'makefile' as6502: assm0.o assm1.o assm2.o assm3.o cc -s -i assm0.o assm1.o assm2.o assm3.o -o as6502 assm0.o: assm.d1 assm.d2 assm0.c cc -c -O assm0.c assm1.o: assm.d1 assm.d2 assm1.c cc -c -O assm1.c assm2.o: assm.d1 assm.d2 assm2.c cc -c -O assm2.c assm3.o: assm.d1 assm.d2 assm3.c cc -c -O assm3.c check: assmtest.l assmtest.l: as6502 as6502 -nisv assmtest > temp touch assmtest.l diff assmtest.l temp manuals: as6502.l user.l as6502.l: as6502.1 man -d as6502.1 > as6502.l user.l: user.nr nroff user.nr > user.l clean: rm assm0.o assm1.o assm2.o assm3.o temp as6502.l user.l SHAR_EOF if test -f 'user.nr' then echo shar: over-writing existing file "'user.nr'" fi cat << \SHAR_EOF > 'user.nr' .de hd 'sp 3 .tl ''\fBas6502 User Notes\fR'Page %' 'sp 2 .. .de fo 'bp .. .wh 0 hd .wh -3 fo .br \fBSOURCE LINE FORMAT\fR: .ti 0.5i .sp 1 <label> <operation> <operand> <comment> .sp 1 Each field is terminated by one or more spaces, a tab or a ';' (which begins the comment field immediately). .sp \fBLABEL FIELD\fR: .sp 1 If first character is ';', entire line is a comment. If first character is space, label field is null. Labels are alphanumeric strings beginning with 'a' through 'z', 'A' through 'Z', underscore or period followed by any of the above characters or '0' through '9'. Currently, labels are limited to 19 characters. A, X, Y, a, x and y are reserved labels. .sp \fBOPERATION FIELD\fR: .sp 1 Upper and lower case letters are equivalent. Machine operation mnemonics are: .in 0.5i .nf .sp 1 ADC BMI CLD DEX JSR PHA RTS STY AND BNE CLI DEY LDA PHP SBC TAX ASL BPL CLV EOR LDX PLA SEC TAY BCC BRK CMP INC LDY PLP SED TSX BCS BVC CPX INX LSR ROL SEI TXA BEQ BVS CPY INY NOP ROR STA TXS BIT CLC DEC JMP ORA RTI STX TYA .in 0 .fi .sp 1 Pseudo operation mnemonics are: .in 1.2i .ti 0.5i .sp 1 = equate label name to operand field value (space is not needed to terminate this operation). .ti 0.5i *= set location counter to operand field value (space is not needed to terminate this operation). .ti 0.5i .tr*. *WORD assign 16 bit value of operand field to next two locations; low byte of value first, then high byte. .ti 0.5i *DBYT assign 16 bit value of operand field to next two locations; high byte of value first, then low byte. .ti 0.5i *BYTE assign 8 bit value of operand field to next location. .ti 0.5i *NLST turn listing mode off (this source line is not listed). .ti 0.5i *LIST turn listing mode on (normal mode) (this source line is not listed). .tr** .in 0 .sp 1 \fBOPERAND FIELD\fR: .sp 1 Operand field expressions use infix notation and are evaluated strictly from left to right. No imbedded spaces are permitted. .sp 1 Operand field terms include labels and numbers. Asterisk (*) is the label for the location counter value. Numbers are binary, octal, decimal, hexadecimal or ASCII. Number type is indicated by the first character of the number string as follows: .nf .in 0.5i .sp 1 % binary prefix @ or 0 octal prefix 1 - 9 decimal by default (prefix is part of number) $ hexadecimal prefix .tr,' , ASCII character prefix .tr,, " ASCII character string prefix and suffix; in the string, \\t is a tab character, \\n is a new line. .in 0 .fi .sp 1 Operand field operations and the corresponding symbols are: .in 0.5i .nf .sp 1 + addition - subtraction / division * multiplication % modulo (remainder after integer division) ^ logical exclusive OR & logical AND | logical OR < low byte > high byte .in 0 .fi .sp 1 \fBERROR MESSAGES\fR: .in 0.5i .nf .sp 1 Invalid operation code Invalid argument count (when as6502 was invoked) Open error for file Creat error for object file 6502.out Close error Close error (6502.out) Symbol table full Label multiply defined Sync error (pass 1 symbol value not equal pass 2 symbol value) Invalid branch address Operand field missing Invalid addressing mode Operand field size error Undefined symbol in operand field Invalid operand field .fi .in 0 .sp 1 \fBINVOKING as6502\fR: .sp 1 .ti 0.5i as6502 {-ilnos} <source files descriptions> .sp 1 Options: .in 0.5i .nf .sp 1 -i ignore any .nlst pseudo operations -l list errors only -n print addresses as <high byte><low byte>, rather than as <low byte>:<high byte>. -o generate ASCII object output in file 6502.out, format is ;<address lo><address hi><data> -s print symbol table at end of listing J. H. Van Ornum 11/5/84 SHAR_EOF # End of shell archive exit 0
brownc@utah-cs.UUCP (Eric C. Brown) (05/03/85)
#!/bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #!/bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # as6502.1 # assm.d1 # assm.d2 # assm0.c # assm1.c # This archive created: Tue Apr 2 14:21:10 1985 # By: James Van Ornum (AT&T-Bell Laboratories) export PATH; PATH=/bin:$PATH if test -f 'as6502.1' then echo shar: over-writing existing file "'as6502.1'" fi cat << \SHAR_EOF > 'as6502.1' .TH AS6502 1 11/5/84 .SH NAME as6502 \- assembler for MOS Technology 650X microprocessors .SH SYNOPSIS .B as6502 [ option ] file ... .SH DESCRIPTION .I As6502 assembles the named files and produces a listing on the standard output. Available options are: .TP 4 .B \-i ignore .nlst pseudo ops in the source file. .TP .B \-l produce only an error listing on the standard output. .TP .B \-n print address in normal <high byte><low byte> format, rather than split <low byte>:<high byte> format. .TP .B \-o generate the ASCII object file .B "6502.out." The per-line format of that file is: .br ;<address low byte><address high byte><data>... .TP .B \-s print symbol table at the end of the assembly listing. .TP Symbol conventions: .br .tr ~| Up to 19 alphanumeric (a-z ~ A-Z ~ 0-9 ~ . ~ _) characters, .tr ~~ with initial character non-numeric. .sp Asterisk (*) is symbolic name of the location counter. .TP Op code mnemonics (upper and/or lower case): .br ADC BIT BVS CPX INC LDX PHP RTI SEI TAY .br AND BMI CLC CPY INX LDY PLA RTS STA TSX .br ASL BNE CLD DEC INY LSR PLP SBC STX TXA .br BCC BPL CLI DEX JMP NOP ROL SEC STY TXS .br BCS BRK CLV DEY JSR ORA ROR SED TAX TYA .br BEQ BVC CMP EOR LDA PHA .TP Pseudo op mnemonics: .br = equate label to operand value. .br *= equate location counter to operand value. .br .WORD assign 16 bit operand value to next 2 locations. .br .DBYT assign 16 bit value to next 2 locations, reverse. .br .BYTE assign 8 bit operand value to next location. .br .NLST turn listing mode off. .br .LIST turn listing mode on. .TP Constant types: .br % binary number prefix. .br @ or 0 octal number prefix. .br $ hexadecimal number prefix. .br ' ASCII character prefix. .br " ASCII character string prefix and suffix. .br default (leading digit 1 through 9) decimal number. .TP Operand field operators: .br + addition ^ logical exclusive OR .br - subtraction ~ logical 1's complement .br / integer division $ logical AND .br .tr || * multiplication | logical OR .br % modulo < low byte .br > high byte .SH FILES .PD 0 .TP /BIN/as6502 the assembler .TP 6502.out object (with -o option) .SH "SEE ALSO" .TP J. H. Van Ornum, "as6502 User Notes" .SH DIAGNOSTICS .in 0 File handling diagnostics: .in 15 .ti 5 Invalid argument count - as6502 invoked without a source file or with too many source files. .ti 5 Open error for file <name> - as6502 cannot open source file. .ti 5 Create error (6502.out) - as6502 cannot create object file. .ti 5 Close error - as6502 cannot close the source file. .ti 5 Close error (6502.out) - as6502 cannot close object file. .in 0 Assembly error diagnostics: .in 15 .ti 5 Symbol table full - symbol table overflowed allotted space. Number of symbols is a function of symbol sizes. .ti 5 Label multiply defined - symbol defined more than once. .ti 5 Sync error - the pass 2 value of symbol in the label field is different than the pass 1 value. .ti 5 Invalid operation code - op code mnemonic is invalid. .ti 5 Operand field missing - the op code mnemonic requires an operand, and none was found. .ti 5 Invalid operand field - operand field contains an operator which is not recognized by as6502. .ti 5 Invalid branch address - branch instruction to a location which is out of range. .ti 5 Invalid addressing mode - tried to use an addressing mode which is not available to the operation code. .ti 5 Operand field size error - operand is larger than hex FF. .ti 5 Undefined symbol in operand field - a symbol in the operand field never appeared in the label field. .SH BUGS SHAR_EOF if test -f 'assm.d1' then echo shar: over-writing existing file "'assm.d1'" fi cat << \SHAR_EOF > 'assm.d1' #define LAST_CH_POS 132 #define SFIELD 23 #define STABSZ 6000 #define SBOLSZ 20 /* * symbol flags */ #define DEFZRO 2 /* defined - page zero address */ #define MDEF 3 /* multiply defined */ #define UNDEF 1 /* undefined - may be zero page */ #define DEFABS 4 /* defined - two byte address */ #define UNDEFAB 5 /* undefined - two byte address */ /* * operation code flags */ #define PSEUDO 0x6000 #define CLASS1 0x2000 #define CLASS2 0x4000 #define IMM1 0x1000 /* opval + 0x00 2 byte */ #define IMM2 0x0800 /* opval + 0x08 2 byte */ #define ABS 0x0400 /* opval + 0x0C 3 byte */ #define ZER 0x0200 /* opval + 0x04 2 byte */ #define INDX 0x0100 /* opval + 0x00 2 byte */ #define ABSY2 0x0080 /* opval + 0x1C 3 byte */ #define INDY 0x0040 /* opval + 0x10 2 byte */ #define ZERX 0x0020 /* opval + 0x14 2 byte */ #define ABSX 0x0010 /* opval + 0x1C 3 byte */ #define ABSY 0x0008 /* opval + 0x18 3 byte */ #define ACC 0x0004 /* opval + 0x08 1 byte */ #define IND 0x0002 /* opval + 0x2C 3 byte */ #define ZERY 0x0001 /* opval + 0x14 2 byte */ /* * pass flags */ #define FIRST_PASS 0 #define LAST_PASS 1 #define DONE 2 SHAR_EOF if test -f 'assm.d2' then echo shar: over-writing existing file "'assm.d2'" fi cat << \SHAR_EOF > 'assm.d2' extern FILE *optr; extern FILE *iptr; extern int dflag; /* debug flag */ extern int errcnt; /* error counter */ extern int hash_tbl[]; /* pointers to starting links in symtab */ extern char hex[]; /* hexadecimal character buffer */ extern int iflag; /* ignore .nlst flag */ extern int lablptr; /* label pointer into symbol table */ extern int lflag; /* disable listing flag */ extern int loccnt; /* location counter */ extern int nflag; /* normal/split address mode */ extern int nxt_free; /* next free location in symtab */ extern int objcnt; /* object byte counter */ extern int oflag; /* object output flag */ extern int opflg; /* operation code flags */ extern int opval; /* operation code value */ extern int pass; /* pass counter */ extern char prlnbuf[]; /* print line buffer */ extern int sflag; /* symbol table output flag */ extern int slnum; /* source line number counter */ extern char symtab[]; /* symbol table */ extern char symbol[]; /* temporary symbol storage */ extern int udtype; /* undefined symbol type */ extern int undef; /* undefined symbol in expression flg */ extern int value; /* operand field value */ extern char zpref; /* zero page reference flag */ SHAR_EOF if test -f 'assm0.c' then echo shar: over-writing existing file "'assm0.c'" fi cat << \SHAR_EOF > 'assm0.c' #include "stdio.h" #include "assm.d1" /* Assembler for the MOS Technology 650X series of microprocessors * Written by J. H. Van Ornum (201) 949-1781 * AT&T Bell Laboratories * Holmdel, NJ */ FILE *optr; FILE *iptr; int dflag; /* debug flag */ int errcnt; /* error counter */ int hash_tbl[128]; /* pointers to starting links in symtab */ char hex[5]; /* hexadecimal character buffer */ int iflag; /* ignore .nlst flag */ int lablptr; /* label pointer into symbol table */ int lflag; /* disable listing flag */ int loccnt; /* location counter */ int nflag; /* normal/split address mode */ int nxt_free; /* next free location in symtab */ int objcnt; /* object byte counter */ int oflag; /* object output flag */ int opflg; /* operation code flags */ int opval; /* operation code value */ int pass; /* pass counter */ char prlnbuf[LAST_CH_POS+1]; /* print line buffer */ int sflag; /* symbol table output flag */ int slnum; /* source line number counter */ char symtab[STABSZ]; /* symbol table */ /* struct sym_tab */ /* { char size; */ /* char chars[size]; */ /* char flag; */ /* int value; */ /* int next_pointer */ /* } */ char symbol[SBOLSZ]; /* temporary symbol storage */ int udtype; /* undefined symbol type */ int undef; /* undefined symbol in expression flg */ int value; /* operand field value */ char zpref; /* zero page reference flag */ #define A 0x20)+('A'&0x1f)) #define B 0x20)+('B'&0x1f)) #define C 0x20)+('C'&0x1f)) #define D 0x20)+('D'&0x1f)) #define E 0x20)+('E'&0x1f)) #define F 0x20)+('F'&0x1f)) #define G 0x20)+('G'&0x1f)) #define H 0x20)+('H'&0x1f)) #define I 0x20)+('I'&0x1f)) #define J 0x20)+('J'&0x1f)) #define K 0x20)+('K'&0x1f)) #define L 0x20)+('L'&0x1f)) #define M 0x20)+('M'&0x1f)) #define N 0x20)+('N'&0x1f)) #define O 0x20)+('O'&0x1f)) #define P 0x20)+('P'&0x1f)) #define Q 0x20)+('Q'&0x1f)) #define R 0x20)+('R'&0x1f)) #define S 0x20)+('S'&0x1f)) #define T 0x20)+('T'&0x1f)) #define U 0x20)+('U'&0x1f)) #define V 0x20)+('V'&0x1f)) #define W 0x20)+('W'&0x1f)) #define X 0x20)+('X'&0x1f)) #define Y 0x20)+('Y'&0x1f)) #define Z 0x20)+('Z'&0x1f)) #define OPSIZE 63 int optab[] = /* nmemonic operation code table */ { /* '.' = 31, '*' = 30, '=' = 29 */ ((0*0x20)+(29)),PSEUDO,1, ((((0*0x20)+(30))*0x20)+(29)),PSEUDO,3, ((((((0*A*D*C,IMM2|ABS|ZER|INDX|INDY|ZERX|ABSX|ABSY,0x61, ((((((0*A*N*D,IMM2|ABS|ZER|INDX|INDY|ZERX|ABSX|ABSY,0x21, ((((((0*A*S*L,ABS|ZER|ZERX|ABSX|ACC,0x02, ((((((0*B*C*C,CLASS2,0x90, ((((((0*B*C*S,CLASS2,0xb0, ((((((0*B*E*Q,CLASS2,0xf0, ((((((0*B*I*T,ABS|ZER,0x20, ((((((0*B*M*I,CLASS2,0x30, ((((((0*B*N*E,CLASS2,0xd0, ((((((0*B*P*L,CLASS2,0x10, ((((((0*B*R*K,CLASS1,0x00, ((((((0*B*V*C,CLASS2,0x50, ((((((0*B*V*S,CLASS2,0x70, ((((((0*C*L*C,CLASS1,0x18, ((((((0*C*L*D,CLASS1,0xd8, ((((((0*C*L*I,CLASS1,0x58, ((((((0*C*L*V,CLASS1,0xb8, ((((((0*C*M*P,IMM2|ABS|ZER|INDX|INDY|ZERX|ABSX|ABSY,0xc1, ((((((0*C*P*X,IMM1|ABS|ZER,0xe0, ((((((0*C*P*Y,IMM1|ABS|ZER,0xc0, ((((((0*D*E*C,ABS|ZER|ZERX|ABSX,0xc2, ((((((0*D*E*X,CLASS1,0xca, ((((((0*D*E*Y,CLASS1,0x88, ((((((0*E*O*R,IMM2|ABS|ZER|INDX|INDY|ZERX|ABSX|ABSY,0x41, ((((((0*I*N*C,ABS|ZER|ZERX|ABSX,0xe2, ((((((0*I*N*X,CLASS1,0xe8, ((((((0*I*N*Y,CLASS1,0xc8, ((((((0*J*M*P,ABS|IND,0x40, ((((((0*J*S*R,ABS,0x14, ((((((0*L*D*A,IMM2|ABS|ZER|INDX|INDY|ZERX|ABSX|ABSY,0xa1, ((((((0*L*D*X,IMM1|ABS|ZER|ABSY2|ZERY,0xa2, ((((((0*L*D*Y,IMM1|ABS|ZER|ABSX|ZERX,0xa0, ((((((0*L*S*R,ABS|ZER|ZERX|ABSX|ACC,0x42, ((((((0*N*O*P,CLASS1,0xea, ((((((0*O*R*A,IMM2|ABS|ZER|INDX|INDY|ZERX|ABSX|ABSY,0x01, ((((((0*P*H*A,CLASS1,0x48, ((((((0*P*H*P,CLASS1,0x08, ((((((0*P*L*A,CLASS1,0x68, ((((((0*P*L*P,CLASS1,0x28, ((((((0*R*O*L,ABS|ZER|ZERX|ABSX|ACC,0x22, ((((((0*R*O*R,ABS|ZER|ZERX|ABSX|ACC,0x62, ((((((0*R*T*I,CLASS1,0x40, ((((((0*R*T*S,CLASS1,0x60, ((((((0*S*B*C,IMM2|ABS|ZER|INDX|INDY|ZERX|ABSX|ABSY,0xe1, ((((((0*S*E*C,CLASS1,0x38, ((((((0*S*E*D,CLASS1,0xf8, ((((((0*S*E*I,CLASS1,0x78, ((((((0*S*T*A,ABS|ZER|INDX|INDY|ZERX|ABSX|ABSY,0x81, ((((((0*S*T*X,ABS|ZER|ZERY,0x82, ((((((0*S*T*Y,ABS|ZER|ZERX,0x80, ((((((0*T*A*X,CLASS1,0xaa, ((((((0*T*A*Y,CLASS1,0xa8, ((((((0*T*S*X,CLASS1,0xba, ((((((0*T*X*A,CLASS1,0x8a, ((((((0*T*X*S,CLASS1,0x9a, ((((((0*T*Y*A,CLASS1,0x98, ((((((0*0x20)+(31))*W*O^((((0*R*D,PSEUDO,2, /* 0x7cab */ ((((((0*0x20)+(31))*B*Y^((((0*T*E,PSEUDO,0, /* 0x7edc */ ((((((0*0x20)+(31))*D*B^((((0*Y*T,PSEUDO,6, /* 0x7fb6 */ ((((((0*0x20)+(31))*N*L^((((0*S*T,PSEUDO,5, /* 0x7fb8 */ ((((((0*0x20)+(31))*L*I^((((0*S*T,PSEUDO,4, /* 0x7ffd */ 0x7fff,0,0, 0x7fff,0,0 }; int step[] = { 3*((OPSIZE+1)/2), 3*((((OPSIZE+1)/2)+1)/2), 3*((((((OPSIZE+1)/2)+1)/2)+1)/2), 3*((((((((OPSIZE+1)/2)+1)/2)+1)/2)+1)/2), 3*(2), 3*(1), 0 }; SHAR_EOF if test -f 'assm1.c' then echo shar: over-writing existing file "'assm1.c'" fi cat << \SHAR_EOF > 'assm1.c' #include "stdio.h" #include "assm.d1" #include "assm.d2" #define CPMEOF EOF /* * Two changes to version 1.4 have been made to "port" as6502 to CP/M(tm). * A "tolower()" function call was add to the command line processing * code to (re)map the command line arguments to lower case (CP/M * converts all command line arguments to upper case). The readline() * function has code added to "ignore" the '\r' character (CP/M includes * the \r character along with \n). * * Also, the ability to process multiple files on the command line has been * added. Now one can do, for example: * * as6502 -nisvo header.file source.file data.file ... * * George V. Wilder * IX 1A-360 x1937 * ihuxp!gvw1 */ main(argc, argv) int argc; char *argv[]; { char c; int cnt; int i; int ac; char **av; while (--argc > 0 && (*++argv)[0] == '-') { for (i = 1; (c = tolower((*argv)[i])) != '\0'; i++) { if (c == 'd') /* debug flag */ dflag++; if (c == 'i') /* ignore .nlst flag */ iflag++; if (c == 'l') /* disable listing flag */ lflag--; if (c == 'n') /* normal/split address mode */ nflag++; if (c == 'o') /* object output flag */ oflag++; if (c == 's') /* list symbol table flag */ sflag++; if (c == 'v') /* print assembler version */ fprintf(stdout, "as6502 - version 4.1b - 11/22/84 - JHV [gvw]\n"); } } ac = argc; av = argv; pass = FIRST_PASS; for (i = 0; i < 128; i++) hash_tbl[i] = -1; errcnt = loccnt = slnum = 0; while (pass != DONE) { initialize(ac, av, argc); if(pass == LAST_PASS && ac == argc) errcnt = loccnt = slnum = 0; while (readline() != -1) assemble(); if (errcnt != 0) { pass = DONE; fprintf(stderr, "Terminated with error counter = %d\n", errcnt); } switch (pass) { case FIRST_PASS: --ac; ++av; if(ac == 0) { pass = LAST_PASS; if (lflag == 0) lflag++; ac = argc; av = argv; } break; case LAST_PASS: --ac; ++av; if(ac == 0) { pass = DONE; if (sflag != 0) stprnt(); } } wrapup(); if ((dflag != 0) && (pass == LAST_PASS)) { fprintf(stdout, "nxt_free = %d\n", nxt_free); cnt = 0; for (i = 0; i < 128; i++) if (hash_tbl[i] == -1) cnt++; fprintf(stdout, "%d unused hash table pointers out of 128\n", cnt); } } return(0); } /*****************************************************************************/ /* initialize opens files */ initialize(ac, av, argc) int ac; char *av[]; int argc; { if (ac == 0) { fprintf(stderr, "Invalid argument count (%d).\n", argc); exit(1); } if ((iptr = fopen(*av, "r")) == NULL) { fprintf(stderr, "Open error for file '%s'.\n", *av); exit(1); } if ((pass == LAST_PASS) && (oflag != 0) && ac == argc) { if ((optr = fopen("6502.out", "w")) == NULL) { fprintf(stderr, "Create error for object file 6502.out.\n"); exit(1); } } } /* readline reads and formats an input line */ int field[] = { SFIELD, SFIELD + 8, SFIELD + 14, SFIELD + 23, SFIELD + 43, SFIELD + 75 }; readline() { int i; /* pointer into prlnbuf */ int j; /* pointer to current field start */ int ch; /* current character */ int cmnt; /* comment line flag */ int spcnt; /* consecutive space counter */ int string; /* ASCII string flag */ int temp1; /* temp used for line number conversion */ temp1 = ++slnum; for (i = 0; i < LAST_CH_POS; i++) prlnbuf[i] = ' '; i = 3; while (temp1 != 0) { /* put source line number into prlnbuf */ prlnbuf[i--] = temp1 % 10 + '0'; temp1 /= 10; } i = SFIELD; cmnt = spcnt = string = 0; j = 1; while ((ch = getc(iptr)) != '\n') { if(ch == '\r') continue; prlnbuf[i++] = ch; if ((ch == ' ') && (string == 0)) { if (spcnt != 0) --i; else if (cmnt == 0) { ++spcnt; if (i < field[j]) i = field[j]; if (++j > 3) { spcnt = 0; ++cmnt; } } } else if (ch == '\t') { prlnbuf[i - 1] = ' '; spcnt = 0; if (cmnt == 0) { if (i < field[j]) i = field[j]; if (++j > 3) ++cmnt; } else i = (i + 8) & 0x78; } else if ((ch == ';') && (string == 0)) { spcnt = 0; if (i == SFIELD + 1) ++cmnt; else if (prlnbuf[i - 2] != '\'') { ++cmnt; prlnbuf[i-1] = ' '; if (i < field[3]) i = field[3]; prlnbuf[i++] = ';'; } } else if (ch == EOF || ch == CPMEOF) return(-1); else { if ((ch == '"') && (cmnt == 0)) string = string ^ 1; spcnt = 0; if (i >= LAST_CH_POS - 1) --i; } } prlnbuf[i] = 0; return(0); } /* * wrapup() closes the source file */ wrapup() { fclose(iptr); if ((pass == DONE) && (oflag != 0)) { fputc('\n', optr); fclose(optr); } return; } /* symbol table print */ stprnt() { int i; int j; int k; fputc('\014', stdout); fputc('\n', stdout); i = 0; while ((j = symtab[i++]) != 0) { for (k = j; k > 0; k--) fputc(symtab[i++], stdout); for (k = 20 - j; k > 0; k--) fputc(' ', stdout); ++i; j = (symtab[i++] & 0xff); j += (symtab[i++] << 8); hexcon(4, j); fprintf(stdout, "\t%c%c:%c%c\t%c%c%c%c\n", hex[3], hex[4], hex[1], hex[2], hex[1], hex[2], hex[3], hex[4]); i += 2; } } SHAR_EOF # End of shell archive exit 0
brownc@utah-cs.UUCP (Eric C. Brown) (05/03/85)
#!/bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #!/bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # assm2.c # assm3.c # This archive created: Tue Apr 2 14:21:24 1985 # By: James Van Ornum (AT&T-Bell Laboratories) export PATH; PATH=/bin:$PATH if test -f 'assm2.c' then echo shar: over-writing existing file "'assm2.c'" fi cat << \SHAR_EOF > 'assm2.c' #include "stdio.h" #include "assm.d1" #include "assm.d2" extern int optab[]; extern int step[]; /* translate source line to machine language */ assemble() { int flg; int i; /* prlnbuf pointer */ if ((prlnbuf[SFIELD] == ';') | (prlnbuf[SFIELD] == 0)) { if (pass == LAST_PASS) println(); return; } lablptr = -1; i = SFIELD; udtype = UNDEF; if (colsym(&i) != 0 && (lablptr = stlook()) == -1) return; while (prlnbuf[++i] == ' '); /* find first non-space */ if ((flg = oplook(&i)) < 0) { /* collect operation code */ labldef(loccnt); if (flg == -1) error("Invalid operation code"); if ((flg == -2) && (pass == LAST_PASS)) { if (lablptr != -1) loadlc(loccnt, 1, 0); println(); } return; } if (opflg == PSEUDO) pseudo(&i); else if (labldef(loccnt) == -1) return; else { if (opflg == CLASS1) class1(); else if (opflg == CLASS2) class2(&i); else class3(&i); } } /****************************************************************************/ /* printline prints the contents of prlnbuf */ println() { if (lflag > 0) fprintf(stdout, "%s\n", prlnbuf); } /* colsym() collects a symbol from prlnbuf into symbol[], * leaves prlnbuf pointer at first invalid symbol character, * returns 0 if no symbol collected */ colsym(ip) int *ip; { int valid; int i; char ch; valid = 1; i = 0; while (valid == 1) { ch = prlnbuf[*ip]; if (ch == '_' || ch == '.'); else if (ch >= 'a' && ch <= 'z'); else if (ch >= 'A' && ch <= 'Z'); else if (i >= 1 && ch >= '0' && ch <= '9'); else if (i == 1 && ch == '='); else valid = 0; if (valid == 1) { if (i < SBOLSZ - 1) symbol[++i] = ch; (*ip)++; } } if (i == 1) { switch (symbol[1]) { case 'A': case 'a': case 'X': case 'x': case 'Y': case 'y': error("Symbol is reserved (A, X or Y)"); i = 0; } } symbol[0] = i; return(i); } /* symbol table lookup * if found, return pointer to symbol * else, install symbol as undefined, and return pointer */ stlook() { int found; int hptr; int j; int nptr; int pptr; int ptr; hptr = 0; for (j = 0; j < symbol[0]; j++) hptr += symbol[j]; hptr %= 128; ptr = hash_tbl[hptr]; if (ptr == -1) { /* no entry for this link */ hash_tbl[hptr] = nxt_free; return(stinstal()); } while (symtab[ptr] != 0) { /* 0 count = end of table */ found = 1; for (j = 0; j <= symbol[0]; j++) { if (symbol[j] != symtab[ptr + j]) { found = 0; pptr = ptr + symtab[ptr] + 4; nptr = (symtab[pptr + 1] << 8) + (symtab[pptr] & 0xff); nptr &= 0xffff; if (nptr == 0) { symtab[ptr + symtab[ptr] + 4] = nxt_free & 0xff; symtab[ptr + symtab[ptr] + 5] = (nxt_free >> 8) & 0xff; return(stinstal()); } ptr = nptr; break; } } if (found == 1) return(ptr); } error("Symbol not found"); return(-1); } /* instal symbol into symtab */ stinstal() { register int j; register int ptr1; register int ptr2; ptr1 = ptr2 = nxt_free; if ((ptr1 + symbol[0] + 6) >= STABSZ) { error("Symbol table full"); return(-1); } for (j = 0; j <= symbol[0]; j++) symtab[ptr1++] = symbol[j]; symtab[ptr1] = udtype; nxt_free = ptr1 + 5; return(ptr2); } /* operation code table lookup * if found, return pointer to symbol, * else, return -1 */ oplook(ip) int *ip; { register char ch; register int i; register int j; int k; int temp[2]; i = j = 0; temp[0] = temp[1] = 0; while((ch=prlnbuf[*ip])!= ' ' && ch!= 0 && ch!= '\t' && ch!= ';') { if (ch >= 'A' && ch <= 'Z') ch &= 0x1f; else if (ch >= 'a' && ch <= 'z') ch &= 0x1f; else if (ch == '.') ch = 31; else if (ch == '*') ch = 30; else if (ch == '=') ch = 29; else return(-1); temp[j] = (temp[j] * 0x20) + (ch & 0xff); if (ch == 29) break; ++(*ip); if (++i >= 3) { i = 0; if (++j >= 2) { return(-1); } } } if ((j = temp[0]^temp[1]) == 0) return(-2); k = 0; i = step[k] - 3; do { if (j == optab[i]) { opflg = optab[++i]; opval = optab[++i]; return(i); } else if (j < optab[i]) i -= step[++k]; else i += step[++k]; } while (step[k] != 0); return(-1); } /* error printing routine */ error(stptr) char *stptr; { loadlc(loccnt, 0, 1); loccnt += 3; loadv(0,0,0); loadv(0,1,0); loadv(0,2,0); fprintf(stderr, "%s\n", prlnbuf); fprintf(stderr, "%s\n", stptr); errcnt++; } /* load 16 bit value in printable form into prlnbuf */ loadlc(val, f, outflg) int val; int f; int outflg; { int i; i = 6 + 7*f; hexcon(4, val); if (nflag == 0) { prlnbuf[i++] = hex[3]; prlnbuf[i++] = hex[4]; prlnbuf[i++] = ':'; prlnbuf[i++] = hex[1]; prlnbuf[i] = hex[2]; } else { prlnbuf[i++] = hex[1]; prlnbuf[i++] = hex[2]; prlnbuf[i++] = hex[3]; prlnbuf[i] = hex[4]; } if ((pass == LAST_PASS)&&(oflag != 0)&&(objcnt <= 0)&&(outflg != 0)) { fprintf(optr, "\n;%c%c%c%c", hex[3], hex[4], hex[1], hex[2]); objcnt = 16; } } /* load value in hex into prlnbuf[contents[i]] */ /* and output hex characters to obuf if LAST_PASS & oflag == 1 */ loadv(val,f,outflg) int val; int f; /* contents field subscript */ int outflg; /* flag to output object bytes */ { hexcon(2, val); prlnbuf[13 + 3*f] = hex[1]; prlnbuf[14 + 3*f] = hex[2]; if ((pass == LAST_PASS) && (oflag != 0) && (outflg != 0)) { fputc(hex[1], optr); fputc(hex[2], optr); --objcnt; } } /* convert number supplied as argument to hexadecimal in hex[digit] (lsd) through hex[1] (msd) */ hexcon(digit, num) int digit; int num; { for (; digit > 0; digit--) { hex[digit] = (num & 0x0f) + '0'; if (hex[digit] > '9') hex[digit] += 'A' -'9' - 1; num >>= 4; } } /* assign <value> to label pointed to by lablptr, * checking for valid definition, etc. */ labldef(lval) int lval; { int i; if (lablptr != -1) { lablptr += symtab[lablptr] + 1; if (pass == FIRST_PASS) { if (symtab[lablptr] == UNDEF) { symtab[lablptr + 1] = lval & 0xff; i = symtab[lablptr + 2] = (lval >> 8) & 0xff; if (i == 0) symtab[lablptr] = DEFZRO; else symtab[lablptr] = DEFABS; } else if (symtab[lablptr] == UNDEFAB) { symtab[lablptr] = DEFABS; symtab[lablptr + 1] = lval & 0xff; symtab[lablptr + 2] = (lval >> 8) & 0xff; } else { symtab[lablptr] = MDEF; symtab[lablptr + 1] = 0; symtab[lablptr + 2] = 0; error("Label multiply defined"); return(-1); } } else { i = (symtab[lablptr + 2] << 8) + (symtab[lablptr+1] & 0xff); i &= 0xffff; if (i != lval && pass == LAST_PASS) { error("Sync error"); return(-1); } } } return(0); } /* determine the value of the symbol, * given pointer to first character of symbol in symtab */ symval(ip) int *ip; { int ptr; int svalue; svalue = 0; colsym(ip); if ((ptr = stlook()) == -1) undef = 1; /* no room error */ else if (symtab[ptr + symtab[ptr] + 1] == UNDEF) undef = 1; else if (symtab[ptr + symtab[ptr] + 1] == UNDEFAB) undef = 1; else svalue = ((symtab[ptr + symtab[ptr] + 3] << 8) + (symtab[ptr + symtab[ptr] + 2] & 0xff)) & 0xffff; if (symtab[ptr + symtab[ptr] + 1] == DEFABS) zpref = 1; if (undef != 0) zpref = 1; return(svalue); } SHAR_EOF if test -f 'assm3.c' then echo shar: over-writing existing file "'assm3.c'" fi cat << \SHAR_EOF > 'assm3.c' #include "stdio.h" #include "assm.d1" #include "assm.d2" /* class 1 machine operations processor - 1 byte, no operand field */ class1() { if (pass == LAST_PASS) { loadlc(loccnt, 0, 1); loadv(opval, 0, 1); println(); } loccnt++; } /* class 2 machine operations processor - 2 byte, relative addressing */ class2(ip) int *ip; { if (pass == LAST_PASS) { loadlc(loccnt, 0, 1); loadv(opval, 0, 1); while (prlnbuf[++(*ip)] == ' '); if (evaluate(ip) != 0) { loccnt += 2; return; } loccnt += 2; if ((value -= loccnt) >= -128 && value < 128) { loadv(value, 1, 1); println(); } else error("Invalid branch address"); } else loccnt += 2; } /* class 3 machine operations processor - various addressing modes */ class3(ip) int *ip; { char ch; int code; int flag; int i; int ztmask; while ((ch = prlnbuf[++(*ip)]) == ' '); switch(ch) { case 0: case ';': error("Operand field missing"); return; case 'A': case 'a': if ((ch = prlnbuf[*ip + 1]) == ' ' || ch == 0) { flag = ACC; break; } default: switch(ch = prlnbuf[*ip]) { case '#': case '=': flag = IMM1 | IMM2; ++(*ip); break; case '(': flag = IND | INDX | INDY; ++(*ip); break; default: flag = ABS | ZER | ZERX | ABSX | ABSY | ABSY2 | ZERY; } if ((flag & (INDX | INDY | ZER | ZERX | ZERY) & opflg) != 0) udtype = UNDEFAB; if (evaluate(ip) != 0) return; if (zpref != 0) { flag &= (ABS | ABSX | ABSY | ABSY2 | IND | IMM1 | IMM2); ztmask = 0; } else ztmask = ZER | ZERX | ZERY; code = 0; i = 0; while (( ch = prlnbuf[(*ip)++]) != ' ' && ch != 0 && i++ < 4) { code *= 8; switch(ch) { case ')': /* ) = 4 */ ++code; case ',': /* , = 3 */ ++code; case 'X': /* X = 2 */ case 'x': ++code; case 'Y': /* Y = 1 */ case 'y': ++code; break; default: flag = 0; } } switch(code) { case 0: /* no termination characters */ flag &= (ABS | ZER | IMM1 | IMM2); break; case 4: /* termination = ) */ flag &= IND; break; case 25: /* termination = ,Y */ flag &= (ABSY | ABSY2 | ZERY); break; case 26: /* termination = ,X */ flag &= (ABSX | ZERX); break; case 212: /* termination = ,X) */ flag &= INDX; break; case 281: /* termination = ),Y */ flag &= INDY; break; default: flag = 0; } } if ((opflg &= flag) == 0) { error("Invalid addressing mode"); return; } if ((opflg & ztmask) != 0) opflg &= ztmask; switch(opflg) { case ACC: /* single byte - class 3 */ if (pass == LAST_PASS) { loadlc(loccnt, 0, 1); loadv(opval + 8, 0, 1); println(); } loccnt++; return; case ZERX: case ZERY: /* double byte - class 3 */ opval += 4; case INDY: opval += 8; case IMM2: opval += 4; case ZER: opval += 4; case INDX: case IMM1: if (pass == LAST_PASS) { loadlc(loccnt, 0, 1); loadv(opval, 0, 1); loadv(value, 1, 1); println(); } loccnt += 2; return; case IND: /* triple byte - class 3 */ opval += 16; case ABSX: case ABSY2: opval += 4; case ABSY: opval += 12; case ABS: if (pass == LAST_PASS) { opval += 12; loadlc(loccnt, 0, 1); loadv(opval, 0, 1); loadv(value, 1, 1); loadv(value >> 8, 2, 1); println(); } loccnt += 3; return; default: error("Invalid addressing mode"); return; } } /* pseudo operations processor */ pseudo(ip) int *ip; { int count; int i; int tvalue; switch(opval) { case 0: /* .byte pseudo */ labldef(loccnt); loadlc(loccnt, 0, 1); while (prlnbuf[++(*ip)] == ' '); /* field */ count = 0; do { if (prlnbuf[*ip] == '"') { while ((tvalue = prlnbuf[++(*ip)]) != '"') { if (tvalue == 0) { error("Unterminated ASCII string"); return; } if (tvalue == '\\') switch(tvalue = prlnbuf[++(*ip)]) { case 'n': tvalue = '\n'; break; case 't': tvalue = '\t'; break; } loccnt++; if (pass == LAST_PASS) { loadv(tvalue, count, 1); if (++count >= 3) { println(); for (i = 0; i < SFIELD; i++) prlnbuf[i] = ' '; prlnbuf[i] = 0; count = 0; loadlc(loccnt, 0, 1); } } } ++(*ip); } else { if (evaluate(ip) != 0) { loccnt++; return; } loccnt++; if (value > 0xff) { error("Operand field size error"); return; } else if (pass == LAST_PASS) { loadv(value, count, 1); if (++count >= 3) { println(); for (i = 0; i < SFIELD; i++) prlnbuf[i] = ' '; prlnbuf[i] = 0; count = 0; loadlc(loccnt, 0, 1); } } } } while (prlnbuf[(*ip)++] == ','); if ((pass == LAST_PASS) && (count != 0)) println(); return; case 1: /* = pseudo */ while (prlnbuf[++(*ip)] == ' '); if (evaluate(ip) != 0) return; labldef(value); if (pass == LAST_PASS) { loadlc(value, 1, 0); println(); } return; case 2: /* .word pseudo */ labldef(loccnt); loadlc(loccnt, 0, 1); while (prlnbuf[++(*ip)] == ' '); do { if (evaluate(ip) != 0) { loccnt += 2; return; } loccnt += 2; if (pass == LAST_PASS) { loadv(value, 0, 1); loadv(value>>8, 1, 1); println(); for (i = 0; i < SFIELD; i++) prlnbuf[i] = ' '; prlnbuf[i] = 0; loadlc(loccnt, 0, 1); } } while (prlnbuf[(*ip)++] == ','); return; case 3: /* *= pseudo */ while (prlnbuf[++(*ip)] == ' '); if (prlnbuf[*ip] == '*') { if (evaluate(ip) != 0) return; if (undef != 0) { error("Undefined symbol in operand field."); return; } tvalue = loccnt; } else { if (evaluate(ip) != 0) return; if (undef != 0) { error("Undefined symbol in operand field."); return; } tvalue = value; } loccnt = value; labldef(tvalue); if (pass == LAST_PASS) { objcnt = 0; loadlc(tvalue, 1, 0); println(); } return; case 4: /* .list pseudo */ if (lflag >= 0) lflag = 1; return; case 5: /* .nlst pseudo */ if (lflag >= 0) lflag = iflag; return; case 6: /* .dbyt pseudo */ labldef(loccnt); loadlc(loccnt, 0, 1); while (prlnbuf[++(*ip)] == ' '); do { if (evaluate(ip) != 0) { loccnt += 2; return; } loccnt += 2; if (pass == LAST_PASS) { loadv(value>>8, 0, 1); loadv(value, 1, 1); println(); for (i = 0; i < SFIELD; i++) prlnbuf[i] = ' '; prlnbuf[i] = 0; loadlc(loccnt, 0, 1); } } while (prlnbuf[(*ip)++] == ','); return; } } /* evaluate expression */ evaluate(ip) int *ip; { int tvalue; int invalid; int parflg, value2; char ch; char op; char op2; op = '+'; parflg = zpref = undef = value = invalid = 0; /* hcj: zpref should reflect the value of the expression, not the value of the intermediate symbols */ while ((ch=prlnbuf[*ip]) != ' ' && ch != ')' && ch != ',' && ch != ';') { tvalue = 0; if (ch == '$' || ch == '@' || ch == '%') tvalue = colnum(ip); else if (ch >= '0' && ch <= '9') tvalue = colnum(ip); else if (ch >= 'a' && ch <= 'z') tvalue = symval(ip); else if (ch >= 'A' && ch <= 'Z') tvalue = symval(ip); else if ((ch == '_') || (ch == '.')) tvalue = symval(ip); else if (ch == '*') { tvalue = loccnt; ++(*ip); } else if (ch == '\'') { ++(*ip); tvalue = prlnbuf[*ip] & 0xff; ++(*ip); } else if (ch == '[') { if (parflg == 1) { error("Too many ['s in expression"); invalid++; } else { value2 = value; op2 = op; value = tvalue = 0; op = '+'; parflg = 1; } goto next; } else if (ch == ']') { if (parflg == 0) { error("No matching [ for ] in expression"); invalid++; } else { parflg = 0; tvalue = value; value = value2; op = op2; } ++(*ip); } switch(op) { case '+': value += tvalue; break; case '-': value -= tvalue; break; case '/': value = (unsigned) value/tvalue; break; case '*': value *= tvalue; break; case '%': value = (unsigned) value%tvalue; break; case '^': value ^= tvalue; break; case '~': value = ~tvalue; break; case '&': value &= tvalue; break; case '|': value |= tvalue; break; case '>': tvalue >>= 8; /* fall through to '<' */ case '<': if (value != 0) { error("High or low byte operator not first in operand field"); } value = tvalue & 0xff; zpref = 0; break; default: invalid++; } if ((op=prlnbuf[*ip]) == ' ' || op == ')' || op == ',' || op == ';') break; else if (op != ']') next: ++(*ip); } if (parflg == 1) { error("Missing ] in expression"); return(1); } if (value < 0 || value >= 256) { zpref = 1; } if (undef != 0) { if (pass != FIRST_PASS) { error("Undefined symbol in operand field"); invalid++; } value = 0; } else if (invalid != 0) { error("Invalid operand field"); } else { /* This is the only way out that may not signal error */ if (value < 0 || value >= 256) { zpref = 1; } else { zpref = 0; } } return(invalid); } /* collect number operand */ colnum(ip) int *ip; { int mul; int nval; char ch; nval = 0; if ((ch = prlnbuf[*ip]) == '$') mul = 16; else if (ch >= '1' && ch <= '9') { mul = 10; nval = ch - '0'; } else if (ch == '@' || ch == '0') mul = 8; else if (ch == '%') mul = 2; while ((ch = prlnbuf[++(*ip)] - '0') >= 0) { if (ch > 9) { ch -= ('A' - '9' - 1); if (ch > 15) ch -= ('a' - 'A'); if (ch > 15) break; if (ch < 10) break; } if (ch >= mul) break; nval = (nval * mul) + ch; } return(nval); } SHAR_EOF # End of shell archive exit 0