mirror of
https://github.com/agn453/RSTS-E.git
synced 2026-01-11 23:22:42 +00:00
Include microcomputer cross-assemblers
This commit is contained in:
parent
a143648efd
commit
634765cfb3
4
.gitattributes
vendored
4
.gitattributes
vendored
@ -8,10 +8,14 @@ README.md text eol=crlf
|
||||
*.pat text eof=crlf linguist-language=DIGITAL Command Language
|
||||
*.txt text eof=crlf
|
||||
*.tsk binary
|
||||
*.TSK binary
|
||||
*.jpeg binary
|
||||
*.txt text eof=crlf
|
||||
*.mac text eol=crlf linguist-language=Assembly
|
||||
*.com text eol=crlf
|
||||
*.COM text eol=crlf
|
||||
*.HLP text eol=crlf
|
||||
*.B2S text eol=crlf linguist-language=BASIC
|
||||
*.obj binary
|
||||
*.zip binary
|
||||
*.pdf binary
|
||||
|
||||
39
README.md
39
README.md
@ -251,6 +251,45 @@ also has information about Forth's handling of program SCREENs and
|
||||
files.
|
||||
|
||||
|
||||
## Microcomputer cross-assemblers etc.
|
||||
|
||||
In the
|
||||
[micros](https://github.com/agn453/RSTS-E/blob/master/micros)
|
||||
subdirectory, I've added a few of the microcomputer cross-assemblers
|
||||
that I developed whilst an undergraduate. These were originally
|
||||
written in BASIC-PLUS - and the source files have been converted
|
||||
to a format now acceptable to both BASIC-PLUS and the PDP-11
|
||||
BASIC-PLUS-2 V2.7-00 compiler. (The original source files used
|
||||
continuation lines of a <LF> <CR> <NUL>, with <CR> <LF> at the
|
||||
end of each statement).
|
||||
|
||||
Cross-assemblers for
|
||||
|
||||
* National Semiconductor SC/MP
|
||||
[SCMPCA.B2S](https://github.com/agn453/RSTS-E/blob/master/micros/SCMPCA.B2S)
|
||||
|
||||
* Intel 8080/8085 with some Zilog Z80 op-codes (using Intel/TDL-style
|
||||
mnemonics)
|
||||
[X80.B2S](https://github.com/agn453/RSTS-E/blob/master/micros/X80.B2S)
|
||||
|
||||
* MOS Technology 6502
|
||||
[X65.B2S](https://github.com/agn453/RSTS-E/blob/master/micros/X65.B2S)
|
||||
|
||||
A dis-assembler for
|
||||
|
||||
* National Semiconductor SC/MP
|
||||
[DISASM.B2S](https://github.com/agn453/RSTS-E/blob/master/micros/DISASM.B2S)
|
||||
|
||||
and,
|
||||
|
||||
* A program to convert hexadecimal output from the cross-assembler
|
||||
to an Intel HEX format absolute loader format file
|
||||
[INTEL.B2S](https://github.com/agn453/RSTS-E/blob/master/micros/INTEL.B2S)
|
||||
|
||||
There are DCL command files to compile them, and I've included a binary
|
||||
task-image for each.
|
||||
|
||||
|
||||
## Background
|
||||
|
||||
I've been a User/Systems Programmer/System Manager/Computer Networking
|
||||
|
||||
13
micros/DISASB.COM
Normal file
13
micros/DISASB.COM
Normal file
@ -0,0 +1,13 @@
|
||||
$! Command file to build DISASM.B2S (with Basic-Plus-2)
|
||||
$!
|
||||
$ set noOn
|
||||
$ run $bp2ic2
|
||||
SCALE 0
|
||||
OLD DISASM.B2S
|
||||
COMPILE DISASM/OBJECT/CHAIN/NODEBUG/NOCROSS/NOLIST/NOWARN
|
||||
BUILD DISASM
|
||||
SCRATCH
|
||||
EXIT
|
||||
$ tkb @DISASM
|
||||
$ del disasm.odl, disasm.obj, disasm.cmd
|
||||
$ exit
|
||||
248
micros/DISASM.B2S
Normal file
248
micros/DISASM.B2S
Normal file
@ -0,0 +1,248 @@
|
||||
1010 REM &
|
||||
REM !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! &
|
||||
REM !! !! &
|
||||
REM !! SC/MP DIS ASSEMBLER !! &
|
||||
REM !! !!
|
||||
1020 REM !! A.G. NICHOLSON, NEWCASTLE UNI. !! &
|
||||
REM !! !! &
|
||||
REM !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! &
|
||||
|
||||
1030 REM ! LAST EDITED 13-MAY-77 ! &
|
||||
|
||||
1040 DIM O$(46%), O%(46%), X(3%), L(100%), C$(32%)
|
||||
1050 ! INITIALISE
|
||||
1060 D%,F%,N0%,T%=0% &
|
||||
\ P%=1%
|
||||
1070 L(0%)=-1%
|
||||
1080 U$=" #### \ \ \\ \\ \ \ \ \ \ \ "
|
||||
1090 H$="0123456789ABCDEF" &
|
||||
\ READ X(I%) FOR I%=0% TO 3%
|
||||
1100 DATA 1,16,256,4096
|
||||
1110 READ O$(I%), O%(I%) FOR I%=1% TO 46%
|
||||
1120 ! MEMORY REFERENCE INSTRUCTIONS 1-8
|
||||
1130 DATA LD,192,ST,200,AND,208,OR,216,XOR,224,DAD,232,ADD,240,CAD,248
|
||||
1140 ! TRANSFER INSTRUCTIONS 9-12
|
||||
1150 DATA JMP,144,JP,148,JZ,152,JNZ,156
|
||||
1160 ! MEMORY INCREMENT, DECREMENT INSTRUCTIONS 13-14
|
||||
1170 DATA ILD,168,DLD,184
|
||||
1180 ! IMMEDIATE INSTRUCTIONS 15-21
|
||||
1190 DATA LDI,196,ANI,212,ORI,220,XRI,228,DAI,236,ADI,244,CAI,252
|
||||
1200 ! DELAY INSTRUCTION 22
|
||||
1210 DATA DLY,143
|
||||
1220 ! POINTER MOVE INSTRUCTIONS 23-25
|
||||
1230 DATA XPAL,48,XPAH,52,XPPC,60
|
||||
1240 ! EXTENSION REGISTER INSTRUCTIONS 26-33
|
||||
1250 DATA LDE,64,XAE,1,ANE,80,ORE,88,XRE,96,DAE,104,ADE,112,CAE,120
|
||||
1260 ! SERIAL I/O, SHIFT & ROTATE INSTRUCTIONS 34-38
|
||||
1270 DATA SIO,25,SR,28,SRL,29,RR,30,RRL,31
|
||||
1280 ! MISCELLANEOUS INSTRUCTIONS 39-46
|
||||
1290 DATA HALT,0,CCL,2,SCL,3,IEN,5,DINT,4,CSA,6,CAS,7,NOP,8
|
||||
1300 MAT READ C$
|
||||
1310 ! ASCII CHARACTERS 0 TO 32
|
||||
1320 DATA NUL,SOH,STX,EXT,EOT,ENQ,ACK,BEL,BS,HT,LF,VT,FF,CR,SO,SI
|
||||
1330 DATA DEL,DC1,DC2,DC3,DC4,NAK,SYN,ETB,CAN,EM,SUB,ESC,FS,GS,RS,US
|
||||
1340 OPEN "KB:" AS FILE 1%
|
||||
1350 Z%=1% ! OUTPUT CHANNEL NUMBER
|
||||
1360 PRINT #1% &
|
||||
\ PRINT #1%,"SC/MP DIS-ASSEMBLER" &
|
||||
\ PRINT #1%
|
||||
1370 PRINT #1%,"#"; &
|
||||
\ INPUT LINE #1%,F$ &
|
||||
\ F$=CVT$$(F$,4%)
|
||||
1380 I%=INSTR(1%,F$,"<") OR INSTR(1%,F$,"=")
|
||||
1390 IF I% THEN X$=LEFT(F$,I%-1%) &
|
||||
\ OPEN X$ FOR OUTPUT AS FILE 3% &
|
||||
\ PRINT #1%," OUTPUT TO ";X$ &
|
||||
\ Z%=3% &
|
||||
\ F$=RIGHT(F$,I%+1%) &
|
||||
\ PRINT #1%
|
||||
1400 OPEN F$ FOR INPUT AS FILE 2% &
|
||||
\ PRINT #1%
|
||||
1410 PRINT #1%," STARTING ADDRESS (HEX) ?"; &
|
||||
\ INPUT #1%,A$ &
|
||||
\ N1=FND(A$) &
|
||||
\ PRINT #1%
|
||||
1420 ! PASS 1
|
||||
1430 PRINT #1%," PASS 1"
|
||||
1440 GOSUB 2240%
|
||||
1450 ! GET SINGLE BYTE PORTIONS AND DECODE
|
||||
1460 FOR J%=2% TO L% STEP 2%
|
||||
1470 B$=MID(L$,J%-1%,2%) &
|
||||
\ GOTO 1530% IF D% &
|
||||
\ GOTO 1630% IF B$="XX"
|
||||
1480 B%=FND(B$) &
|
||||
\ N0%=N0%+1%
|
||||
1490 GOTO 1610% IF B%<128%
|
||||
1500 ! TWO BYTE INSTRUCTIONS
|
||||
1510 IF J%=L% THEN D%=-1% &
|
||||
\ GOTO 1610%
|
||||
1520 J%=J%+2% &
|
||||
\ B$=MID(L$,J%-1%,2%)
|
||||
1530 IF B$="XX" THEN PRINT #1%, &
|
||||
"MISSING ARGUMENT AT LINE ";FNH$(N1+N0%);" (HEX)" &
|
||||
\ GOTO 1630%
|
||||
1540 D%=0% ! RESET CONTINUATION BYTE
|
||||
1550 N0%=N0%+1%
|
||||
1560 ! TEST FOR A TRANSFER INSTRUCTION
|
||||
1570 IF B%<144% OR B%>159% THEN B%=FND(B$) &
|
||||
\ GOTO 1610%
|
||||
1580 B%=FND(B$)
|
||||
1590 ! ENTER LINE NUMBER REFERENCED IN TABLE T()
|
||||
1600 B%=B%-256% IF B%>127% &
|
||||
\ GOTO 1610% IF L(I%)=N1+N0%+B%+1% FOR I%=0% TO T% &
|
||||
\ T%=T%+1% &
|
||||
\ L(T%)=N1+N0%+B%+1%
|
||||
1610 NEXT J% ! PROCESS NEXT CHARACTER
|
||||
1620 GOTO 1440%
|
||||
1630 ! END PASS 1
|
||||
1640 CLOSE 2%
|
||||
1650 D%,F%=0%
|
||||
1660 ! PASS 2
|
||||
1670 OPEN F$ FOR INPUT AS FILE 2% &
|
||||
\ PRINT #1%," PASS 2" &
|
||||
\ PRINT #1%
|
||||
1680 PRINT #Z%," ADDR B1 B2 LABEL OPCODE ARGUMENT "; &
|
||||
"[DECIMAL] <ASCII>" &
|
||||
\ PRINT #Z%
|
||||
1690 PRINT #Z%
|
||||
1700 P%=2% &
|
||||
\ N0%=0%
|
||||
1710 GOSUB 2240%
|
||||
1720 FOR J%=2% TO L% STEP 2%
|
||||
1730 B$=MID(L$,J%-1%,2%) &
|
||||
\ GOTO 1950% IF D% &
|
||||
\ B1$=B$ &
|
||||
\ GOTO 2210% IF B$="XX"
|
||||
1740 B%=FND(B$) &
|
||||
\ N0%=N0%+1%
|
||||
1750 S$,O$,A$=""
|
||||
1760 ! CHECK TO SEE WHETHER STATEMENT IS LABELED
|
||||
1770 S$="L"+CVT$$(NUM$(I%),2%)+":" IF L(I%)=N1+N0% FOR I%=0% TO T%
|
||||
1780 O%=B% &
|
||||
\ GOTO 2060% IF B%<128%
|
||||
1790 ! TWO BYTE INSTRUCTIONS
|
||||
1800 N1%=2% ! NUMBER OF BYTES
|
||||
1810 ! POINTER REFERENCE CHECK FOR TRANSFER, MEMORY INC/DEC
|
||||
1820 FOR I%=1% TO 3% &
|
||||
\ FOR K%=9% TO 14%
|
||||
1830 IF O%(K%)+I%=O% THEN A$=A$+"("+CVT$$(NUM$(I%),2%)+")" &
|
||||
\ O%=O%-I% &
|
||||
\ GOTO 1910%
|
||||
1840 NEXT K% &
|
||||
\ NEXT I%
|
||||
1850 ! AUTO INDEX AND POINTER CHECK FOR MEMORY REFERENCE
|
||||
1860 FOR K%=1% TO 8% &
|
||||
\ FOR I%=1% TO 3%
|
||||
1870 IF O%(K%)+4%+I%=O% THEN A$="@("+CVT$$(NUM$(I%),2%)+")" &
|
||||
\ O%=O%-4%-I% &
|
||||
\ GOTO 1910%
|
||||
1880 IF O%(K%)+I%=O% THEN A$="("+CVT$$(NUM$(I%),2%)+")" &
|
||||
\ O%=O%-I% &
|
||||
\ GOTO 1910%
|
||||
1890 NEXT I% &
|
||||
\ NEXT K%
|
||||
1900 ! FIND OPCODE FOR DOUBLE BYTE INSTRUCTION
|
||||
1910 O$=O$(I%) IF O%(I%)=O% FOR I%=1% TO 22%
|
||||
1920 ! GET SECOND BYTE
|
||||
1930 IF J%=L% THEN D%=-1% &
|
||||
\ GOTO 2180% ! SECOND BYTE ON NEXT PHYSICAL LINE IN FILE F$
|
||||
1940 J%=J%+2% &
|
||||
\ B$=MID(L$,J%-1%,2%)
|
||||
1950 GOTO 2210% IF B$="XX"
|
||||
1960 D%=0%
|
||||
1970 B2$=B$
|
||||
1980 N0%=N0%+1%
|
||||
1990 ! CHECK FOR TRANSFER INSTRUCTION
|
||||
2000 GOTO 2030% IF B%<144% OR B%>159%
|
||||
2010 ! ADD LABEL REFERENCED TO ARGUMENT
|
||||
2020 B%=FND(B$) &
|
||||
\ B%=B%-256% IF B%>127% &
|
||||
\ A$=A$+"L"+CVT$$(NUM$(I%),2%) IF L(I%)=N1+N0%+B%+1% FOR I%=0% TO T% &
|
||||
\ GOTO 2050%
|
||||
2030 A$=A$+"X'"+B2$
|
||||
2040 ! OUTPUT TO CHANNEL 1
|
||||
2050 GOSUB 2300% &
|
||||
\ GOTO 2180%
|
||||
2060 ! SINGLE BYTE INSTRUCTIONS
|
||||
2070 N1%=1% ! NUMBER OF BYTES
|
||||
2080 ! CHECK POINTER MOVE
|
||||
2090 FOR K%=23% TO 25% &
|
||||
\ FOR I%=0% TO 3%
|
||||
2100 IF O%(K%)+I%=O% THEN A$=CVT$$(NUM$(I%),2%) &
|
||||
\ O%=O%-I% &
|
||||
\ GOTO 2130%
|
||||
2110 NEXT I% &
|
||||
\ NEXT K%
|
||||
2120 ! SET OPCODE FOR SINGLE BYTE INSTRUCTION
|
||||
2130 O$=O$(I%) IF O%(I%)=O% FOR I%=23% TO 46%
|
||||
2140 IF O$="" THEN O$=".BYTE" \ A$="X'"+B1$
|
||||
2150 B2$=""
|
||||
2160 ! OUTPUT TO CHANNEL 1
|
||||
2170 GOSUB 2300%
|
||||
2180 NEXT J%
|
||||
2190 ! GET NEXT LINE FROM FILE F$
|
||||
2200 GOTO 1710%
|
||||
2210 ! EXIT
|
||||
2220 CLOSE 2% &
|
||||
\ PRINT #Z% FOR I%=1% TO 3% &
|
||||
\ CLOSE 1%,3%
|
||||
2230 GOTO 32767%
|
||||
2240 ! SUBROUTINE TO GET A LINE FROM FILE F$
|
||||
2250 INPUT LINE #2%,L$ &
|
||||
\ L$=CVT$$(L$,6%) &
|
||||
\ L%=LEN(L$) &
|
||||
\ GOTO 2250% IF L%=0%
|
||||
2260 ! F% IS THE NUMBER OF THE LINE READ FROM FILE F$
|
||||
2270 F%=F%+1%
|
||||
2280 IF (L%/2%)*2%<>L% THEN PRINT #1%, &
|
||||
"INCOMPLETE BYTE READ FROM ";F$;", LINE";F% &
|
||||
\ L$=L$+" "
|
||||
2290 RETURN
|
||||
2300 ! OUTPUT ROUTINE TO CHANNEL Z%
|
||||
2310 PRINT #Z% USING U$,N0%-N1%,FNH$(N1+N0%-N1%),B1$,B2$,S$,O$,A$;
|
||||
2320 ! LINE NUMBER, ADDR B1 B2 LABEL: OPCODE ARGUMENT
|
||||
2330 IF B2$="" THEN B$=B1$ ELSE B$=B2$ &
|
||||
\ B%=FND(B$)
|
||||
2340 IF B%<32% THEN C$=C$(B%+1%) ELSE IF B%<96% THEN C$=CHR$(B%)
|
||||
2350 B%=B%-256% IF B%>127%
|
||||
2360 PRINT #Z% USING "[ #### ]",B%;
|
||||
2370 IF C$<>"" THEN PRINT #Z% USING " < \ \ >",C$ ELSE PRINT #Z%
|
||||
2380 C$=""
|
||||
2390 RETURN
|
||||
2400 DEF* FNH$(X) ! HEXADECIMAL CONVERSION
|
||||
2410 X0=X &
|
||||
\ X0=X0+65536 IF X0<0% &
|
||||
\ X0=INT(X0+0.1) &
|
||||
\ GOTO 2440% IF X0>65536 &
|
||||
\ X$=""
|
||||
2420 FOR X%=3% TO 1% STEP -1% &
|
||||
\ X1=X(X%) &
|
||||
\ X2=INT(X0/X1) &
|
||||
\ X0=X0-X1*X2 &
|
||||
\ X2=X2+1% &
|
||||
\ X$=X$+MID(H$,X2,1%)
|
||||
2430 NEXT X% &
|
||||
\ FNH$=X$+MID(H$,X0+1%,1%) &
|
||||
\ GOTO 2450%
|
||||
2440 PRINT #1%,"OVERFLOW IN HEX CONVERSION" &
|
||||
\ E%=E%+1% &
|
||||
\ FNH$=" "
|
||||
2450 FNEND
|
||||
2460 DEF* FND(X$) ! HEX TO DECIMAL CONVERSION
|
||||
2470 X=LEN(X$) &
|
||||
\ X0=0% &
|
||||
\ GOTO 2500% IF X>4%
|
||||
2480 FOR X%=0% TO X-1% &
|
||||
\ X1$=MID(X$,X-X%,1%) &
|
||||
\ GOTO 2490% IF X1$=MID(H$,X1,1%) FOR X1=1% TO 16% &
|
||||
\ PRINT #1%,"ILLEGAL CHARACTER IN HEX NUMBER :";X$ &
|
||||
\ GOTO 2510%
|
||||
2490 X0=X0+(X1-1%)*X(X%) &
|
||||
\ NEXT X% &
|
||||
\ FND=X0 &
|
||||
\ GOTO 2520%
|
||||
2500 PRINT #1%,"OVERFLOW IN DECIMAL CONVERSION :"
|
||||
2510 E%=E%+1% &
|
||||
\ FND=0%
|
||||
2520 FNEND
|
||||
32767 END
|
||||
BIN
micros/DISASM.TSK
Normal file
BIN
micros/DISASM.TSK
Normal file
Binary file not shown.
53
micros/INTEL.B2S
Normal file
53
micros/INTEL.B2S
Normal file
@ -0,0 +1,53 @@
|
||||
10 ON ERROR GOTO 220
|
||||
15 PRINT "Hex dump to INTEL absolute load format"
|
||||
16 PRINT
|
||||
20 PRINT "Filename ";
|
||||
30 INPUT LINE F$
|
||||
40 OPEN F$ FOR INPUT AS FILE 1%
|
||||
50 PRINT "Output to ";
|
||||
60 INPUT LINE O$
|
||||
70 OPEN O$ FOR OUTPUT AS FILE 2%
|
||||
80 INPUT "Start address (hex) ";S$
|
||||
90 WHILE -1%
|
||||
100 INPUT #1%,L$
|
||||
111 N$=RIGHT(FNH$(LEN(L$)/2%),3%)
|
||||
112 N%=FND%(N$)
|
||||
113 C%=N%+FND%(LEFT(S$,2%))+FND%(RIGHT(S$,3%))
|
||||
120 PRINT #2%,":"+N$+S$+"00";
|
||||
150 FOR I%=1% TO 31% STEP 2%
|
||||
151 D$=MID(L$,I%,2%)
|
||||
152 D%=FND%(D$)
|
||||
153 C%=C%+D%
|
||||
160 PRINT #2%,D$;
|
||||
170 NEXT I%
|
||||
180 PRINT #2%,RIGHT(FNH$(-C%),3%)
|
||||
200 S$=FNH$(FND%(S$)+16%)
|
||||
210 NEXT
|
||||
220 PRINT #2%
|
||||
230 CLOSE 1%,2%
|
||||
240 PRINT
|
||||
250 PRINT "Done"
|
||||
260 GOTO 32767
|
||||
1000 DEF* FND%(X$)
|
||||
1010 X0%=0%
|
||||
1020 FOR X1%=1% TO LEN(X$)
|
||||
1030 X2%=ASCII(MID(X$,X1%,1%))
|
||||
1040 IF X2%<48% OR (X2%>57% AND X2%<65%) OR X2%>70% THEN &
|
||||
PRINT "Illegal hex character in "+X$ \ STOP
|
||||
1050 X2%=X2%-48%
|
||||
1060 X2%=X2%-7% IF X2%>9%
|
||||
1070 X0%=X2%+X0%*16%
|
||||
1080 NEXT X1%
|
||||
1090 FND%=X0%
|
||||
1100 FNEND
|
||||
2000 DEF* FNH$(X%)
|
||||
2010 X$=""
|
||||
2020 FOR X1%=0% TO 3%
|
||||
2030 X0%=(X% AND (16%^(X1%+1%)-1%*(16%^X1%)))/(16%^X1%)
|
||||
2040 X0%=X0%+16% IF X0%<0%
|
||||
2050 X$=CHR$(48%+X0%)+X$ IF X0%<10%
|
||||
2060 X$=CHR$(55%+X0%)+X$ IF X0%>9%
|
||||
2070 NEXT X1%
|
||||
2080 FNH$=X$
|
||||
2090 FNEND
|
||||
32767 END
|
||||
BIN
micros/INTEL.TSK
Normal file
BIN
micros/INTEL.TSK
Normal file
Binary file not shown.
13
micros/INTELB.COM
Normal file
13
micros/INTELB.COM
Normal file
@ -0,0 +1,13 @@
|
||||
$! Command file to build INTEL.B2S (with Basic-Plus-2)
|
||||
$!
|
||||
$ set noOn
|
||||
$ run $bp2ic2
|
||||
SCALE 0
|
||||
OLD INTEL.B2S
|
||||
COMPILE INTEL/OBJECT/CHAIN/NODEBUG/NOCROSS/NOLIST/NOWARN
|
||||
BUILD INTEL
|
||||
SCRATCH
|
||||
EXIT
|
||||
$ tkb @INTEL
|
||||
$ del intel.odl, intel.obj, intel.cmd
|
||||
$ exit
|
||||
13
micros/SCMBLD.COM
Normal file
13
micros/SCMBLD.COM
Normal file
@ -0,0 +1,13 @@
|
||||
$! Command file to build SCMPCA.B2S (with Basic-Plus-2)
|
||||
$!
|
||||
$ set noOn
|
||||
$ run $bp2ic2
|
||||
SCALE 0
|
||||
OLD SCMPCA.B2S
|
||||
COMPILE SCMPCA/OBJECT/CHAIN/NODEBUG/NOCROSS/NOLIST/NOWARN
|
||||
BUILD SCMPCA
|
||||
SCRATCH
|
||||
EXIT
|
||||
$ tkb @SCMPCA
|
||||
$ del scmpca.odl, scmpca.obj, scmpca.cmd
|
||||
$ exit
|
||||
549
micros/SCMPCA.B2S
Normal file
549
micros/SCMPCA.B2S
Normal file
@ -0,0 +1,549 @@
|
||||
1010 REM !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! &
|
||||
REM !! !! &
|
||||
REM !! SC/MP CROSS ASSEMBLER !! &
|
||||
REM !! !!
|
||||
1020 REM !! A.G. NICHOLSON, NEWCASTLE UNI. !! &
|
||||
REM !! !! &
|
||||
REM !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
1021 REM &
|
||||
REM ! Last edited: 30-Jan-79 &
|
||||
|
||||
1025 C9%=0%
|
||||
1030 DIM O$(51), O%(51), T$(255), T%(255), D%(3)
|
||||
1040 ! -- Set up error trap routine --
|
||||
1050 ON ERROR GOTO 31020 &
|
||||
\ X$=SYS(CHR$(6%)+CHR$(-7%))
|
||||
1060 ! -- Initialise --
|
||||
1070 N%=51% &
|
||||
\ T%(0%)=255% &
|
||||
\ T0%=TIME(1%) &
|
||||
\ F1$="KB:" &
|
||||
\ READ O$(I%), O%(I%) FOR I%=0% TO N%
|
||||
1080 ! -- Print header --
|
||||
1090 OPEN F1$ AS FILE 1% &
|
||||
\ GOTO 1130 IF C9% &
|
||||
\ PRINT #1%,"SC/MP Cross assembler" &
|
||||
\ PRINT #1%,"#";
|
||||
1100 ! -- Get listing, source filenames --
|
||||
1110 INPUT LINE #1%, F2$ &
|
||||
\ F2$=CVT$$(F2$,-1%)
|
||||
1120 ! -- Check for errors only switch --
|
||||
1130 F0%=-1% &
|
||||
\ L%=INSTR(1%,F2$,"/E") &
|
||||
\ IF L% THEN F2$=LEFT(F2$,L%-1%)+RIGHT(F2$,L%+2%) &
|
||||
\ F0%=0%
|
||||
1140 ! -- Check for object module output switch --
|
||||
1150 F4%=0% &
|
||||
\ L%=INSTR(1%,F2$,"/O") &
|
||||
\ IF L% THEN F2$=LEFT(F2$,L%-1%)+RIGHT(F2$,L%+2%) &
|
||||
\ F4%=-1%
|
||||
1160 ! -- Check for listing file and add default extensions --
|
||||
1170 F5%=INSTR(1%,F2$,"=") &
|
||||
\ IF F5% THEN F1$=LEFT(F2$,F5%-1%) &
|
||||
\ F1$=F1$+".LST" UNLESS INSTR(1%,F1$,".") &
|
||||
\ F2$=RIGHT(F2$,F5%+1%)
|
||||
1180 F2$=F2$+".SRC" UNLESS INSTR(1%,F2$,".")
|
||||
1190 PRINT #1%,"Listing sent to ";F1$ IF F5%
|
||||
1200 IF F4% THEN F4$=LEFT(F2$,INSTR(1%,F2$,"."))+"BIN" &
|
||||
\ PRINT #1%,"Object module to ";F4$
|
||||
1210 ! -- Get a unique workfile name --
|
||||
1220 W$="SCMP"+MID(NUM$(100%+ASCII(SYS(CHR$(6%)+CHR$(9%)))/2%),3%,2%)+".TMP"
|
||||
1230 ! -- Commence assembly --
|
||||
1240 GOSUB 1310 &
|
||||
\ GOSUB 1860 &
|
||||
\ X%=1% &
|
||||
\ GOSUB 2460
|
||||
1250 ! -- Print symbol table --
|
||||
1260 GOSUB 2480 IF T% AND F0% &
|
||||
\ PRINT #1%
|
||||
1270 ! -- Finish up and exit --
|
||||
1280 CLOSE 1 &
|
||||
\ IF F5% THEN X%=0% &
|
||||
\ GOSUB 2460
|
||||
1290 PRINT "Runtime was";(TIME(1%)-T0%)/10;"sec" &
|
||||
\ GOTO 32767
|
||||
1300 ! -- Pass 1 Driver routine --
|
||||
1310 E%,T%,N0%,N1%,F1%,O%=0% \ P0%=1% &
|
||||
\ OPEN F2$ FOR INPUT AS FILE 2% &
|
||||
\ PRINT #1% &
|
||||
\ OPEN W$ FOR OUTPUT AS FILE 3% &
|
||||
\ PRINT #1%,"Pass 1"
|
||||
1320 FOR L%=1% STEP 1% UNTIL O%=N% &
|
||||
\ INPUT LINE #2%, L$ &
|
||||
\ L$=CVT$$(L$,165%) &
|
||||
\ L1%=LEN(L$)
|
||||
1330 IF L1%=0% THEN O%=0% &
|
||||
\ GOTO 1450
|
||||
1340 ! -- Scan source line --
|
||||
1350 GOSUB 1470 &
|
||||
\ GOSUB 1520
|
||||
1360 ! -- Comment line ? --
|
||||
1370 IF D3%=1% THEN O%=0% &
|
||||
\ GOTO 1450
|
||||
1380 ! -- Get argument field --
|
||||
1390 IF D3% THEN A$=CVT$$(MID(L$,D2%+1%,D3%-D2%-1%),136%) &
|
||||
ELSE A$=CVT$$(RIGHT(L$,D2%+1%),8%)
|
||||
1400 ! -- Label ? --
|
||||
1410 IF D1% THEN S$=CVT$$(LEFT(L$,D1%-1%),128%) &
|
||||
\ S1%=N1% &
|
||||
\ GOSUB 1600
|
||||
1420 ! -- Assignment ? --
|
||||
1430 IF D4% THEN GOSUB 1650 &
|
||||
ELSE GOSUB 1690
|
||||
1440 ! -- Write to workfile --
|
||||
1450 GOSUB 1710 &
|
||||
\ NEXT L% &
|
||||
\ CLOSE 2,3 &
|
||||
\ RETURN
|
||||
1460 ! -- Scan for strings in L$, D%() is the delimiter table --
|
||||
1470 D%=-1% &
|
||||
\ S2%=0%
|
||||
1480 S1%=INSTR(S2%+1%,L$,"'") &
|
||||
\ RETURN UNLESS S1% &
|
||||
\ IF MID(L$,S1%-1%,1%)="X" THEN S2%=S1% &
|
||||
\ GOTO 1480
|
||||
1490 S2%=INSTR(S1%+1%,L$,"'") &
|
||||
\ IF S2% THEN D%=D%+1% &
|
||||
\ IF D%<4% THEN D%(D%)=SWAP%(S1% AND 255%) OR (S2% AND 255%) &
|
||||
\ GOTO 1480
|
||||
1500 RETURN
|
||||
1510 &
|
||||
! -- Search for token delimiters -- &
|
||||
! D1% Label &
|
||||
! D2% Opcode &
|
||||
! D3% Comment &
|
||||
! D4% Assignment
|
||||
1520 D1%=INSTR(1%,L$,":") &
|
||||
\ D1%=0% IF FNS%(D1%) &
|
||||
\ D3%=0%
|
||||
1530 D3%=INSTR(D3%+1%,L$,";") &
|
||||
\ GOTO 1530 IF FNS%(D3%) &
|
||||
\ D1%=0% IF (D1%>D3% AND D3%<>0%) &
|
||||
\ D2%=D1%
|
||||
1540 D2%=D2%+1% &
|
||||
\ IF D2%>=L1% THEN 1560 &
|
||||
ELSE X%=ASCII(RIGHT(L$,D2%)) &
|
||||
\ IF X%=9% OR X%=32% THEN 1540
|
||||
1550 D2%=D2%+1% &
|
||||
\ IF D2%<L1% THEN X%=ASCII(RIGHT(L$,D2%)) &
|
||||
\ IF X%<>9% AND X%<>32% THEN 1550 &
|
||||
ELSE D2%=D2%-1%
|
||||
1560 D4%=INSTR(1%,L$,"=") &
|
||||
\ D4%=0% IF FNS%(D4%) OR (D4%>D3% AND D3%<>0%) &
|
||||
\ D2%=D4% IF D4%
|
||||
1570 D2%=D3%-1% IF (D2%>=D3% AND D3%<>0%) &
|
||||
\ RETURN
|
||||
1590 &
|
||||
! Enter symbol S$ and its value S1% into T$() and T%() &
|
||||
|
||||
1600 X%=ASCII(S$) &
|
||||
\ IF X%<65% OR X%>90% OR LEN(S$)>6% THEN &
|
||||
X%=FNE%("Inv sym "+S$) &
|
||||
\ RETURN
|
||||
1610 FOR I%=1% TO T% &
|
||||
\ IF S$=T$(I%) THEN S1%=FNE%("Redef sym "+S$) &
|
||||
\ RETURN
|
||||
1620 NEXT I% &
|
||||
\ IF T%=T%(0%) THEN PRINT #1%,"Sym ovf" &
|
||||
\ RETURN
|
||||
1630 T%=T%+1% &
|
||||
\ T$(T%)=S$ &
|
||||
\ T%(T%)=S1% &
|
||||
\ RETURN
|
||||
1640 ! -- Enter assignment --
|
||||
1650 S$=CVT$$(MID(L$,D1%+1%,D4%-D1%-1%),136%) &
|
||||
\ S1%=FNA%(A$)
|
||||
1660 IF S$="." THEN N1%=S1% &
|
||||
ELSE IF S$<>"" THEN GOSUB 1600 &
|
||||
ELSE S1%=FNE%("Missing symbol")
|
||||
1670 O%=0% &
|
||||
\ RETURN
|
||||
1680 ! -- Get opcode subscript --
|
||||
1690 X1$=CVT$$(MID(L$,D1%+1%,D2%-D1%),8%) &
|
||||
\ RETURN IF X1$=O$(O%) FOR O%=0% TO N% &
|
||||
\ O%=FNE%("Inv opc "+X1$) &
|
||||
\ RETURN
|
||||
1700 ! -- Get byte count and output to workfile --
|
||||
1710 IF O%>46% THEN GOSUB 1770 &
|
||||
ELSE IF O%>22% THEN N2%=1% &
|
||||
ELSE IF O%>0% THEN N2%=2% &
|
||||
ELSE N2%=0%
|
||||
1720 PRINT #3%,N1%;",";N2%;",";O%;",";F1% &
|
||||
\ PRINT #3%,A$ &
|
||||
\ N0%=N0%+N2% &
|
||||
\ N1%=N1%+N2% &
|
||||
\ F1%=0% &
|
||||
\ RETURN
|
||||
1760 ! -- Get byte count for pseudo-op --
|
||||
1770 ON O%-46% GOTO 1790, 1790, 1810, 1840, 1840
|
||||
1780 ! -- .BYTE, .DBYTE --
|
||||
1790 S1%=0% \ S2%=-1% &
|
||||
\ FOR N2%=0% WHILE S2% &
|
||||
\ S1%, S2%=INSTR(S1%+1%,A$,",") &
|
||||
\ NEXT N2% &
|
||||
\ N2%=N2%*2% IF O%=48% &
|
||||
\ RETURN
|
||||
1800 ! -- .ASCII --
|
||||
1810 S1%=INSTR(2%,A$,LEFT(A$,1%)) &
|
||||
\ IF S1% THEN N2%=S1%-2% &
|
||||
\ RETURN
|
||||
1820 O%=FNE%("Missing delim") &
|
||||
\ RETURN
|
||||
1830 ! -- .LIST, END --
|
||||
1840 N2%=0% &
|
||||
\ RETURN
|
||||
1850 ! -- Pass 2 Driver routine --
|
||||
1860 L%,C%,F2%=0% &
|
||||
\ P0%=2% &
|
||||
\ F3%=-1% &
|
||||
\ PRINT #1%,"Pass 2" &
|
||||
\ CLOSE 1 &
|
||||
\ OPEN F1$ FOR OUTPUT AS FILE 1% &
|
||||
\ OPEN F2$ FOR INPUT AS FILE 2% &
|
||||
\ OPEN W$ FOR INPUT AS FILE 3%
|
||||
1870 ! -- If object out then output leader and <stx> and byte count --
|
||||
1880 IF F4% THEN OPEN F4$ FOR OUTPUT AS FILE 4% &
|
||||
\ GOSUB 2350 &
|
||||
\ B%=2% &
|
||||
\ GOSUB 2440 &
|
||||
\ B%=SWAP%(N0%) AND 255% &
|
||||
\ GOSUB 2440 &
|
||||
\ B%=N0% AND 255% &
|
||||
\ GOSUB 2440
|
||||
1890 IF F0% THEN PRINT #1% &
|
||||
\ PRINT #1%," Line Addr B1 B2" &
|
||||
\ PRINT #1%
|
||||
1900 INPUT #3%,N1%,N2%,O%,F1% &
|
||||
\ INPUT LINE #3%, A$ &
|
||||
\ A$=CVT$$(A$,4%) &
|
||||
\ INPUT LINE #2%, L$ &
|
||||
\ L$=CVT$$(L$,4%) &
|
||||
\ L%=L%+1%
|
||||
1910 ! -- Form object code and output to listing file --
|
||||
1920 IF O%=N% THEN GOSUB 1980 &
|
||||
\ RETURN
|
||||
1930 IF O%=0% THEN GOSUB 2370 &
|
||||
\ GOTO 1900
|
||||
1940 O1$=FNH$(N1%,0%) &
|
||||
\ V%=O%(O%)
|
||||
1950 IF O%>46% THEN GOSUB 2140 &
|
||||
ELSE IF O%>25% THEN GOSUB 2120 &
|
||||
ELSE IF O%>22% THEN GOSUB 2100 &
|
||||
ELSE IF O%>14% THEN GOSUB 2080 &
|
||||
ELSE IF O%>8% THEN GOSUB 2030 &
|
||||
ELSE GOSUB 2010
|
||||
1960 GOTO 1900
|
||||
1970 ! -- End of assembly, tidy up --
|
||||
1980 GOSUB 2370 &
|
||||
\ IF F4% THEN B%=2% &
|
||||
\ GOSUB 2440 &
|
||||
\ B%=C% AND 255% &
|
||||
\ GOSUB 2440 &
|
||||
\ GOSUB 2350
|
||||
1990 CLOSE 2,3,4 &
|
||||
\ KILL W$ &
|
||||
\ RETURN
|
||||
2000 ! -- Memory reference --
|
||||
2010 S1%=INSTR(1%,A$,"@") &
|
||||
\ IF S1% THEN V%=V%+4% &
|
||||
\ A$=LEFT(A$,S1%-1%)+RIGHT(A$,S1%+1%)
|
||||
2020 ! -- Memory reference, inc, dec and transfer --
|
||||
2030 GOSUB 2290 &
|
||||
\ V%=V%+P% &
|
||||
\ GOSUB 2250
|
||||
2040 V%=FNA%(A$) &
|
||||
\ IF P%=0% THEN V%=V%-N1%-1% &
|
||||
\ IF O%>8% AND O%<13% THEN V%=V%-1%
|
||||
2041 ! Quirk for wrap around within 4K page - fixed 09-Oct-2018
|
||||
2042 IF V%>(4096%-127%) THEN V%=V%-4096%
|
||||
2050 IF V%<-128% OR V%>127% THEN V%=FNE%("Inv disp ="+NUM$(V%))
|
||||
2060 GOSUB 2270 &
|
||||
\ GOSUB 2370 &
|
||||
\ RETURN
|
||||
2070 ! -- Immediate and Delay --
|
||||
2080 GOSUB 2250 &
|
||||
\ V%=FNA%(A$) &
|
||||
\ GOSUB 2270 &
|
||||
\ GOSUB 2370 &
|
||||
\ RETURN
|
||||
2090 ! -- Pointer exchange --
|
||||
2100 GOSUB 2290 &
|
||||
\ P%=FNA%(A$) UNLESS P% &
|
||||
\ V%=V%+P%
|
||||
2110 ! -- Single byte --
|
||||
2120 GOSUB 2250 &
|
||||
\ GOSUB 2370 &
|
||||
\ RETURN
|
||||
2130 ! -- Pseudo-ops. --
|
||||
2140 ON O%-46% GOTO 2160, 2160, 2210, 2230
|
||||
2150 ! -- .BYTE, .DBYTE --
|
||||
2160 A$=A$+"," &
|
||||
\ FOR I%=1% TO N2% STEP O%-46% &
|
||||
\ O1$=FNH$(N1%+I%-1%,0%) &
|
||||
\ S1%=INSTR(1%,A$,",")
|
||||
2170 S2%=FNA%(LEFT(A$,S1%-1%)) &
|
||||
\ IF O%=48% THEN V%=SWAP%(S2%) &
|
||||
\ GOSUB 2250 &
|
||||
\ V%=S2% &
|
||||
\ GOSUB 2270
|
||||
2180 IF O%=47% THEN V%=S2% &
|
||||
\ GOSUB 2250
|
||||
2190 GOSUB 2370 &
|
||||
\ A$=RIGHT(A$,S1%+1%) &
|
||||
\ NEXT I% &
|
||||
\ RETURN
|
||||
2200 ! -- .ASCII --
|
||||
2210 A$=MID(A$,2%,N2%) &
|
||||
\ FOR I%=1% TO N2% &
|
||||
\ O1$=FNH$(N1%+I%-1%,0%) &
|
||||
\ V%=ASCII(RIGHT(A$,I%)) &
|
||||
\ GOSUB 2250 &
|
||||
\ GOSUB 2370 &
|
||||
\ NEXT I% &
|
||||
\ RETURN
|
||||
2220 ! -- .LIST --
|
||||
2230 F3%=FNA%(A$) &
|
||||
\ RETURN
|
||||
2240 ! -- Form B1 and update checksum --
|
||||
2250 O2$=FNH$(V%,3%) &
|
||||
\ B%=V% AND 255% &
|
||||
\ GOSUB 2440 IF F4% &
|
||||
\ C%=C%+B% &
|
||||
\ RETURN
|
||||
2260 ! -- Form B2 and update checksum --
|
||||
2270 O3$=FNH$(V%,3%) &
|
||||
\ B%=V% AND 255% &
|
||||
\ GOSUB 2440 IF F4% &
|
||||
\ C%=C%+B% &
|
||||
\ RETURN
|
||||
2280 ! -- Extract pointer from argument --
|
||||
2290 P%, S1%=0%
|
||||
2300 S1%=INSTR(S1%+1%,A$,"(") &
|
||||
\ RETURN UNLESS S1% &
|
||||
\ X$=LEFT(A$,S1%-1%) &
|
||||
\ GOTO 2300 IF X$="H" OR X$="L"
|
||||
2310 S2%=INSTR(S1%+1%,A$,")") &
|
||||
\ P%=FNA%(MID(A$,S1%+1%,S2%-S1%-1%)) &
|
||||
\ A$=LEFT(A$,S1%-1%)+RIGHT(A$,S2%+1%)
|
||||
2320 IF P%<0% OR P%>3% THEN P%=FNE%("Inv ptr ="+NUM$(P%))
|
||||
2330 RETURN
|
||||
2340 ! -- Output a leader to object file --
|
||||
2350 PRINT #4%,STRING$(80%,0%); &
|
||||
\ RETURN
|
||||
2360 ! -- Output assembled code to listing file --
|
||||
2370 GOTO 2420 UNLESS F0% OR F1%
|
||||
2380 IF F1% THEN PRINT #1%,"?"; ELSE PRINT #1%," ";
|
||||
2390 IF F2%<L% THEN PRINT #1% USING "#### ",L%; ELSE PRINT #1%," ";
|
||||
2400 PRINT #1% USING"\ \ \\ \\",O1$,O2$,O3$; &
|
||||
\ IF F3% AND L$<>"" THEN PRINT #1%,CHR$(9%);L$ &
|
||||
ELSE PRINT #1%
|
||||
2410 ! -- Set a flag, clear output strings --
|
||||
2420 F2%=L% &
|
||||
\ O1$,O2$,O3$,L$="" &
|
||||
\ RETURN
|
||||
2430 ! -- Output binary byte to object file --
|
||||
2440 PRINT #4%,CHR$(B%); &
|
||||
\ RETURN
|
||||
2450 ! -- Print error count, checksum --
|
||||
2460 PRINT #X% &
|
||||
\ PRINT #X%,"Errors detected";E% &
|
||||
\ PRINT #X%,"Source checksum ";FNH$(C%,0%) &
|
||||
\ PRINT #X%,"Total bytes ";N0% &
|
||||
\ PRINT #X% &
|
||||
\ RETURN
|
||||
2470 ! -- Print sorted symbol table --
|
||||
2480 PRINT #1%," Symbol Table" &
|
||||
\ PRINT #1%
|
||||
2490 ! -- Bubble sort symbol table --
|
||||
2500 S2%=-1% &
|
||||
\ FOR S1%=T%-1% STEP -1% WHILE S2% &
|
||||
\ S2%=0% &
|
||||
\ FOR I%=1% TO S1%
|
||||
2510 IF T$(I%+1%)<T$(I%) THEN S$=T$(I%) &
|
||||
\ X%=T%(I%) &
|
||||
\ T$(I%)=T$(I%+1%) &
|
||||
\ T%(I%)=T%(I%+1%) &
|
||||
\ T$(I%+1%)=S$ &
|
||||
\ T%(I%+1%)=X% &
|
||||
\ S2%=S2%+1%
|
||||
2520 NEXT I% &
|
||||
\ NEXT S1%
|
||||
2530 ! -- Output to listing file --
|
||||
2540 FOR I%=1% TO T% &
|
||||
\ PRINT #1% USING " \ \ \ \ ",T$(I%),FNH$(T%(I%),0%); &
|
||||
\ PRINT #1% IF CCPOS(1%)>63% &
|
||||
\ NEXT I%
|
||||
2550 PRINT #1% IF CCPOS(1%) &
|
||||
\ RETURN
|
||||
2560 &
|
||||
! -- Check position of char X% in L$ using -- &
|
||||
! -- tables D%(). FNS%=-1% means in string --
|
||||
2570 DEF* FNS%(X%)
|
||||
2580 GOTO 2600 IF D%=-1% OR X%=0% &
|
||||
\ FOR X0%=0% TO D% &
|
||||
\ GOTO 2600 IF X%<(SWAP%(D%(X0%)) AND 255%) &
|
||||
\ IF X%<(D%(X0%) AND 255%) THEN FNS%=-1% &
|
||||
\ GOTO 2610
|
||||
2590 NEXT X0%
|
||||
2600 FNS%=0%
|
||||
2610 FNEND
|
||||
2620 ! -- Evaluate the argument expression --
|
||||
2630 DEF* FNA%(X$)
|
||||
2640 ! -- Main driver routine --
|
||||
2650 X3$=CVT$$(X$,136%) &
|
||||
\ GOSUB 2680 &
|
||||
\ GOSUB 2710 &
|
||||
\ X3%=X0%
|
||||
2660 GOTO 2890 UNLESS X5% &
|
||||
\ X7%=X5% &
|
||||
\ GOSUB 2680 &
|
||||
\ GOSUB 2710 &
|
||||
\ GOSUB 2840 &
|
||||
\ GOTO 2660
|
||||
2670 REM ! -- Scan for the next operator { ! & % + * - / } --
|
||||
2680 IF X3$="" THEN X5%,X4%=0% &
|
||||
\ RETURN
|
||||
2690 X9%=-1% &
|
||||
\ FOR X4%=1% TO LEN(X3$) &
|
||||
\ X5%=ASCII(RIGHT(X3$,X4%)) &
|
||||
\ X9%= NOT X9% IF X5%=39% &
|
||||
\ RETURN IF X9% AND ( X5%=33% OR X5%=37% OR X5%=38% &
|
||||
OR X5%=42% OR X5%=43% OR X5%=45% OR X5%=47%) &
|
||||
\ NEXT X4% &
|
||||
\ X5%=0% &
|
||||
\ X4%=X4%+1% &
|
||||
\ RETURN
|
||||
2700 ! -- Get value of term --
|
||||
2710 X2$=CVT$$(LEFT(X3$,X4%-1%),136%) &
|
||||
\ X3$=RIGHT(X3$,X4%+1%)
|
||||
2720 IF X2$="" THEN X0%=0% &
|
||||
\ RETURN
|
||||
2730 ! -- H() or L() ? --
|
||||
2740 X1$=LEFT(X2$,2%) &
|
||||
\ IF X1$="H(" THEN X9%=1% &
|
||||
ELSE IF X1$="L(" THEN X9%=2% &
|
||||
ELSE X9%=0%
|
||||
2750 IF X9% THEN IF RIGHT(X2$,LEN(X2$))=")" THEN X2$=MID(X2$,3%,LEN(X2$)-3%) &
|
||||
ELSE 2820
|
||||
2760 ! -- Hex or Dec number ? -- &
|
||||
! -- Ascii character ? -- &
|
||||
! -- Current LC (".") ? -- &
|
||||
! -- or Symbol ? -- &
|
||||
|
||||
2770 IF X1$="X'" THEN X0%=FND%(RIGHT(X2$,3%)) &
|
||||
\ GOTO 2800
|
||||
2780 X1$=LEFT(X2$,1%)
|
||||
2790 IF X1$="0" THEN X0%=FND%(RIGHT(X2$,2%)) &
|
||||
ELSE IF X1$>="1" AND X1$<="9" THEN X0%=VAL(X2$) &
|
||||
ELSE IF X1$>="A" AND X1$<="Z" THEN X0%=FNV%(X2$) &
|
||||
ELSE IF X1$="'" THEN X0%=ASCII(RIGHT(X2$,2%)) &
|
||||
ELSE IF X2$="." THEN X0%=N1% &
|
||||
ELSE 2820
|
||||
2800 IF X9%=1% THEN X0%=SWAP%(X0%) AND 255% &
|
||||
ELSE IF X9%=2% THEN X0%=X0% AND 255%
|
||||
2810 RETURN
|
||||
2820 X0%=FNE%("Inv term = "+X2$) &
|
||||
\ RETURN
|
||||
2830 ! -- Carry out the arithmetic or logical operation --
|
||||
2840 IF X7%>38% THEN 2860 &
|
||||
ELSE IF X7%=33% THEN X3%=X3% OR X0% &
|
||||
ELSE IF X7%=37% THEN X3%=X3%+(NOT X0%) &
|
||||
ELSE IF X7%=38% THEN X3%=X3% AND X0%
|
||||
2850 RETURN
|
||||
2860 IF X7%=42% THEN X3%=X3%*X0% &
|
||||
ELSE IF X7%=43% THEN X3%=X3%+X0% &
|
||||
ELSE IF X7%=45% THEN X3%=X3%-X0% &
|
||||
ELSE IF X7%=47% THEN X3%=X3%/X0%
|
||||
2870 RETURN
|
||||
2880 ! -- Exit with value of expression --
|
||||
2890 FNA%=X3%
|
||||
2900 FNEND
|
||||
2905 ! -- Print the given error message to the listing file
|
||||
2906 DEF* FNE%(X$) &
|
||||
\ PRINT #1%,X$; &
|
||||
\ IF P0%=1% THEN PRINT #1%," at line";L% ELSE PRINT #1%
|
||||
2907 E%=E%+1% &
|
||||
\ F1%=-1% &
|
||||
\ FNE%=0% &
|
||||
\ FNEND
|
||||
2910 ! -- Look up value of symbol --
|
||||
2920 DEF* FNV%(X$)
|
||||
2930 GOTO 2940 IF X$=T$(X%) FOR X%=1% TO T% &
|
||||
\ FNV%=FNE%("Undef sym = "+X$) &
|
||||
\ GOTO 2950
|
||||
2940 FNV%=T%(X%)
|
||||
2950 FNEND
|
||||
2960 ! -- Dec to Hex conversion --
|
||||
2970 DEF* FNH$(X%,D%)
|
||||
2980 X$="" &
|
||||
\ FOR X1%=0% TO 3% &
|
||||
\ X0%=(X% AND (16%^(X1%+1%)-1%*(16%^X1%)))/(16%^X1%) &
|
||||
\ X0%=X0%+16% IF X0%<0% &
|
||||
\ X$=CHR$(48%+X0%)+X$ IF X0%<10% &
|
||||
\ X$=CHR$(55%+X0%)+X$ IF X0%>9% &
|
||||
\ NEXT X1% &
|
||||
\ IF D% THEN X$=MID(X$,D%,2%)
|
||||
2990 FNH$=X$
|
||||
3000 FNEND
|
||||
3010 ! -- Hex to Dec conversion --
|
||||
3020 DEF* FND%(X$) &
|
||||
\ X0%=0% &
|
||||
\ FOR X1%=1% TO LEN(X$) &
|
||||
\ X2%=ASCII(MID(X$,X1%,1%)) &
|
||||
\ IF X2%<48% OR (X2%>57% AND X2%<65%) OR X2%>70% THEN &
|
||||
FND%=FNE%("Inv Hex const = "+X$) &
|
||||
\ GOTO 3040
|
||||
3030 X2%=X2%-48% &
|
||||
\ X2%=X2%-7% IF X2%>9% &
|
||||
\ X0%=X2%+X0%*16% &
|
||||
\ NEXT X1% &
|
||||
\ FND%=X0%
|
||||
3040 FNEND
|
||||
30000 ! CCL Entry point
|
||||
30010 F2$=CVT$$(SYS(CHR$(7%)),188%) &
|
||||
\ I%=INSTR(1%,F2$,"SCMPCA") &
|
||||
\ IF I% THEN F2$=RIGHT(F2$,7%) &
|
||||
ELSE PRINT "?SCMPCA - Illegal entry" &
|
||||
\ GOTO 32767
|
||||
30020 C9%=-1% &
|
||||
\ GOTO 1050
|
||||
31000 ! -- Error routine --
|
||||
31010 ! -- No "END" --
|
||||
31020 IF ERR=11% AND ERL=1320% THEN O%=N%+FNE%("Missing END") &
|
||||
\ RESUME 1450
|
||||
31030 IF ERR=11% AND ERL=1900% THEN L$="" &
|
||||
\ RESUME 1920
|
||||
31040 ! -- ^Z at filename request --
|
||||
31050 RESUME 32767 IF ERL=1110%
|
||||
31060 ! -- Illegal number in FNA%() --
|
||||
31070 IF ERR=51% AND ERL=2790% THEN X0%=VAL(X2$)-65536 &
|
||||
\ RESUME 2800
|
||||
31080 RESUME 2820 IF ERR=52% AND ERL=2790%
|
||||
31090 CLOSE 1,2,3 &
|
||||
\ KILL W$ IF LINE>=1310% &
|
||||
\ RESUME 32767 IF ERR=28%
|
||||
31100 ! -- Print any unanticipated error --
|
||||
31110 ON ERROR GOTO 0
|
||||
32000 ! -- Opcode data --
|
||||
32010 DATA "",0
|
||||
32020 ! Memory reference 1-8
|
||||
32030 DATA LD,192,ST,200,AND,208,OR,216,XOR,224,DAD,232,ADD,240,CAD,248
|
||||
32040 ! Transfer 9-12
|
||||
32050 DATA JMP,144,JP,148,JZ,152,JNZ,156
|
||||
32060 ! Memory inc,dec 13-14
|
||||
32070 DATA ILD,168,DLD,184
|
||||
32080 ! Immediate 15-21
|
||||
32090 DATA LDI,196,ANI,212,ORI,220,XRI,228,DAI,236,ADI,244,CAI,252
|
||||
32100 ! Delay 22
|
||||
32110 DATA DLY,143
|
||||
32120 ! Pointer 23-25
|
||||
32130 DATA XPAL,48,XPAH,52,XPPC,60
|
||||
32140 ! Extension 26-33
|
||||
32150 DATA LDE,64,XAE,1,ANE,80,ORE,88,XRE,96,DAE,104,ADE,112,CAE,120
|
||||
32160 ! SIO, Shift, Rotate 34-38
|
||||
32170 DATA SIO,25,SR,28,SRL,29,RR,30,RRL,31
|
||||
32180 ! Miscellaneous 39-46
|
||||
32190 DATA HALT,0,CCL,2,SCL,3,IEN,5,DINT,4,CSA,6,CAS,7,NOP,8
|
||||
32200 ! Assembler pseudo-ops 47-51
|
||||
32210 DATA .BYTE,0,.DBYTE,0,.ASCII,0,.LIST,0,END,0
|
||||
32767 END
|
||||
BIN
micros/SCMPCA.TSK
Normal file
BIN
micros/SCMPCA.TSK
Normal file
Binary file not shown.
987
micros/X65.B2S
Normal file
987
micros/X65.B2S
Normal file
@ -0,0 +1,987 @@
|
||||
1000 REM &
|
||||
REM !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! &
|
||||
REM !! !! &
|
||||
REM !! 6502 Cross Assembler !! &
|
||||
REM !! !!
|
||||
1010 REM !! A.G. Nicholson, Newcastle Uni . !! &
|
||||
REM !! !! &
|
||||
REM !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! &
|
||||
|
||||
1020 REM &
|
||||
REM ! Version of 26-Nov-79 &
|
||||
|
||||
1030 EXTEND
|
||||
1040 DIM SYMBOLS$(767%), &
|
||||
VALUES%(767%), &
|
||||
FLAGS%(767%), &
|
||||
SYMBOL.CHARS%(6%), &
|
||||
DELIMITER.TABLE%(3%)
|
||||
1050 ! -- Set up error trap routine --
|
||||
1060 ON ERROR GOTO 31020 &
|
||||
\ X$=SYS(CHR$(6%)+CHR$(-7%))
|
||||
1070 ! -- Initialise --
|
||||
1080 NUMBER.OF.SYMBOLS%=0% &
|
||||
\ SYMBOL.TABLE.SIZE%=768% &
|
||||
\ START.CPU.TIME%=TIME(1%) &
|
||||
\ LISTING.FILE$="KB:"
|
||||
1090 FOR I%=1% TO 65% &
|
||||
\ READ SYMBOL$,VALUE%,FLAG.WORD% &
|
||||
\ GOSUB 2490 &
|
||||
\ NEXT I% &
|
||||
! Read in opcodes
|
||||
1100 ! -- Print header --
|
||||
1110 OPEN LISTING.FILE$ AS FILE 1% &
|
||||
\ PRINT #1%,"6502 Cross assembler" &
|
||||
\ PRINT #1%,"#";
|
||||
1120 ! &
|
||||
|
||||
1130 ! -- Get listing, source filenames --
|
||||
1140 INPUT LINE #1%, SOURCE.FILE$ &
|
||||
\ SOURCE.FILE$=CVT$$(SOURCE.FILE$,-1%)
|
||||
1150 ! -- Check for errors only switch --
|
||||
1160 ERRORS.ONLY.SWITCH%=-1% &
|
||||
\ I%=INSTR(1%,SOURCE.FILE$,"/E") &
|
||||
\ IF I% THEN SOURCE.FILE$=LEFT(SOURCE.FILE$,I%-1%)+ &
|
||||
RIGHT(SOURCE.FILE$,I%+2%) &
|
||||
\ ERRORS.ONLY.SWITCH%=0%
|
||||
1170 ! -- Check for symbol table listing switch --
|
||||
1180 SYMBOL.TABLE.LIST.FLAG%=INSTR(1%,SOURCE.FILE$,"/S") &
|
||||
\ IF SYMBOL.TABLE.LIST.FLAG% THEN SOURCE.FILE$= &
|
||||
LEFT(SOURCE.FILE$,SYMBOL.TABLE.LIST.FLAG%-1%)+ &
|
||||
RIGHT(SOURCE.FILE$,SYMBOL.TABLE.LIST.FLAG%+2%)
|
||||
1190 ! -- Check for object module output switch --
|
||||
1200 OBJECT.OUT.FLAG%=0% &
|
||||
\ I%=INSTR(1%,SOURCE.FILE$,"/O") &
|
||||
\ IF I% THEN SOURCE.FILE$=LEFT(SOURCE.FILE$,I%-1%)+ &
|
||||
RIGHT(SOURCE.FILE$,I%+2%) &
|
||||
\ OBJECT.OUT.FLAG%=-1%
|
||||
1210 ! -- Check for listing file and add default extensions --
|
||||
1220 LISTING.TO.FILE.FLAG%=INSTR(1%,SOURCE.FILE$,"=") &
|
||||
\ IF LISTING.TO.FILE.FLAG% THEN LISTING.FILE$= &
|
||||
LEFT(SOURCE.FILE$,LISTING.TO.FILE.FLAG%-1%) &
|
||||
\ LISTING.FILE$=LISTING.FILE$+".LST" UNLESS &
|
||||
INSTR(1%,LISTING.FILE$,".") &
|
||||
\ SOURCE.FILE$=RIGHT(SOURCE.FILE$, &
|
||||
LISTING.TO.FILE.FLAG%+1%)
|
||||
1230 SOURCE.FILE$=SOURCE.FILE$+".SRC" UNLESS &
|
||||
INSTR(1%,SOURCE.FILE$,".")
|
||||
1240 PRINT #1%,"Listing output to "+ &
|
||||
LISTING.FILE$ IF LISTING.TO.FILE.FLAG%
|
||||
1250 IF OBJECT.OUT.FLAG% THEN OBJECT.FILE$= &
|
||||
LEFT(SOURCE.FILE$,INSTR(1%,SOURCE.FILE$,"."))+"HEX" &
|
||||
\ PRINT #1%,"Object module to ";OBJECT.FILE$
|
||||
1260 ! -- Get a unique workfile name --
|
||||
1270 WORK.FILE$="X65X"+MID(NUM$(100%+ASCII(SYS(CHR$(6%)+ &
|
||||
CHR$(9%)))/2%),3%,2%)+".TMP"
|
||||
1280 ! -- Commence assembly --
|
||||
1290 GOSUB 2010 &
|
||||
\ GOSUB 3010 &
|
||||
\ X%=1% &
|
||||
\ GOSUB 3630
|
||||
1300 ! -- Print symbol table --
|
||||
1310 GOSUB 3660 IF SYMBOL.TABLE.LIST.FLAG% &
|
||||
\ PRINT #1%
|
||||
1320 ! -- Finish up and exit --
|
||||
1330 CLOSE 1% &
|
||||
\ IF LISTING.TO.FILE.FLAG% THEN X%=0% &
|
||||
\ GOSUB 3630
|
||||
1340 PRINT "Runtime was";(TIME(1%)-START.CPU.TIME%)/10;"sec" &
|
||||
\ GOTO 32767
|
||||
1350 ! &
|
||||
|
||||
2000 &
|
||||
! -- Pass 1 Driver routine -- &
|
||||
|
||||
2010 ERROR.COUNT%, &
|
||||
TOTAL.BYTES%, &
|
||||
LOCATION.COUNTER%, &
|
||||
ERROR.LINE.FLAG%, &
|
||||
OPCODE.TABLE.SUBSCRIPT%=0% &
|
||||
\ PASS.NUMBER%=1% &
|
||||
\ OPEN SOURCE.FILE$ FOR INPUT AS FILE 2% &
|
||||
\ OPEN WORK.FILE$ FOR OUTPUT AS FILE 3% &
|
||||
\ PRINT #1%,"Pass 1"
|
||||
2020 INPUT LINE #2%,SOURCE.LINE$ &
|
||||
\ SOURCE.LINE$=CVT$$(SOURCE.LINE$,421%) &
|
||||
\ LINE.LENGTH%=LEN(SOURCE.LINE$) &
|
||||
\ LINE.NUMBER%=LINE.NUMBER%+1%
|
||||
2030 IF LINE.LENGTH%=0% OR LEFT(SOURCE.LINE$,1%)="$" THEN &
|
||||
OPCODE.TABLE.SUBSCRIPT%=-1% &
|
||||
\ GOTO 2150
|
||||
2040 ! -- Scan source line --
|
||||
2050 GOSUB 2360 &
|
||||
\ GOSUB 2410
|
||||
2060 ! -- Comment line ? --
|
||||
2070 IF COMMENT.DELIMITER%=1% THEN &
|
||||
OPCODE.TABLE.SUBSCRIPT%=-1% &
|
||||
\ GOTO 2150
|
||||
2080 ! -- Get argument field --
|
||||
2090 IF COMMENT.DELIMITER% THEN ARGUMENT$= &
|
||||
CVT$$(MID(SOURCE.LINE$,OPCODE.DELIMITER%+1%, &
|
||||
COMMENT.DELIMITER%-OPCODE.DELIMITER%-1%),258%) &
|
||||
ELSE ARGUMENT$=CVT$$(RIGHT(SOURCE.LINE$,OPCODE.DELIMITER%+1%),258%)
|
||||
2100 ! -- Label ? --
|
||||
2110 IF LABEL.DELIMITER% THEN SYMBOL$= &
|
||||
CVT$$(LEFT(SOURCE.LINE$,LABEL.DELIMITER%-1%),128%) &
|
||||
\ VALUE%=LOCATION.COUNTER% &
|
||||
\ FLAG.WORD%=-2% &
|
||||
\ GOSUB 2490
|
||||
2120 ! -- Assignment ? --
|
||||
2130 IF EQU.DELIMITER% THEN GOSUB 2560 &
|
||||
ELSE GOSUB 2610
|
||||
2140 ! -- Write to workfile --
|
||||
2150 GOSUB 2770 &
|
||||
\ GOTO 2020 IF OPCODE.TABLE.SUBSCRIPT%=-1% &
|
||||
\ GOTO 2020 IF FLAGS%(OPCODE.TABLE.SUBSCRIPT%)<>1%
|
||||
2160 CLOSE 2%,3% &
|
||||
\ RETURN &
|
||||
! -- End of Pass 1
|
||||
2170 ! &
|
||||
|
||||
2180 &
|
||||
! -- Determine the addressing mode &
|
||||
! -- and the number of bytes for this opcode &
|
||||
|
||||
2190 OP.TYPE%=SWAP%(VALUES%(OPCODE.TABLE.SUBSCRIPT%)) AND 255%
|
||||
2200 IF OP.TYPE%=0% THEN BYTE.COUNT%=1% &
|
||||
\ TEMP1%=FNERROR.PRINT%("No argument required") &
|
||||
IF ARGUMENT$<>"" &
|
||||
\ RETURN
|
||||
2210 IF OP.TYPE%=1% THEN BYTE.COUNT%=2% &
|
||||
\ RETURN &
|
||||
! relative branch
|
||||
2220 IF OP.TYPE%=2% THEN BYTE.COUNT%=3% &
|
||||
\ RETURN &
|
||||
! transfer
|
||||
2230 ARG.LENGTH%=LEN(ARGUMENT$) &
|
||||
\ IF ARG.LENGTH%=0% THEN BYTE.COUNT%=FNERROR.PRINT%( &
|
||||
"Missing argument") &
|
||||
\ OPCODE.TABLE.SUBSCRIPT%=-1% &
|
||||
\ RETURN
|
||||
2240 TEMP2$=MID(ARGUMENT$,ARG.LENGTH%-2%,3%) &
|
||||
\ TEMP3$=LEFT(ARGUMENT$,1%) &
|
||||
\ IF TEMP2$=",X)" AND TEMP3$="(" THEN ADDR.MODE%=0% &
|
||||
\ ARGUMENT$=MID(ARGUMENT$,2%,ARG.LENGTH%-4%) &
|
||||
\ BYTE.COUNT%=2% &
|
||||
\ RETURN &
|
||||
! (ind ,X)
|
||||
2250 IF TEMP2$="),Y" AND TEMP3$="(" THEN ADDR.MODE%=16% &
|
||||
\ ARGUMENT$=MID(ARGUMENT$,2%,ARG.LENGTH%-4%) &
|
||||
\ BYTE.COUNT%=2% &
|
||||
\ RETURN &
|
||||
! (ind),Y
|
||||
2260 IF TEMP3$="#" THEN ADDR.MODE%=8% &
|
||||
\ ARGUMENT$=RIGHT(ARGUMENT$,2%) &
|
||||
\ BYTE.COUNT%=2% &
|
||||
\ RETURN &
|
||||
! #
|
||||
2270 IF ARGUMENT$="A" THEN ADDR.MODE%=8% &
|
||||
\ BYTE.COUNT%=1% &
|
||||
\ RETURN &
|
||||
! A
|
||||
2280 TEMP2$=RIGHT(TEMP2$,2%) &
|
||||
\ IF OP.TYPE%>7% AND TEMP2$=",Y" THEN TEMP2$=",X" &
|
||||
\ GOTO 2300 &
|
||||
! Convert ',Y' to ',X' for idx store and load
|
||||
2290 IF TEMP2$=",Y" THEN ADDR.MODE%=24% &
|
||||
\ ARGUMENT$=LEFT(ARGUMENT$,ARG.LENGTH%-2%) &
|
||||
\ BYTE.COUNT%=3% &
|
||||
\ RETURN &
|
||||
! abs,Y
|
||||
2300 IF TEMP2$<>",X" THEN 2320 &
|
||||
ELSE ARGUMENT$=LEFT(ARGUMENT$,ARG.LENGTH%-2%) &
|
||||
\ VALUE%=FNEVALUATE.EXPR%(ARGUMENT$) &
|
||||
\ IF UNDEFINED.SYMBOL% OR ( VALUE% AND -256% ) THEN &
|
||||
ADDR.MODE%=28% &
|
||||
\ BYTE.COUNT%=3% &
|
||||
\ RETURN &
|
||||
! abs,X
|
||||
2310 ADDR.MODE%=20% &
|
||||
\ BYTE.COUNT%=2% &
|
||||
\ RETURN &
|
||||
! z page,X
|
||||
2320 VALUE%=FNEVALUATE.EXPR%(ARGUMENT$) &
|
||||
\ IF UNDEFINED.SYMBOL% OR ( VALUE% AND -256% ) THEN &
|
||||
ADDR.MODE%=12% &
|
||||
\ BYTE.COUNT%=3% &
|
||||
\ RETURN &
|
||||
! abs
|
||||
2330 ADDR.MODE%=4% &
|
||||
\ BYTE.COUNT%=2% &
|
||||
\ RETURN &
|
||||
! zero page
|
||||
2340 ! &
|
||||
|
||||
2350 &
|
||||
! -- Scan for strings in SOURCE.LINE$ -- &
|
||||
|
||||
2360 DELIMITER%=-1% &
|
||||
\ TEMP2%=0%
|
||||
2370 TEMP1%=INSTR(TEMP2%+1%,SOURCE.LINE$,"'") &
|
||||
\ RETURN UNLESS TEMP1%
|
||||
2380 TEMP2%=INSTR(TEMP1%+1%,SOURCE.LINE$,"'") &
|
||||
\ IF TEMP2% THEN DELIMITER%=DELIMITER%+1% &
|
||||
\ IF DELIMITER%<4% THEN DELIMITER.TABLE%(DELIMITER%)= &
|
||||
SWAP%(TEMP1% AND 255%) OR (TEMP2% AND 255%) &
|
||||
\ GOTO 2370
|
||||
2390 RETURN
|
||||
2400 &
|
||||
! -- Search for token delimiters -- &
|
||||
! LABEL.DELIMITER% Label &
|
||||
! OPCODE.DELIMITER% Opcode &
|
||||
! COMMENT.DELIMITER% Comment &
|
||||
! EQU.DELIMITER% Assignment &
|
||||
|
||||
2410 LABEL.DELIMITER%=INSTR(1%,SOURCE.LINE$,":") &
|
||||
\ LABEL.DELIMITER%=0% IF FNCHECK.SYNTAX%(LABEL.DELIMITER%) &
|
||||
\ COMMENT.DELIMITER%=0%
|
||||
2420 COMMENT.DELIMITER%=INSTR(COMMENT.DELIMITER%+1%,SOURCE.LINE$,";") &
|
||||
\ GOTO 2420 IF FNCHECK.SYNTAX%(COMMENT.DELIMITER%) &
|
||||
\ LABEL.DELIMITER%=0% IF (LABEL.DELIMITER%> &
|
||||
COMMENT.DELIMITER% AND COMMENT.DELIMITER%<>0%) &
|
||||
\ OPCODE.DELIMITER%=LABEL.DELIMITER%
|
||||
2430 OPCODE.DELIMITER%=OPCODE.DELIMITER%+1% &
|
||||
\ IF OPCODE.DELIMITER%>=LINE.LENGTH% THEN 2450 &
|
||||
ELSE X%=ASCII(RIGHT(SOURCE.LINE$,OPCODE.DELIMITER%)) &
|
||||
\ IF X%=9% OR X%=32% THEN 2430
|
||||
2440 OPCODE.DELIMITER%=OPCODE.DELIMITER%+1% &
|
||||
\ IF OPCODE.DELIMITER%<LINE.LENGTH% THEN &
|
||||
X%=ASCII(RIGHT(SOURCE.LINE$,OPCODE.DELIMITER%)) &
|
||||
\ IF X%<>9% AND X%<>32% THEN 2440 &
|
||||
ELSE OPCODE.DELIMITER%=OPCODE.DELIMITER%-1%
|
||||
2450 EQU.DELIMITER%=INSTR(1%,SOURCE.LINE$,"=") &
|
||||
\ EQU.DELIMITER%=0% IF FNCHECK.SYNTAX%(EQU.DELIMITER%) OR &
|
||||
(EQU.DELIMITER%>COMMENT.DELIMITER% AND &
|
||||
COMMENT.DELIMITER%<>0%) &
|
||||
\ OPCODE.DELIMITER%=EQU.DELIMITER% IF EQU.DELIMITER%
|
||||
2460 OPCODE.DELIMITER%=COMMENT.DELIMITER%-1% IF &
|
||||
(OPCODE.DELIMITER%>=COMMENT.DELIMITER% AND &
|
||||
COMMENT.DELIMITER%<>0%) &
|
||||
\ RETURN
|
||||
2470 ! &
|
||||
|
||||
2480 &
|
||||
! Enter symbol SYMBOL$ into symbol table &
|
||||
! and its value VALUE% &
|
||||
|
||||
2490 IF NUMBER.OF.SYMBOLS%=SYMBOL.TABLE.SIZE% THEN &
|
||||
VALUE%=FNERROR.PRINT%("?X65 - FATAL: Symbol table overflow") &
|
||||
\ STOP &
|
||||
! Symbol table full
|
||||
2500 X%=ASCII(SYMBOL$) &
|
||||
\ IF X%<>46% AND ( X%<65% OR X%>90% ) THEN &
|
||||
VALUE%=FNERROR.PRINT%("Invalid symbol = "+SYMBOL$) &
|
||||
\ RETURN &
|
||||
! Invalid symbol
|
||||
2510 TEMP2%=FNHASH.SYMBOL%(SYMBOL$,SYMBOL.TABLE.SIZE%) &
|
||||
! Hash symbol
|
||||
2520 IF SYMBOLS$(TEMP2%)="" THEN SYMBOLS$(TEMP2%)=SYMBOL$ &
|
||||
\ VALUES%(TEMP2%)=VALUE% &
|
||||
\ FLAGS%(TEMP2%)=FLAG.WORD% &
|
||||
\ NUMBER.OF.SYMBOLS%=NUMBER.OF.SYMBOLS%+1% &
|
||||
\ RETURN &
|
||||
! If slot empty, enter symbol, value and flagword
|
||||
2530 IF SYMBOLS$(TEMP2%)=SYMBOL$ AND FLAGS%(TEMP2%)<0% THEN &
|
||||
VALUE%=FNERROR.PRINT%("Redefined symbol = "+SYMBOL$) &
|
||||
\ RETURN &
|
||||
! Multiple definition not allowed
|
||||
2540 TEMP2%=FNREHASH.SYMBOL%(TEMP2%,SYMBOL.TABLE.SIZE%) &
|
||||
\ GOTO 2520
|
||||
2550 &
|
||||
! -- Enter assignment -- &
|
||||
|
||||
2560 SYMBOL$=CVT$$(MID(SOURCE.LINE$,LABEL.DELIMITER%+1%, &
|
||||
EQU.DELIMITER%-LABEL.DELIMITER%-1%),136%) &
|
||||
\ VALUE%=FNEVALUATE.EXPR%(ARGUMENT$) &
|
||||
\ IF UNDEFINED.SYMBOL% THEN VALUE%= &
|
||||
FNERROR.PRINT%("Undefined value")
|
||||
2570 IF SYMBOL$="." THEN LOCATION.COUNTER%=VALUE% &
|
||||
ELSE IF SYMBOL$="" THEN VALUE%= &
|
||||
FNERROR.PRINT%("Missing symbol") &
|
||||
ELSE FLAG.WORD%=-1% &
|
||||
\ GOSUB 2490
|
||||
2580 OPCODE.TABLE.SUBSCRIPT%=-1% &
|
||||
\ RETURN
|
||||
2590 ! &
|
||||
|
||||
2600 &
|
||||
! -- Get opcode subscript -- &
|
||||
|
||||
2610 OPCODE$=CVT$$(MID(SOURCE.LINE$,LABEL.DELIMITER%+1%, &
|
||||
OPCODE.DELIMITER%-LABEL.DELIMITER%),8%) &
|
||||
\ IF OPCODE$<>"" THEN OPCODE.TABLE.SUBSCRIPT%= &
|
||||
FNHASH.SYMBOL%(OPCODE$,SYMBOL.TABLE.SIZE%) &
|
||||
ELSE OPCODE.TABLE.SUBSCRIPT%=-1% \ RETURN
|
||||
2620 IF SYMBOLS$(OPCODE.TABLE.SUBSCRIPT%)=OPCODE$ THEN RETURN &
|
||||
ELSE IF FLAGS%(OPCODE.TABLE.SUBSCRIPT%)<0% OR &
|
||||
SYMBOLS$(OPCODE.TABLE.SUBSCRIPT%)="" THEN &
|
||||
OPCODE.TABLE.SUBSCRIPT%= &
|
||||
FNERROR.PRINT%("Invalid opcode = "+OPCODE$)-1% &
|
||||
ELSE OPCODE.TABLE.SUBSCRIPT%= &
|
||||
FNREHASH.SYMBOL%(OPCODE.TABLE.SUBSCRIPT%, &
|
||||
SYMBOL.TABLE.SIZE%) &
|
||||
\ GOTO 2620 &
|
||||
! Check for opcode match in the symbol table &
|
||||
! If flagword < 0 then report an error else rehash
|
||||
2630 RETURN
|
||||
2640 &
|
||||
! -- Get address mode and check for validity &
|
||||
|
||||
2650 GOSUB 2190 &
|
||||
\ RETURN IF OP.TYPE%<3% &
|
||||
! O.K. if single byte, branch or transfer
|
||||
2660 ON OP.TYPE%-2% GOTO &
|
||||
2670, 2680, 2690, 2700, &
|
||||
2710, 2720, 2730 &
|
||||
! shift accum bit idx cmp &
|
||||
! inc/dec load idx store idx
|
||||
2670 RETURN IF ( ADDR.MODE%=8% AND ARGUMENT$="A" ) &
|
||||
OR ADDR.MODE%=4% OR ADDR.MODE%=20% &
|
||||
OR ADDR.MODE%=12% OR ADDR.MODE%=28% &
|
||||
\ GOTO 2740
|
||||
2680 RETURN
|
||||
2690 RETURN IF ADDR.MODE%=4% OR ADDR.MODE%=12% &
|
||||
\ GOTO 2740
|
||||
2700 RETURN IF ADDR.MODE%>0% AND ADDR.MODE%<16% &
|
||||
\ GOTO 2740
|
||||
2710 RETURN IF ADDR.MODE%=4% OR ADDR.MODE%=20% &
|
||||
OR ADDR.MODE%=12% OR ADDR.MODE%=28% &
|
||||
\ GOTO 2740
|
||||
2720 RETURN UNLESS ADDR.MODE%=0% OR ADDR.MODE%=16% &
|
||||
OR ADDR.MODE%=24% &
|
||||
\ GOTO 2740
|
||||
2730 RETURN IF ADDR.MODE%=4% OR ADDR.MODE%=12% &
|
||||
OR ADDR.MODE%=20%
|
||||
2740 OPCODE.TABLE.SUBSCRIPT%=FNERROR.PRINT%( &
|
||||
"Illegal addressing mode")-1% &
|
||||
\ RETURN
|
||||
2750 ! &
|
||||
|
||||
2760 &
|
||||
! -- Get byte count and output to workfile -- &
|
||||
|
||||
2770 IF OPCODE.TABLE.SUBSCRIPT%=-1% THEN BYTE.COUNT%=0% &
|
||||
ELSE IF FLAGS%(OPCODE.TABLE.SUBSCRIPT%)>0% THEN &
|
||||
GOSUB 2800 &
|
||||
ELSE GOSUB 2650 &
|
||||
! Get byte count into BYTE.COUNT%
|
||||
2780 PRINT #3%,LOCATION.COUNTER%;","; &
|
||||
BYTE.COUNT%;","; &
|
||||
OPCODE.TABLE.SUBSCRIPT%;","; &
|
||||
ADDR.MODE%;","; &
|
||||
ERROR.LINE.FLAG% &
|
||||
\ PRINT #3%,ARGUMENT$ &
|
||||
\ TOTAL.BYTES%=TOTAL.BYTES%+BYTE.COUNT% &
|
||||
\ LOCATION.COUNTER%=LOCATION.COUNTER%+BYTE.COUNT% &
|
||||
\ ERROR.LINE.FLAG%=0% &
|
||||
\ RETURN
|
||||
2790 &
|
||||
! -- Get byte count for pseudo-op -- &
|
||||
|
||||
2800 ON FLAGS%(OPCODE.TABLE.SUBSCRIPT%) &
|
||||
GOTO 2890, 2820, 2820, 2820, &
|
||||
2840, 2840, 2840, 2870, &
|
||||
2890 &
|
||||
! .END .BYTE .DBYTE .WORD &
|
||||
! .ASCII .ASCIP .ASCIZ .BLKB &
|
||||
! .LIST
|
||||
2810 ! -- .BYTE, .DBYTE, .WORD --
|
||||
2820 TEMP1%=0% &
|
||||
\ TEMP2%=-1% &
|
||||
\ FOR BYTE.COUNT%=0% WHILE TEMP2% &
|
||||
\ TEMP1%,TEMP2%=INSTR(TEMP1%+1%,ARGUMENT$,",") &
|
||||
\ NEXT BYTE.COUNT% &
|
||||
\ BYTE.COUNT%=BYTE.COUNT%*2% IF FLAGS%(OPCODE.TABLE.SUBSCRIPT%)=3% &
|
||||
OR FLAGS%(OPCODE.TABLE.SUBSCRIPT%)=4% &
|
||||
\ RETURN
|
||||
2830 ! -- .ASCII, .ASCIP, .ASCIZ --
|
||||
2840 TEMP1%=INSTR(2%,ARGUMENT$,LEFT(ARGUMENT$,1%)) &
|
||||
\ IF TEMP1%=0% THEN OPCODE.TABLE.SUBSCRIPT%= &
|
||||
FNERROR.PRINT%("Missing delimiter")-1% &
|
||||
ELSE BYTE.COUNT%=TEMP1%-2%
|
||||
2850 BYTE.COUNT%=BYTE.COUNT%+1% IF FLAGS%(OPCODE.TABLE.SUBSCRIPT%)=7% &
|
||||
\ RETURN
|
||||
2860 ! -- .BLKB
|
||||
2870 BYTE.COUNT%=FNEVALUATE.EXPR%(ARGUMENT$) &
|
||||
\ RETURN
|
||||
2880 ! -- .LIST, .END --
|
||||
2890 BYTE.COUNT%=0% &
|
||||
\ RETURN
|
||||
2900 ! &
|
||||
|
||||
3000 &
|
||||
! -- Pass 2 Driver routine -- &
|
||||
|
||||
3010 LINE.NUMBER%, &
|
||||
CHECKSUM%, &
|
||||
NEW.LINE.FLAG%=0% &
|
||||
\ PASS.NUMBER%=2% &
|
||||
\ LIST.FLAG%=-1% &
|
||||
\ PRINT #1%,"Pass 2" &
|
||||
\ CLOSE 1% &
|
||||
\ OPEN LISTING.FILE$ FOR OUTPUT AS FILE 1% &
|
||||
\ OPEN SOURCE.FILE$ FOR INPUT AS FILE 2% &
|
||||
\ OPEN WORK.FILE$ FOR INPUT AS FILE 3% &
|
||||
\ KILL WORK.FILE$
|
||||
3020 IF OBJECT.OUT.FLAG% THEN &
|
||||
OPEN OBJECT.FILE$ FOR OUTPUT AS FILE 4% &
|
||||
\ NEW.OBJ.LINE%=0%
|
||||
3030 IF ERRORS.ONLY.SWITCH% THEN PRINT #1%," Line Addr B1 B2 B3" &
|
||||
\ PRINT #1%
|
||||
3040 INPUT #3%,LOCATION.COUNTER%, &
|
||||
BYTE.COUNT%, &
|
||||
OPCODE.TABLE.SUBSCRIPT%, &
|
||||
ADDR.MODE%, &
|
||||
ERROR.LINE.FLAG% &
|
||||
\ INPUT LINE #3%, ARGUMENT$ &
|
||||
\ ARGUMENT$=CVT$$(ARGUMENT$,4%) &
|
||||
\ INPUT LINE #2%, SOURCE.LINE$ &
|
||||
\ SOURCE.LINE$=CVT$$(SOURCE.LINE$,4%) &
|
||||
\ LINE.NUMBER%=LINE.NUMBER%+1%
|
||||
3050 ! -- Form object code and output to listing file --
|
||||
3060 IF LEFT(SOURCE.LINE$,1%)="$" THEN &
|
||||
SOURCE.LINE$=RIGHT(SOURCE.LINE$,2%)
|
||||
3070 IF OPCODE.TABLE.SUBSCRIPT%=-1% THEN GOSUB 3540 &
|
||||
\ GOTO 3040
|
||||
3080 IF FLAGS%(OPCODE.TABLE.SUBSCRIPT%)=1% THEN &
|
||||
GOSUB 3130 &
|
||||
\ RETURN
|
||||
3090 ADDRESS$=FNDEC.TO.HEX$(LOCATION.COUNTER%,0%) &
|
||||
\ VALUE%=VALUES%(OPCODE.TABLE.SUBSCRIPT%) &
|
||||
\ FLAG.WORD%=SWAP%(VALUE%) AND 255% &
|
||||
\ VALUE%=VALUE% AND 255%
|
||||
3100 IF FLAGS%(OPCODE.TABLE.SUBSCRIPT%)>0% THEN GOSUB 3260 &
|
||||
ELSE IF FLAG.WORD% THEN GOSUB 3170 &
|
||||
ELSE GOSUB 3450 &
|
||||
\ GOSUB 3540
|
||||
3110 GOTO 3040
|
||||
3120 &
|
||||
! -- End of assembly, tidy up -- &
|
||||
|
||||
3130 GOSUB 3540 &
|
||||
\ PRINT #4% IF OBJECT.OUT.FLAG%
|
||||
3140 CLOSE 2%,3%,4% &
|
||||
\ RETURN
|
||||
3150 ! &
|
||||
|
||||
3160 &
|
||||
! -- Process operands -- &
|
||||
|
||||
3170 IF FLAG.WORD%=1% THEN GOSUB 3450 &
|
||||
\ VALUE%=FNEVALUATE.EXPR%(ARGUMENT$)-LOCATION.COUNTER%-2% &
|
||||
\ VALUE%=FNERROR.PRINT%("Invalid displacement ="+NUM$(VALUE%)) &
|
||||
IF VALUE%<-128% OR VALUE%>127% &
|
||||
\ GOSUB 3470 &
|
||||
\ GOTO 3540 &
|
||||
! relative branch
|
||||
3180 IF FLAG.WORD%<>2% THEN 3200 &
|
||||
ELSE ARG.LENGTH%=LEN(ARGUMENT$) &
|
||||
\ IF LEFT(ARGUMENT$,1%)="(" AND &
|
||||
RIGHT(ARGUMENT$,ARG.LENGTH%)=")" AND &
|
||||
VALUE%=76% THEN VALUE%=VALUE%+32% &
|
||||
\ ARGUMENT$=MID(ARGUMENT$,2%,ARG.LENGTH%-2%) &
|
||||
! JMP ( )
|
||||
3190 GOSUB 3450 &
|
||||
\ VALUE%=FNEVALUATE.EXPR%(ARGUMENT$) &
|
||||
\ GOSUB 3470 &
|
||||
\ GOTO 3230 &
|
||||
! transfer
|
||||
3200 IF FLAG.WORD%=6% THEN &
|
||||
ADDR.MODE%=0% IF ADDR.MODE%=8% &
|
||||
! kludge for compare idx
|
||||
3210 IF FLAG.WORD%=8% THEN &
|
||||
ADDR.MODE%=ADDR.MODE%+4% &
|
||||
\ ADDR.MODE%=4% IF ADDR.MODE%=12% &
|
||||
! kludge for load idx
|
||||
3220 VALUE%=VALUE%+ADDR.MODE% &
|
||||
\ GOSUB 3450 &
|
||||
\ GOTO 3540 IF BYTE.COUNT%=1% &
|
||||
\ VALUE%=FNEVALUATE.EXPR%(ARGUMENT$) &
|
||||
\ GOSUB 3470 &
|
||||
\ GOTO 3540 IF BYTE.COUNT%=2%
|
||||
3230 VALUE%=SWAP%(VALUE%) &
|
||||
\ GOSUB 3490 &
|
||||
\ GOTO 3540 &
|
||||
! multi mode
|
||||
3240 ! &
|
||||
|
||||
3250 &
|
||||
! -- Pseudo-ops. -- &
|
||||
|
||||
3260 ON FLAGS%(OPCODE.TABLE.SUBSCRIPT%) &
|
||||
GOTO 3430, 3280, 3280, 3280, &
|
||||
3340, 3340, 3340, 3410, &
|
||||
3390 &
|
||||
! .END .BYTE .DBYTE .WORD &
|
||||
! .ASCII .ASCIP .ASCIZ .BLKB &
|
||||
! .LIST
|
||||
3270 ! -- .BYTE, .DBYTE, .WORD --
|
||||
3280 ARGUMENT$=ARGUMENT$+"," &
|
||||
\ TEMP3%=1% &
|
||||
\ TEMP3%=2% IF FLAGS%(OPCODE.TABLE.SUBSCRIPT%)=3% &
|
||||
OR FLAGS%(OPCODE.TABLE.SUBSCRIPT%)=4% &
|
||||
\ FOR I%=1% TO BYTE.COUNT% STEP TEMP3% &
|
||||
\ ADDRESS$=FNDEC.TO.HEX$(LOCATION.COUNTER%+I%-1%,0%) &
|
||||
\ TEMP1%=INSTR(1%,ARGUMENT$,",")
|
||||
3290 TEMP2%=FNEVALUATE.EXPR%(LEFT(ARGUMENT$,TEMP1%-1%)) &
|
||||
\ IF FLAGS%(OPCODE.TABLE.SUBSCRIPT%)=3% THEN &
|
||||
VALUE%=SWAP%(TEMP2%) &
|
||||
\ GOSUB 3450 &
|
||||
\ VALUE%=TEMP2% &
|
||||
\ GOSUB 3470
|
||||
3300 IF FLAGS%(OPCODE.TABLE.SUBSCRIPT%)=4% THEN &
|
||||
VALUE%=SWAP%(TEMP2%) &
|
||||
\ GOSUB 3470 &
|
||||
\ VALUE%=TEMP2% &
|
||||
\ GOSUB 3450
|
||||
3310 IF FLAGS%(OPCODE.TABLE.SUBSCRIPT%)=2% THEN &
|
||||
VALUE%=TEMP2% &
|
||||
\ GOSUB 3450
|
||||
3320 GOSUB 3540 &
|
||||
\ ARGUMENT$=RIGHT(ARGUMENT$,TEMP1%+1%) &
|
||||
\ NEXT I% &
|
||||
\ RETURN
|
||||
3330 ! -- .ASCII, .ASCIP, .ASCIZ --
|
||||
3340 ARGUMENT$=MID(ARGUMENT$,2%,BYTE.COUNT%) &
|
||||
\ ARGUMENT$=LEFT(ARGUMENT$,BYTE.COUNT%-1%)+CHR$(0%) &
|
||||
IF FLAGS%(OPCODE.TABLE.SUBSCRIPT%)=7% &
|
||||
\ FOR I%=1% TO BYTE.COUNT% STEP 3% &
|
||||
\ ADDRESS$=FNDEC.TO.HEX$(LOCATION.COUNTER%+I%-1%,0%) &
|
||||
\ VALUE%=FNCHAR%(I%) &
|
||||
\ GOSUB 3450 &
|
||||
\ VALUE%=FNCHAR%(I%+1%) &
|
||||
\ GOSUB 3470 IF I%+1%<=BYTE.COUNT% &
|
||||
\ VALUE%=FNCHAR%(I%+2%) &
|
||||
\ GOSUB 3490 IF I%+2%<=BYTE.COUNT% &
|
||||
\ GOSUB 3540 &
|
||||
\ NEXT I% &
|
||||
\ RETURN
|
||||
3350 ! &
|
||||
|
||||
3360 ! -- Get character J% from ARGUMENT$
|
||||
3370 DEF* FNCHAR%(J%) &
|
||||
\ CHAR%=ASCII(MID(ARGUMENT$,J%,1%)) &
|
||||
\ CHAR%=CHAR% OR 128% IF FLAGS%(OPCODE.TABLE.SUBSCRIPT%)=6% &
|
||||
AND J%=BYTE.COUNT% &
|
||||
\ FNCHAR%=CHAR% &
|
||||
\ FNEND &
|
||||
|
||||
3380 ! -- .LIST --
|
||||
3390 LIST.FLAG%=FNEVALUATE.EXPR%(ARGUMENT$) &
|
||||
\ ADDRESS$="" &
|
||||
\ RETURN
|
||||
3400 ! -- .BLKB
|
||||
3410 TEMP1%=FNEVALUATE.EXPR%(ARGUMENT$) &
|
||||
\ IF OBJECT.OUT.FLAG% THEN VALUE%=0% &
|
||||
\ FOR X%=1% TO TEMP1% &
|
||||
\ GOSUB 3520 &
|
||||
\ NEXT X%
|
||||
3420 GOSUB 3540
|
||||
3430 RETURN
|
||||
3440 &
|
||||
! -- Form B1 -- &
|
||||
|
||||
3450 BYTE1$=FNDEC.TO.HEX$(VALUE%,3%) &
|
||||
\ GOSUB 3520 &
|
||||
\ RETURN
|
||||
3460 &
|
||||
! -- Form B2 -- &
|
||||
|
||||
3470 BYTE2$=FNDEC.TO.HEX$(VALUE%,3%) &
|
||||
\ GOSUB 3520 &
|
||||
\ RETURN
|
||||
3480 &
|
||||
! -- Form B3 -- &
|
||||
|
||||
3490 BYTE3$=FNDEC.TO.HEX$(VALUE%,3%) &
|
||||
\ GOSUB 3520 &
|
||||
\ RETURN
|
||||
3500 ! &
|
||||
|
||||
3510 &
|
||||
! -- Output object and update checksum -- &
|
||||
|
||||
3520 OBJECT.BYTE%=VALUE% AND 255% &
|
||||
\ OBJECT.BYTE%=FNOBJECT.OUTPUT%(VALUE%) IF OBJECT.OUT.FLAG% &
|
||||
\ CHECKSUM%=CHECKSUM%+OBJECT.BYTE% &
|
||||
\ RETURN
|
||||
3530 &
|
||||
! -- Output assembled code to listing file -- &
|
||||
|
||||
3540 GOTO 3590 UNLESS ERRORS.ONLY.SWITCH% OR ERROR.LINE.FLAG%
|
||||
3550 IF ERROR.LINE.FLAG% THEN PRINT #1%,"?"; ELSE PRINT #1%," ";
|
||||
3560 IF NEW.LINE.FLAG%<LINE.NUMBER% THEN &
|
||||
PRINT #1% USING "#### ",LINE.NUMBER%; &
|
||||
ELSE PRINT #1%," ";
|
||||
3570 PRINT #1% USING"\ \ \\ \\ \\",ADDRESS$,BYTE1$,BYTE2$,BYTE3$; &
|
||||
\ IF LIST.FLAG% AND SOURCE.LINE$<>"" THEN &
|
||||
PRINT #1%,CHR$(9%);SOURCE.LINE$ &
|
||||
ELSE PRINT #1%
|
||||
3580 ! -- Set a flag, clear output strings --
|
||||
3590 NEW.LINE.FLAG%=LINE.NUMBER% &
|
||||
\ ADDRESS$,BYTE1$,BYTE2$,BYTE3$,SOURCE.LINE$="" &
|
||||
\ RETURN
|
||||
3600 &
|
||||
! -- Output binary byte to object file -- &
|
||||
|
||||
3610 DEF* FNOBJECT.OUTPUT%(X%) &
|
||||
\ OBJECT.BYTE%=X% AND 255% &
|
||||
\ PRINT #4%,FNDEC.TO.HEX$(OBJECT.BYTE%,3%); &
|
||||
\ NEW.OBJ.LINE%=NEW.OBJ.LINE%+1% &
|
||||
\ PRINT #4% IF (NEW.OBJ.LINE% AND 15%)=0% &
|
||||
\ FNOBJECT.OUTPUT%=OBJECT.BYTE% &
|
||||
\ FNEND
|
||||
3620 &
|
||||
! -- Print error count, checksum -- &
|
||||
|
||||
3630 PRINT #X% &
|
||||
\ PRINT #X%,"Errors detected ";FNDEC.TO.HEX$(ERROR.COUNT%,0%) &
|
||||
\ PRINT #X%,"Source checksum ";FNDEC.TO.HEX$(CHECKSUM%,0%) &
|
||||
\ PRINT #X%,"Total hex bytes ";FNDEC.TO.HEX$(TOTAL.BYTES%,0%) &
|
||||
\ PRINT #X% &
|
||||
\ RETURN
|
||||
3640 ! &
|
||||
|
||||
3650 &
|
||||
! -- Print sorted symbol table -- &
|
||||
|
||||
3660 TEMP1%,TEMP2%=0% &
|
||||
\ NUMBER.OF.SYMBOLS%=NUMBER.OF.SYMBOLS%-66% &
|
||||
\ RETURN IF NUMBER.OF.SYMBOLS%<0%
|
||||
3670 PRINT #1%," Symbol Table" &
|
||||
\ PRINT #1%
|
||||
3680 TEMP1%=TEMP1%+1% WHILE FLAGS%(TEMP1%)>=0% &
|
||||
\ SYMBOLS$(TEMP2%)=SYMBOLS$(TEMP1%) &
|
||||
\ VALUES%(TEMP2%)=VALUES%(TEMP1%) &
|
||||
\ FLAGS%(TEMP2%)=FLAGS%(TEMP1%) &
|
||||
\ TEMP2%=TEMP2%+1% &
|
||||
\ TEMP1%=TEMP1%+1% &
|
||||
\ GOTO 3680 UNLESS TEMP2%=NUMBER.OF.SYMBOLS%
|
||||
3690 ! -- Quick sort the symbol table
|
||||
3700 TEMP1%=FNQUICKSORT%(0%,NUMBER.OF.SYMBOLS%,0%,NUMBER.OF.SYMBOLS%)
|
||||
3710 ! -- Output to listing file --
|
||||
3720 FOR I%=0% TO NUMBER.OF.SYMBOLS% &
|
||||
\ IF FLAGS%(I%)=-1% THEN S$="#" ELSE S$=" "
|
||||
3730 PRINT #1% USING " \ \ \ \ ", &
|
||||
SYMBOLS$(I%),FNDEC.TO.HEX$(VALUES%(I%),0%)+S$; &
|
||||
\ PRINT #1% IF CCPOS(1%)>63% &
|
||||
\ NEXT I%
|
||||
3740 PRINT #1% IF CCPOS(1%) &
|
||||
\ RETURN
|
||||
3750 &
|
||||
! -- Check position of char X% in SOURCE.LINE$ using tables &
|
||||
! -- DELIMITER%(). FNCHECK.SYNTAX%=-1% means in string &
|
||||
|
||||
3760 DEF* FNCHECK.SYNTAX%(X%)
|
||||
3770 GOTO 3790 IF DELIMITER%=-1% OR X%=0% &
|
||||
\ FOR X0%=0% TO DELIMITER% &
|
||||
\ GOTO 3790 IF X%<(SWAP%(DELIMITER.TABLE%(X0%)) AND 255%) &
|
||||
\ IF X%<(DELIMITER.TABLE%(X0%) AND 255%) THEN &
|
||||
FNCHECK.SYNTAX%=-1% &
|
||||
\ GOTO 3800
|
||||
3780 NEXT X0%
|
||||
3790 FNCHECK.SYNTAX%=0%
|
||||
3800 FNEND
|
||||
3810 ! &
|
||||
|
||||
4000 &
|
||||
! -- Evaluate the argument expression -- &
|
||||
|
||||
4010 DEF* FNEVALUATE.EXPR%(X$) &
|
||||
\ UNDEFINED.SYMBOL%=0%
|
||||
4020 &
|
||||
! -- Main driver routine -- &
|
||||
|
||||
4030 EXPR$=X$ &
|
||||
\ GOSUB 4060 &
|
||||
\ GOSUB 4080 &
|
||||
\ EXP.VAL%=TERM%
|
||||
4040 GOTO 4290 UNLESS OP% &
|
||||
\ LAST.OP%=OP% &
|
||||
\ GOSUB 4060 &
|
||||
\ GOSUB 4080 &
|
||||
\ GOSUB 4190 &
|
||||
\ GOTO 4040
|
||||
4050 &
|
||||
REM ! -- Scan for the next operator { ! & % + * - / } -- &
|
||||
|
||||
4060 EXP.FLAG%=-1% &
|
||||
\ FOR TOK.PTR%=1% TO LEN(EXPR$) &
|
||||
\ TOK.CHR$=MID(EXPR$,TOK.PTR%,1%) &
|
||||
\ EXP.FLAG%= NOT EXP.FLAG% IF TOK.CHR$="'" &
|
||||
\ OP%=INSTR(1%,"!%&*+-/",TOK.CHR$) &
|
||||
\ RETURN IF OP% AND EXP.FLAG% &
|
||||
\ NEXT TOK.PTR% &
|
||||
\ OP%=0% &
|
||||
\ TOK.PTR%=TOK.PTR%+1% &
|
||||
\ RETURN
|
||||
4070 &
|
||||
! -- Get value of term -- &
|
||||
|
||||
4080 TERM$=LEFT(EXPR$,TOK.PTR%-1%) &
|
||||
\ EXPR$=RIGHT(EXPR$,TOK.PTR%+1%)
|
||||
4090 IF TERM$="" THEN TERM%=0% &
|
||||
\ RETURN
|
||||
4100 ! -- H() or L() ? --
|
||||
4110 TEMP1$=LEFT(TERM$,2%) &
|
||||
\ IF TEMP1$="H(" THEN EXP.FLAG%=1% &
|
||||
ELSE IF TEMP1$="L(" THEN EXP.FLAG%=2% &
|
||||
ELSE EXP.FLAG%=0%
|
||||
4120 IF EXP.FLAG% THEN IF RIGHT(TERM$,LEN(TERM$))=")" THEN &
|
||||
TERM$=MID(TERM$,3%,LEN(TERM$)-3%) &
|
||||
ELSE 4170
|
||||
4130 TEMP1$=LEFT(TERM$,1%)
|
||||
4140 IF TEMP1$>="A" AND TEMP1$<="Z" THEN TERM%=FNSYMBOL.LOOKUP%(TERM$) &
|
||||
ELSE IF TEMP1$="0" OR TEMP1$="$" THEN &
|
||||
TERM%=FNHEX.TO.DEC%(RIGHT(TERM$,2%)) &
|
||||
ELSE IF TEMP1$>="1" AND TEMP1$<="9" THEN TERM%=VAL(TERM$) &
|
||||
ELSE IF TEMP1$="'" THEN TERM%=ASCII(RIGHT(TERM$,2%)) &
|
||||
ELSE IF TEMP1$="^" THEN TERM%=FNOCT.TO.DEC%(RIGHT(TERM$,2%)) &
|
||||
ELSE IF TERM$="." THEN TERM%=LOCATION.COUNTER% &
|
||||
ELSE 4170
|
||||
4150 IF EXP.FLAG%=1% THEN TERM%=SWAP%(TERM%) AND 255% &
|
||||
ELSE IF EXP.FLAG%=2% THEN TERM%=TERM% AND 255%
|
||||
4160 RETURN
|
||||
4170 TERM%=FNERROR.PRINT%("Invalid term = "+TERM$) &
|
||||
\ RETURN
|
||||
4180 &
|
||||
! -- Carry out the arithmetic or logical operation -- &
|
||||
|
||||
4190 ON LAST.OP%+1% &
|
||||
GOTO 4270, 4200, 4210, 4220, &
|
||||
4230, 4240, 4250, 4260 &
|
||||
! or not and &
|
||||
! mult add sub div
|
||||
4200 EXP.VAL%=EXP.VAL% OR TERM% &
|
||||
\ RETURN &
|
||||
! or
|
||||
4210 EXP.VAL%=EXP.VAL%+(NOT TERM%) &
|
||||
\ RETURN &
|
||||
! not
|
||||
4220 EXP.VAL%=EXP.VAL% AND TERM% &
|
||||
\ RETURN &
|
||||
! and
|
||||
4230 EXP.VAL%=EXP.VAL%*TERM% &
|
||||
\ RETURN &
|
||||
! multiply
|
||||
4240 EXP.VAL%=EXP.VAL%+TERM% &
|
||||
\ RETURN &
|
||||
! add
|
||||
4250 EXP.VAL%=EXP.VAL%-TERM% &
|
||||
\ RETURN &
|
||||
! subtract
|
||||
4260 IF TERM%=0% THEN EXP.VAL%=FNERROR.PRINT%("Division by zero") &
|
||||
ELSE EXP.VAL%=EXP.VAL%/TERM%
|
||||
4270 RETURN
|
||||
4280 &
|
||||
! -- Exit with value of expression --
|
||||
4290 FNEVALUATE.EXPR%=EXP.VAL%
|
||||
4300 FNEND
|
||||
4310 ! &
|
||||
|
||||
4320 &
|
||||
! -- Print the given error message to the listing file &
|
||||
|
||||
4330 DEF* FNERROR.PRINT%(X$) &
|
||||
\ PRINT #1%,"********";X$; &
|
||||
\ IF PASS.NUMBER%=1% THEN PRINT #1%," at line";LINE.NUMBER% &
|
||||
ELSE PRINT #1%
|
||||
4340 ERROR.COUNT%=ERROR.COUNT%+1% &
|
||||
\ ERROR.LINE.FLAG%=-1% &
|
||||
\ FNERROR.PRINT%=0% &
|
||||
\ FNEND
|
||||
4350 &
|
||||
! -- Look up value of symbol -- &
|
||||
|
||||
4360 DEF* FNSYMBOL.LOOKUP%(SYMBOL$) &
|
||||
\ X%=FNHASH.SYMBOL%(SYMBOL$,SYMBOL.TABLE.SIZE%)
|
||||
4370 IF SYMBOLS$(X%)=SYMBOL$ AND FLAGS%(X%)<=0% THEN &
|
||||
FNSYMBOL.LOOKUP%=VALUES%(X%) &
|
||||
ELSE IF SYMBOLS$(X%)="" THEN GOSUB 4390 &
|
||||
ELSE X%=FNREHASH.SYMBOL%(X%,SYMBOL.TABLE.SIZE%) &
|
||||
\ GOTO 4370
|
||||
4380 FNEND
|
||||
4390 UNDEFINED.SYMBOL%=-1% &
|
||||
\ IF PASS.NUMBER%=2% THEN &
|
||||
FNSYMBOL.LOOKUP%=FNERROR.PRINT%( &
|
||||
"Undefined symbol "+SYMBOL$)
|
||||
4400 RETURN
|
||||
4410 &
|
||||
! -- Dec to Hex conversion -- &
|
||||
|
||||
4420 DEF* FNDEC.TO.HEX$(X%,D%)
|
||||
4430 X$="" &
|
||||
\ FOR X1%=0% TO 3% &
|
||||
\ X0%=(X% AND (16%^(X1%+1%)-1%*(16%^X1%)))/(16%^X1%) &
|
||||
\ X0%=X0%+16% IF X0%<0% &
|
||||
\ X$=CHR$(48%+X0%)+X$ IF X0%<10% &
|
||||
\ X$=CHR$(55%+X0%)+X$ IF X0%>9% &
|
||||
\ NEXT X1% &
|
||||
\ IF D% THEN X$=MID(X$,D%,2%)
|
||||
4440 FNDEC.TO.HEX$=X$
|
||||
4450 FNEND
|
||||
4460 &
|
||||
! -- Hex to Dec conversion -- &
|
||||
|
||||
4470 DEF* FNHEX.TO.DEC%(X$) &
|
||||
\ X0%=0% &
|
||||
\ FOR X1%=1% TO LEN(X$) &
|
||||
\ X2%=ASCII(MID(X$,X1%,1%)) &
|
||||
\ IF X2%<48% OR (X2%>57% AND X2%<65%) OR X2%>70% THEN &
|
||||
FNHEX.TO.DEC%=FNERROR.PRINT%("Invalid HEX constant = "+X$) &
|
||||
\ GOTO 4490
|
||||
4480 X2%=X2%-48% &
|
||||
\ X2%=X2%-7% IF X2%>9% &
|
||||
\ X0%=X2%+X0%*16% &
|
||||
\ NEXT X1% &
|
||||
\ FNHEX.TO.DEC%=X0%
|
||||
4490 FNEND
|
||||
4500 &
|
||||
! -- Octal to Dec conversion -- &
|
||||
|
||||
4510 DEF* FNOCT.TO.DEC%(X$) &
|
||||
\ X0%=0% &
|
||||
\ FOR X1%=1% TO LEN(X$) &
|
||||
\ X2%=ASCII(MID(X$,X1%,1%))-48% &
|
||||
\ IF X2%<0% OR X2%>7% THEN &
|
||||
FNOCT.TO.DEC%=FNERROR.PRINT%("Invalid OCTAL constant = "+X$) &
|
||||
\ GOTO 4530
|
||||
4520 X0%=X0%*8% + X2% &
|
||||
\ NEXT X1% &
|
||||
\ FNOCT.TO.DEC%=X0%
|
||||
4530 FNEND
|
||||
4540 &
|
||||
! -- Calculate X1% modulo X2% -- &
|
||||
|
||||
4550 DEF* FNMOD%(X1%,X2%) &
|
||||
\ X1%=X1%-(X1%/X2%)*X2% &
|
||||
\ X1%=X1%+X2% IF X1%<0% &
|
||||
\ FNMOD%=X1% &
|
||||
\ FNEND
|
||||
4560 &
|
||||
! -- Hash symbol X$, modulo SYMBOL.TABLE.SIZE% -- &
|
||||
|
||||
4570 DEF* FNHASH.SYMBOL%(SYMBOL$,M%) &
|
||||
\ SYMBOL$=LEFT(SYMBOL$+" ",6%) &
|
||||
\ CHANGE SYMBOL$ TO SYMBOL.CHARS% &
|
||||
\ SYMBOL.CHARS%(X%)=SYMBOL.CHARS%(X%)-48% FOR X%=1% TO 6% &
|
||||
\ FNHASH.SYMBOL%=FNMOD%(SYMBOL.CHARS%(1%)*23%+ &
|
||||
SYMBOL.CHARS%(2%)*19%+SYMBOL.CHARS%(3%)*17%+ &
|
||||
SYMBOL.CHARS%(4%)*13%+SYMBOL.CHARS%(5%)*11%+ &
|
||||
SYMBOL.CHARS%(6%)*7%,M%) &
|
||||
\ FNEND
|
||||
4580 &
|
||||
! -- Rehash function, modulo X2% &
|
||||
|
||||
4590 DEF* FNREHASH.SYMBOL%(X1%,X2%)=FNMOD%(X1%+23%,X2%)
|
||||
4600 &
|
||||
! -- Quick sort symbol table &
|
||||
|
||||
4610 ! &
|
||||
|
||||
4620 DEF* FNQUICKSORT%(LOW%,HIGH%,I%,J%) &
|
||||
\ I%=LOW% &
|
||||
\ J%=HIGH% &
|
||||
\ X$=SYMBOLS$((HIGH%+LOW%)/2%)
|
||||
4630 I%=I%+1% WHILE SYMBOLS$(I%)<X$
|
||||
4640 J%=J%-1% WHILE X$<SYMBOLS$(J%)
|
||||
4650 IF I%>J% THEN 4670 &
|
||||
ELSE IF I%<>J% THEN VALUE%=VALUES%(I%) &
|
||||
\ FLAG.WORD%=FLAGS%(I%) &
|
||||
\ SYMBOL$=SYMBOLS$(I%) &
|
||||
\ VALUES%(I%)=VALUES%(J%) &
|
||||
\ FLAGS%(I%)=FLAGS%(J%) &
|
||||
\ SYMBOLS$(I%)=SYMBOLS$(J%) &
|
||||
\ VALUES%(J%)=VALUE% &
|
||||
\ FLAGS%(J%)=FLAG.WORD% &
|
||||
\ SYMBOLS$(J%)=SYMBOL$
|
||||
4660 I%=I%+1% &
|
||||
\ J%=J%-1% &
|
||||
\ IF I%<=J% THEN 4630
|
||||
4670 IF LOW%<J% THEN TEMP1%=FNQUICKSORT%(LOW%,J%,LOW%,J%)
|
||||
4680 IF I%<HIGH% THEN TEMP1%=FNQUICKSORT%(I%,HIGH%,I%,HIGH%)
|
||||
4690 FNQUICKSORT%=-1% &
|
||||
\ FNEND
|
||||
4700 ! &
|
||||
|
||||
31000 &
|
||||
! -- Error routine -- &
|
||||
|
||||
31010 ! -- No ".END" --
|
||||
31020 IF ERR=11% AND ERL=2020% THEN OPCODE.TABLE.SUBSCRIPT%= &
|
||||
FNERROR.PRINT%("Missing .END")+ &
|
||||
FNHASH.SYMBOL%(".END",SYMBOL.TABLE.SIZE%) &
|
||||
\ SOURCE.LINE$="" &
|
||||
\ RESUME 2150
|
||||
31030 IF ERR=11% AND ERL=3040% THEN SOURCE.LINE$="" &
|
||||
\ OPCODE.TABLE.SUBSCRIPT%=FNHASH.SYMBOL%(".END", &
|
||||
SYMBOL.TABLE.SIZE%) &
|
||||
\ RESUME 3080
|
||||
31040 ! -- ^Z at filename request --
|
||||
31050 RESUME 32767 IF ERL=1140%
|
||||
31060 ! -- Illegal number in FNEVALUATE.EXPR%() --
|
||||
31070 IF ERR=51% AND ERL=4140% THEN X0%=VAL(TERM$)-65536 &
|
||||
\ RESUME 4150
|
||||
31080 RESUME 4170 IF ERR=52% AND ERL=4140%
|
||||
31090 CLOSE 1%,2%,3%,4% &
|
||||
\ RESUME 32767% IF ERR=28%
|
||||
31100 ! -- Print any unanticipated error --
|
||||
31110 ON ERROR GOTO 0
|
||||
31120 ! &
|
||||
|
||||
32000 &
|
||||
! -- Opcode data &
|
||||
|
||||
32010 ! Table is of the form: &
|
||||
! SYMBOL,value,flag &
|
||||
! where: the low byte of value is the opcode base &
|
||||
! and the high byte a flag indicating the &
|
||||
! instruction type. flag is used by the &
|
||||
! symbol table routines &
|
||||
!
|
||||
32020 ! Assembler pseudo-ops
|
||||
32030 DATA .END, 0, 1, .BYTE, 0, 2, &
|
||||
.DBYTE, 0, 3, .WORD, 0, 4, &
|
||||
.ASCII, 0, 5, .ASCIP, 0, 6, &
|
||||
.ASCIZ, 0, 7, .BLKB, 0, 8, &
|
||||
.LIST, 0, 9
|
||||
32040 ! Single byte instructions
|
||||
32050 DATA BRK, 0, 0, CLC, 24, 0, &
|
||||
CLD, 216, 0, CLI, 88, 0, &
|
||||
CLV, 184, 0, DEX, 202, 0, &
|
||||
DEY, 136, 0, INX, 232, 0, &
|
||||
INY, 200, 0, NOP, 234, 0, &
|
||||
PHA, 72, 0, PHP, 8, 0, &
|
||||
PLA, 104, 0, PLP, 40, 0, &
|
||||
RTI, 64, 0, RTS, 96, 0, &
|
||||
SEC, 56, 0, SED, 248, 0, &
|
||||
SEI, 120, 0, TAX, 170, 0, &
|
||||
TAY, 168, 0, TSX, 186, 0, &
|
||||
TXA, 138, 0, TYA, 152, 0, &
|
||||
TXS, 154, 0
|
||||
32060 ! Two byte relative branches
|
||||
32070 DATA BCC, 400, 0, BCS, 432, 0, &
|
||||
BEQ, 496, 0, BMI, 304, 0, &
|
||||
BNE, 464, 0, BPL, 272, 0, &
|
||||
BVC, 336, 0, BVS, 368, 0
|
||||
32080 ! Three byte transfer
|
||||
32090 DATA JMP, 588, 0, JSR, 544, 0
|
||||
32100 ! Shifts and rotates
|
||||
32110 DATA ASL, 770, 0, LSR, 834, 0, &
|
||||
ROL, 802, 0, ROR, 866, 0
|
||||
32120 ! Accumulator
|
||||
32130 DATA ADC, 1121, 0, AND, 1057, 0, &
|
||||
CMP, 1217, 0, EOR, 1089, 0, &
|
||||
LDA, 1185, 0, ORA, 1025, 0, &
|
||||
SBC, 1249, 0, STA, 1153, 0
|
||||
32140 ! Bit test
|
||||
32150 DATA BIT, 1312, 0
|
||||
32160 ! Compare index
|
||||
32170 DATA CPX, 1760, 0, CPY, 1728, 0
|
||||
32180 ! Increment, Decrement
|
||||
32190 DATA DEC, 1986, 0, INC, 2018, 0
|
||||
32200 ! Index load
|
||||
32210 DATA LDX, 2206, 0, LDY, 2204, 0
|
||||
32220 ! Index store
|
||||
32230 DATA STX, 2434, 0, STY, 2432, 0
|
||||
32767 END
|
||||
BIN
micros/X65.TSK
Normal file
BIN
micros/X65.TSK
Normal file
Binary file not shown.
13
micros/X65BLD.COM
Normal file
13
micros/X65BLD.COM
Normal file
@ -0,0 +1,13 @@
|
||||
$! Command file to build X65.B2S (with Basic-Plus-2)
|
||||
$!
|
||||
$ set noOn
|
||||
$ run $bp2ic2
|
||||
SCALE 0
|
||||
OLD X65.B2S
|
||||
COMPILE X65/OBJECT/CHAIN/NODEBUG/NOCROSS/NOLIST/NOWARN
|
||||
BUILD X65
|
||||
SCRATCH
|
||||
EXIT
|
||||
$ tkb @X65
|
||||
$ del x65.odl, x65.obj, x65.cmd
|
||||
$ exit
|
||||
921
micros/X80.B2S
Normal file
921
micros/X80.B2S
Normal file
@ -0,0 +1,921 @@
|
||||
1000 REM &
|
||||
REM !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! &
|
||||
REM !! !! &
|
||||
REM !! 8080/8085 Cross Assembler !! &
|
||||
REM !! !!
|
||||
1010 REM !! A.G. Nicholson, Newcastle Uni . !! &
|
||||
REM !! !! &
|
||||
REM !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! &
|
||||
|
||||
1020 REM &
|
||||
REM ! Version of 12-May-80 &
|
||||
|
||||
1030 EXTEND
|
||||
1040 CCL.ENTRY%=0%
|
||||
1050 DIM SYMBOLS$(767%), &
|
||||
VALUES%(767%), &
|
||||
FLAGS%(767%), &
|
||||
SYMBOL.CHARS%(6%), &
|
||||
DELIMITER.TABLE%(3%)
|
||||
1060 ! -- Set up error trap routine --
|
||||
1070 ON ERROR GOTO 31020 &
|
||||
\ X$=SYS(CHR$(6%)+CHR$(-7%))
|
||||
1080 ! -- Initialise --
|
||||
1090 NUMBER.OF.SYMBOLS%=0% &
|
||||
\ SYMBOL.TABLE.SIZE%=768% &
|
||||
\ START.CPU.TIME%=TIME(1%) &
|
||||
\ LISTING.FILE$="KB:"
|
||||
1100 FOR I%=1% TO 97% &
|
||||
\ READ SYMBOL$,VALUE%,FLAG.WORD% &
|
||||
\ GOSUB 2310 &
|
||||
\ NEXT I% &
|
||||
! Read in opcodes
|
||||
1110 FLAG.WORD%=0% &
|
||||
\ FOR I%=1% TO 13% &
|
||||
\ READ SYMBOL$,VALUE% &
|
||||
\ GOSUB 2310 &
|
||||
\ NEXT I% &
|
||||
! Read in register definitions
|
||||
1120 ! -- Print header --
|
||||
1130 OPEN LISTING.FILE$ AS FILE 1% &
|
||||
\ GOTO 1180 IF CCL.ENTRY% &
|
||||
\ PRINT #1%,"8080/8085 Cross assembler" &
|
||||
\ PRINT #1%,"#";
|
||||
1140 ! &
|
||||
|
||||
1150 ! -- Get listing, source filenames --
|
||||
1160 INPUT LINE #1%, SOURCE.FILE$ &
|
||||
\ SOURCE.FILE$=CVT$$(SOURCE.FILE$,-1%)
|
||||
1170 ! -- Check for errors only switch --
|
||||
1180 ERRORS.ONLY.SWITCH%=-1% &
|
||||
\ I%=INSTR(1%,SOURCE.FILE$,"/E") &
|
||||
\ IF I% THEN SOURCE.FILE$=LEFT(SOURCE.FILE$,I%-1%)+ &
|
||||
RIGHT(SOURCE.FILE$,I%+2%) &
|
||||
\ ERRORS.ONLY.SWITCH%=0%
|
||||
1190 ! -- Check for symbol table listing switch --
|
||||
1200 SYMBOL.TABLE.LIST.FLAG%=INSTR(1%,SOURCE.FILE$,"/S") &
|
||||
\ IF SYMBOL.TABLE.LIST.FLAG% THEN SOURCE.FILE$= &
|
||||
LEFT(SOURCE.FILE$,SYMBOL.TABLE.LIST.FLAG%-1%)+ &
|
||||
RIGHT(SOURCE.FILE$,SYMBOL.TABLE.LIST.FLAG%+2%)
|
||||
1210 ! -- Check for object module output switch --
|
||||
1220 OBJECT.OUT.FLAG%=0% &
|
||||
\ I%=INSTR(1%,SOURCE.FILE$,"/O") &
|
||||
\ IF I% THEN SOURCE.FILE$=LEFT(SOURCE.FILE$,I%-1%)+ &
|
||||
RIGHT(SOURCE.FILE$,I%+2%) &
|
||||
\ OBJECT.OUT.FLAG%=-1%
|
||||
1230 ! -- Check for listing file and add default extensions --
|
||||
1240 LISTING.TO.FILE.FLAG%=INSTR(1%,SOURCE.FILE$,"=") &
|
||||
\ IF LISTING.TO.FILE.FLAG% THEN LISTING.FILE$= &
|
||||
LEFT(SOURCE.FILE$,LISTING.TO.FILE.FLAG%-1%) &
|
||||
\ LISTING.FILE$=LISTING.FILE$+".LST" UNLESS &
|
||||
INSTR(1%,LISTING.FILE$,".") &
|
||||
\ SOURCE.FILE$=RIGHT(SOURCE.FILE$, &
|
||||
LISTING.TO.FILE.FLAG%+1%)
|
||||
1250 SOURCE.FILE$=SOURCE.FILE$+".SRC" UNLESS &
|
||||
INSTR(1%,SOURCE.FILE$,".")
|
||||
1260 PRINT #1%,"Listing sent to "+ &
|
||||
LISTING.FILE$ IF LISTING.TO.FILE.FLAG%
|
||||
1270 IF OBJECT.OUT.FLAG% THEN OBJECT.FILE$= &
|
||||
LEFT(SOURCE.FILE$,INSTR(1%,SOURCE.FILE$,"."))+"HEX" &
|
||||
\ PRINT #1%,"Object module to ";OBJECT.FILE$
|
||||
1280 ! -- Get a unique workfile name --
|
||||
1290 WORK.FILE$="X80X"+MID(NUM$(100%+ASCII(SYS(CHR$(6%)+ &
|
||||
CHR$(9%)))/2%),3%,2%)+".TMP"
|
||||
1300 ! -- Commence assembly --
|
||||
1310 GOSUB 2010 &
|
||||
\ GOSUB 3010 &
|
||||
\ X%=1% &
|
||||
\ GOSUB 3720
|
||||
1320 ! -- Print symbol table --
|
||||
1330 GOSUB 3750 IF SYMBOL.TABLE.LIST.FLAG% &
|
||||
\ PRINT #1%
|
||||
1340 ! -- Finish up and exit --
|
||||
1350 CLOSE 1% &
|
||||
\ IF LISTING.TO.FILE.FLAG% THEN X%=0% &
|
||||
\ GOSUB 3720
|
||||
1360 PRINT "Runtime was";(TIME(1%)-START.CPU.TIME%)/10;"sec" &
|
||||
\ GOTO 32767
|
||||
1370 !
|
||||
2000 &
|
||||
! -- Pass 1 Driver routine -- &
|
||||
|
||||
2010 ERROR.COUNT%, &
|
||||
TOTAL.BYTES%, &
|
||||
LOCATION.COUNTER%, &
|
||||
ERROR.LINE.FLAG%, &
|
||||
OPCODE.TABLE.SUBSCRIPT%=0% &
|
||||
\ PASS.NUMBER%=1% &
|
||||
\ OPEN SOURCE.FILE$ FOR INPUT AS FILE 2% &
|
||||
\ OPEN WORK.FILE$ FOR OUTPUT AS FILE 3% &
|
||||
\ PRINT #1%,"Pass 1"
|
||||
2020 INPUT LINE #2%,SOURCE.LINE$ &
|
||||
\ SOURCE.LINE$=CVT$$(SOURCE.LINE$,421%) &
|
||||
\ LINE.LENGTH%=LEN(SOURCE.LINE$) &
|
||||
\ LINE.NUMBER%=LINE.NUMBER%+1%
|
||||
2030 IF LINE.LENGTH%=0% OR LEFT(SOURCE.LINE$,1%)="$" THEN &
|
||||
OPCODE.TABLE.SUBSCRIPT%=-1% &
|
||||
\ GOTO 2150
|
||||
2040 ! -- Scan source line --
|
||||
2050 GOSUB 2190 &
|
||||
\ GOSUB 2240
|
||||
2060 ! -- Comment line ? --
|
||||
2070 IF COMMENT.DELIMITER%=1% THEN &
|
||||
OPCODE.TABLE.SUBSCRIPT%=-1% &
|
||||
\ GOTO 2150
|
||||
2080 ! -- Get argument field --
|
||||
2090 IF COMMENT.DELIMITER% THEN ARGUMENT$= &
|
||||
CVT$$(MID(SOURCE.LINE$,OPCODE.DELIMITER%+1%, &
|
||||
COMMENT.DELIMITER%-OPCODE.DELIMITER%-1%),258%) &
|
||||
ELSE ARGUMENT$=CVT$$(RIGHT(SOURCE.LINE$,OPCODE.DELIMITER%+1%),258%)
|
||||
2100 ! -- Label ? --
|
||||
2110 IF LABEL.DELIMITER% THEN SYMBOL$= &
|
||||
CVT$$(LEFT(SOURCE.LINE$,LABEL.DELIMITER%-1%),128%) &
|
||||
\ VALUE%=LOCATION.COUNTER% &
|
||||
\ FLAG.WORD%=-2% &
|
||||
\ GOSUB 2310
|
||||
2120 ! -- Assignment ? --
|
||||
2130 IF EQU.DELIMITER% THEN GOSUB 2380 &
|
||||
ELSE GOSUB 2420
|
||||
2140 ! -- Write to workfile --
|
||||
2150 GOSUB 2460 &
|
||||
\ GOTO 2020 IF OPCODE.TABLE.SUBSCRIPT%=-1% &
|
||||
\ GOTO 2020 IF FLAGS%(OPCODE.TABLE.SUBSCRIPT%)<>10%
|
||||
2160 CLOSE 2%,3% &
|
||||
\ RETURN &
|
||||
! -- End of Pass 1
|
||||
2170 ! &
|
||||
|
||||
2180 &
|
||||
! -- Scan for strings in SOURCE.LINE$ -- &
|
||||
|
||||
2190 DELIMITER%=-1% &
|
||||
\ TEMP2%=0%
|
||||
2200 TEMP1%=INSTR(TEMP2%+1%,SOURCE.LINE$,"'") &
|
||||
\ RETURN UNLESS TEMP1%
|
||||
2210 TEMP2%=INSTR(TEMP1%+1%,SOURCE.LINE$,"'") &
|
||||
\ IF TEMP2% THEN DELIMITER%=DELIMITER%+1% &
|
||||
\ IF DELIMITER%<4% THEN DELIMITER.TABLE%(DELIMITER%)= &
|
||||
SWAP%(TEMP1% AND 255%) OR (TEMP2% AND 255%) &
|
||||
\ GOTO 2200
|
||||
2220 RETURN
|
||||
2230 &
|
||||
! -- Search for token delimiters -- &
|
||||
! LABEL.DELIMITER% Label &
|
||||
! OPCODE.DELIMITER% Opcode &
|
||||
! COMMENT.DELIMITER% Comment &
|
||||
! EQU.DELIMITER% Assignment &
|
||||
|
||||
2240 LABEL.DELIMITER%=INSTR(1%,SOURCE.LINE$,":") &
|
||||
\ LABEL.DELIMITER%=0% IF FNCHECK.SYNTAX%(LABEL.DELIMITER%) &
|
||||
\ COMMENT.DELIMITER%=0%
|
||||
2250 COMMENT.DELIMITER%=INSTR(COMMENT.DELIMITER%+1%,SOURCE.LINE$,";") &
|
||||
\ GOTO 2250 IF FNCHECK.SYNTAX%(COMMENT.DELIMITER%) &
|
||||
\ LABEL.DELIMITER%=0% IF (LABEL.DELIMITER%> &
|
||||
COMMENT.DELIMITER% AND COMMENT.DELIMITER%<>0%) &
|
||||
\ OPCODE.DELIMITER%=LABEL.DELIMITER%
|
||||
2260 OPCODE.DELIMITER%=OPCODE.DELIMITER%+1% &
|
||||
\ IF OPCODE.DELIMITER%>=LINE.LENGTH% THEN 2280 &
|
||||
ELSE X%=ASCII(RIGHT(SOURCE.LINE$,OPCODE.DELIMITER%)) &
|
||||
\ IF X%=9% OR X%=32% THEN 2260
|
||||
2270 OPCODE.DELIMITER%=OPCODE.DELIMITER%+1% &
|
||||
\ IF OPCODE.DELIMITER%<LINE.LENGTH% THEN &
|
||||
X%=ASCII(RIGHT(SOURCE.LINE$,OPCODE.DELIMITER%)) &
|
||||
\ IF X%<>9% AND X%<>32% THEN 2270 &
|
||||
ELSE OPCODE.DELIMITER%=OPCODE.DELIMITER%-1%
|
||||
2280 EQU.DELIMITER%=INSTR(1%,SOURCE.LINE$,"=") &
|
||||
\ EQU.DELIMITER%=0% IF FNCHECK.SYNTAX%(EQU.DELIMITER%) OR &
|
||||
(EQU.DELIMITER%>COMMENT.DELIMITER% AND &
|
||||
COMMENT.DELIMITER%<>0%) &
|
||||
\ OPCODE.DELIMITER%=EQU.DELIMITER% IF EQU.DELIMITER%
|
||||
2290 OPCODE.DELIMITER%=COMMENT.DELIMITER%-1% IF &
|
||||
(OPCODE.DELIMITER%>=COMMENT.DELIMITER% AND &
|
||||
COMMENT.DELIMITER%<>0%) &
|
||||
\ RETURN
|
||||
2300 &
|
||||
! Enter symbol SYMBOL$ into symbol table &
|
||||
! and its value VALUE% &
|
||||
|
||||
2310 IF NUMBER.OF.SYMBOLS%=SYMBOL.TABLE.SIZE% THEN &
|
||||
VALUE%=FNERROR.PRINT%("?X80 - FATAL: Symbol table overflow") &
|
||||
\ STOP &
|
||||
! Symbol table full
|
||||
2320 X%=ASCII(SYMBOL$) &
|
||||
\ IF X%<>46% AND ( X%<65% OR X%>90% ) THEN &
|
||||
VALUE%=FNERROR.PRINT%("Invalid symbol = "+SYMBOL$) &
|
||||
\ RETURN &
|
||||
! Invalid symbol
|
||||
2330 TEMP2%=FNHASH.SYMBOL%(SYMBOL$,SYMBOL.TABLE.SIZE%) &
|
||||
! Hash symbol
|
||||
2340 IF SYMBOLS$(TEMP2%)="" THEN SYMBOLS$(TEMP2%)=SYMBOL$ &
|
||||
\ VALUES%(TEMP2%)=VALUE% &
|
||||
\ FLAGS%(TEMP2%)=FLAG.WORD% &
|
||||
\ NUMBER.OF.SYMBOLS%=NUMBER.OF.SYMBOLS%+1% &
|
||||
\ RETURN &
|
||||
! If slot empty, enter symbol, value and flagword
|
||||
2350 IF SYMBOLS$(TEMP2%)=SYMBOL$ AND FLAGS%(TEMP2%)<0% THEN &
|
||||
VALUE%=FNERROR.PRINT%("Redefined symbol = "+SYMBOL$) &
|
||||
\ RETURN &
|
||||
! Multiple definition not allowed
|
||||
2360 TEMP2%=FNREHASH.SYMBOL%(TEMP2%,SYMBOL.TABLE.SIZE%) &
|
||||
\ GOTO 2340
|
||||
2370 &
|
||||
! -- Enter assignment -- &
|
||||
|
||||
2380 SYMBOL$=CVT$$(MID(SOURCE.LINE$,LABEL.DELIMITER%+1%, &
|
||||
EQU.DELIMITER%-LABEL.DELIMITER%-1%),136%) &
|
||||
\ VALUE%=FNEVALUATE.EXPR%(ARGUMENT$)
|
||||
2390 IF SYMBOL$="." THEN LOCATION.COUNTER%=VALUE% &
|
||||
ELSE IF SYMBOL$="" THEN VALUE%= &
|
||||
FNERROR.PRINT%("Missing symbol") &
|
||||
ELSE FLAG.WORD%=-1% &
|
||||
\ GOSUB 2310
|
||||
2400 OPCODE.TABLE.SUBSCRIPT%=-1% &
|
||||
\ RETURN
|
||||
2410 &
|
||||
! -- Get opcode subscript -- &
|
||||
|
||||
2420 OPCODE$=CVT$$(MID(SOURCE.LINE$,LABEL.DELIMITER%+1%, &
|
||||
OPCODE.DELIMITER%-LABEL.DELIMITER%),8%) &
|
||||
\ IF OPCODE$<>"" THEN OPCODE.TABLE.SUBSCRIPT%= &
|
||||
FNHASH.SYMBOL%(OPCODE$,SYMBOL.TABLE.SIZE%) &
|
||||
ELSE OPCODE.TABLE.SUBSCRIPT%=-1% \ RETURN
|
||||
2430 IF SYMBOLS$(OPCODE.TABLE.SUBSCRIPT%)=OPCODE$ THEN RETURN &
|
||||
ELSE IF FLAGS%(OPCODE.TABLE.SUBSCRIPT%)<0% OR &
|
||||
SYMBOLS$(OPCODE.TABLE.SUBSCRIPT%)="" THEN &
|
||||
OPCODE.TABLE.SUBSCRIPT%= &
|
||||
FNERROR.PRINT%("Invalid opcode = "+OPCODE$)-1% &
|
||||
ELSE OPCODE.TABLE.SUBSCRIPT%= &
|
||||
FNREHASH.SYMBOL%(OPCODE.TABLE.SUBSCRIPT%, &
|
||||
SYMBOL.TABLE.SIZE%) &
|
||||
\ GOTO 2430 &
|
||||
! Check for opcode match in the symbol table &
|
||||
! If flagword < 0 then report an error else rehash
|
||||
2440 RETURN
|
||||
2450 &
|
||||
! -- Get byte count and output to workfile -- &
|
||||
|
||||
2460 IF OPCODE.TABLE.SUBSCRIPT%=-1% THEN BYTE.COUNT%=0% &
|
||||
ELSE IF FLAGS%(OPCODE.TABLE.SUBSCRIPT%)>3% THEN &
|
||||
GOSUB 2500 &
|
||||
ELSE BYTE.COUNT%=FLAGS%(OPCODE.TABLE.SUBSCRIPT%) &
|
||||
! Get byte count into BYTE.COUNT%
|
||||
2470 PRINT #3%,LOCATION.COUNTER%;","; &
|
||||
BYTE.COUNT%;","; &
|
||||
OPCODE.TABLE.SUBSCRIPT%;","; &
|
||||
ERROR.LINE.FLAG% &
|
||||
\ PRINT #3%,ARGUMENT$ &
|
||||
\ TOTAL.BYTES%=TOTAL.BYTES%+BYTE.COUNT% &
|
||||
\ LOCATION.COUNTER%=LOCATION.COUNTER%+BYTE.COUNT% &
|
||||
\ ERROR.LINE.FLAG%=0% &
|
||||
\ RETURN
|
||||
2480 ! &
|
||||
|
||||
2490 &
|
||||
! -- Get byte count for pseudo-op -- &
|
||||
|
||||
2500 ON FLAGS%(OPCODE.TABLE.SUBSCRIPT%)-9% &
|
||||
GOTO 2590, 2520, 2520, 2520, &
|
||||
2540, 2540, 2540, 2590, &
|
||||
2570 &
|
||||
! .END .BYTE .DBYTE .WORD &
|
||||
! .ASCII .ASCIP .ASCIZ .LIST &
|
||||
! .BLKB
|
||||
2510 ! -- .BYTE, .DBYTE, .WORD --
|
||||
2520 TEMP1%=0% &
|
||||
\ TEMP2%=-1% &
|
||||
\ FOR BYTE.COUNT%=0% WHILE TEMP2% &
|
||||
\ TEMP1%,TEMP2%=INSTR(TEMP1%+1%,ARGUMENT$,",") &
|
||||
\ NEXT BYTE.COUNT% &
|
||||
\ BYTE.COUNT%=BYTE.COUNT%*2% IF FLAGS%(OPCODE.TABLE.SUBSCRIPT%)=12% &
|
||||
OR FLAGS%(OPCODE.TABLE.SUBSCRIPT%)=13% &
|
||||
\ RETURN
|
||||
2530 ! -- .ASCII, .ASCIP, .ASCIZ --
|
||||
2540 TEMP1%=INSTR(2%,ARGUMENT$,LEFT(ARGUMENT$,1%)) &
|
||||
\ IF TEMP1%=0% THEN OPCODE.TABLE.SUBSCRIPT%= &
|
||||
FNERROR.PRINT%("Missing delimiter")-1% &
|
||||
ELSE BYTE.COUNT%=TEMP1%-2%
|
||||
2550 BYTE.COUNT%=BYTE.COUNT%+1% IF FLAGS%(OPCODE.TABLE.SUBSCRIPT%)=16% &
|
||||
\ RETURN
|
||||
2560 ! -- .BLKB
|
||||
2570 BYTE.COUNT%=FNEVALUATE.EXPR%(ARGUMENT$) &
|
||||
\ RETURN
|
||||
2580 ! -- .LIST, END --
|
||||
2590 BYTE.COUNT%=0% &
|
||||
\ RETURN
|
||||
2600 ! &
|
||||
|
||||
3000 &
|
||||
! -- Pass 2 Driver routine -- &
|
||||
|
||||
3010 LINE.NUMBER%, &
|
||||
CHECKSUM%, &
|
||||
NEW.LINE.FLAG%=0% &
|
||||
\ PASS.NUMBER%=2% &
|
||||
\ LIST.FLAG%=-1% &
|
||||
\ PRINT #1%,"Pass 2" &
|
||||
\ CLOSE 1% &
|
||||
\ OPEN LISTING.FILE$ FOR OUTPUT AS FILE 1% &
|
||||
\ OPEN SOURCE.FILE$ FOR INPUT AS FILE 2% &
|
||||
\ OPEN WORK.FILE$ FOR INPUT AS FILE 3% &
|
||||
\ KILL WORK.FILE$
|
||||
3020 IF OBJECT.OUT.FLAG% THEN &
|
||||
OPEN OBJECT.FILE$ FOR OUTPUT AS FILE 4% &
|
||||
\ NEW.OBJ.LINE%=0%
|
||||
3030 IF ERRORS.ONLY.SWITCH% THEN PRINT #1%," Line Addr B1 B2 B3" &
|
||||
\ PRINT #1%
|
||||
3040 INPUT #3%,LOCATION.COUNTER%, &
|
||||
BYTE.COUNT%, &
|
||||
OPCODE.TABLE.SUBSCRIPT%, &
|
||||
ERROR.LINE.FLAG% &
|
||||
\ INPUT LINE #3%, ARGUMENT$ &
|
||||
\ ARGUMENT$=CVT$$(ARGUMENT$,4%) &
|
||||
\ INPUT LINE #2%, SOURCE.LINE$ &
|
||||
\ SOURCE.LINE$=CVT$$(SOURCE.LINE$,4%) &
|
||||
\ LINE.NUMBER%=LINE.NUMBER%+1%
|
||||
3050 ! -- Form object code and output to listing file --
|
||||
3060 IF LEFT(SOURCE.LINE$,1%)="$" THEN &
|
||||
SOURCE.LINE$=RIGHT(SOURCE.LINE$,2%)
|
||||
3070 IF OPCODE.TABLE.SUBSCRIPT%=-1% THEN GOSUB 3630 &
|
||||
\ GOTO 3040
|
||||
3080 IF FLAGS%(OPCODE.TABLE.SUBSCRIPT%)=10% THEN &
|
||||
GOSUB 3130 &
|
||||
\ RETURN
|
||||
3090 ADDRESS$=FNDEC.TO.HEX$(LOCATION.COUNTER%,0%) &
|
||||
\ VALUE%=VALUES%(OPCODE.TABLE.SUBSCRIPT%) &
|
||||
\ FLAG.WORD%=SWAP%(VALUE%) AND 255% &
|
||||
\ VALUE%=VALUE% AND 255%
|
||||
3100 IF FLAGS%(OPCODE.TABLE.SUBSCRIPT%)>3% THEN GOSUB 3370 &
|
||||
ELSE IF FLAG.WORD% THEN GOSUB 3170 &
|
||||
ELSE GOSUB 3540 &
|
||||
\ GOSUB 3630
|
||||
3110 GOTO 3040
|
||||
3120 &
|
||||
! -- End of assembly, tidy up -- &
|
||||
|
||||
3130 GOSUB 3630 &
|
||||
\ PRINT #4% IF OBJECT.OUT.FLAG%
|
||||
3140 CLOSE 2%,3%,4% &
|
||||
\ RETURN
|
||||
3150 ! &
|
||||
|
||||
3160 &
|
||||
! -- Process operands -- &
|
||||
|
||||
3170 FIRST.ARG.TYPE%=FLAG.WORD% AND 7% &
|
||||
\ SECOND.ARG.TYPE%=(FLAG.WORD% AND 56%)/8% &
|
||||
\ SHIFT.ARG.FLAG%=(FLAG.WORD% AND 192%)/64% &
|
||||
\ SHIFT.ARG.FLAG%=4% IF SHIFT.ARG.FLAG%=2%
|
||||
3180 ! -- If two operands evaluate the second into ARG2.VALUE%
|
||||
3190 IF SECOND.ARG.TYPE%=0% THEN ARG2.VALUE%=0% &
|
||||
ELSE TEMP2%=INSTR(1%,ARGUMENT$,",") &
|
||||
\ IF TEMP2%=0% THEN ARG2.VALUE%= &
|
||||
FNERROR.PRINT%("Missing operand") &
|
||||
ELSE ARG2.VALUE%=FNEVALUATE.ARGUMENT%( &
|
||||
RIGHT(ARGUMENT$,TEMP2%+1%),SECOND.ARG.TYPE%) &
|
||||
\ ARGUMENT$=LEFT(ARGUMENT$,TEMP2%-1%)
|
||||
3200 ! -- Evaluate the first (only) operand
|
||||
3210 ARG1.VALUE%=FNEVALUATE.ARGUMENT%(ARGUMENT$,FIRST.ARG.TYPE%)
|
||||
3220 ! -- If register , do appropriate shift and OR into opcode base
|
||||
3230 IF FIRST.ARG.TYPE%<4% OR FIRST.ARG.TYPE%=7% THEN &
|
||||
ARG1.VALUE%=ARG1.VALUE%*(2%^SHIFT.ARG.FLAG%) &
|
||||
\ VALUE%=VALUE% OR ARG1.VALUE%
|
||||
3240 IF SECOND.ARG.TYPE%<4% THEN VALUE%=VALUE% OR ARG2.VALUE% &
|
||||
! -- Assemble the bytes for this instruction
|
||||
3250 GOSUB 3540
|
||||
3260 IF SHIFT.ARG.FLAG%=1% THEN GOSUB 3330 &
|
||||
\ GOSUB 3560 &
|
||||
\ GOSUB 3630 &
|
||||
\ RETURN
|
||||
3270 IF SECOND.ARG.TYPE%=4% THEN FIRST.ARG.TYPE%=4% &
|
||||
\ ARG1.VALUE%=ARG2.VALUE%
|
||||
3280 IF FIRST.ARG.TYPE%=4% THEN VALUE%=ARG1.VALUE% &
|
||||
\ GOSUB 3560 &
|
||||
\ GOSUB 3630 &
|
||||
\ RETURN
|
||||
3290 IF SECOND.ARG.TYPE%=5% THEN FIRST.ARG.TYPE%=6% &
|
||||
\ ARG1.VALUE%=ARG2.VALUE%
|
||||
3300 IF FIRST.ARG.TYPE%=6% THEN VALUE%=ARG1.VALUE% &
|
||||
\ GOSUB 3560 &
|
||||
\ VALUE%=SWAP%(ARG1.VALUE%) &
|
||||
\ GOSUB 3580
|
||||
3310 GOSUB 3630 &
|
||||
\ RETURN
|
||||
3320 ! -- Z80 relative branches
|
||||
3330 VALUE%=ARG1.VALUE%-LOCATION.COUNTER%-2% &
|
||||
\ IF VALUE%<-128% OR VALUE%>127% THEN &
|
||||
VALUE%=FNERROR.PRINT%("Invalid displacement ="+NUM$(VALUE%))
|
||||
3340 RETURN
|
||||
3350 ! &
|
||||
|
||||
3360 &
|
||||
! -- Pseudo-ops. -- &
|
||||
|
||||
3370 ON FLAGS%(OPCODE.TABLE.SUBSCRIPT%)-9% &
|
||||
GOTO 3490, 3390, 3390, 3390, &
|
||||
3450, 3450, 3450, 3490, &
|
||||
3510 &
|
||||
! .END .BYTE .DBYTE .WORD &
|
||||
! .ASCII .ASCIP .ASCIZ .LIST &
|
||||
! .BLKB
|
||||
3380 ! -- .BYTE, .DBYTE, .WORD --
|
||||
3390 ARGUMENT$=ARGUMENT$+"," &
|
||||
\ TEMP3%=1% &
|
||||
\ TEMP3%=2% IF FLAGS%(OPCODE.TABLE.SUBSCRIPT%)=12% &
|
||||
OR FLAGS%(OPCODE.TABLE.SUBSCRIPT%)=13% &
|
||||
\ FOR I%=1% TO BYTE.COUNT% STEP TEMP3% &
|
||||
\ ADDRESS$=FNDEC.TO.HEX$(LOCATION.COUNTER%+I%-1%,0%) &
|
||||
\ TEMP1%=INSTR(1%,ARGUMENT$,",")
|
||||
3400 TEMP2%=FNEVALUATE.EXPR%(LEFT(ARGUMENT$,TEMP1%-1%)) &
|
||||
\ IF FLAGS%(OPCODE.TABLE.SUBSCRIPT%)=12% THEN &
|
||||
VALUE%=SWAP%(TEMP2%) &
|
||||
\ GOSUB 3540 &
|
||||
\ VALUE%=TEMP2% &
|
||||
\ GOSUB 3560
|
||||
3410 IF FLAGS%(OPCODE.TABLE.SUBSCRIPT%)=13% THEN &
|
||||
VALUE%=TEMP2% &
|
||||
\ GOSUB 3540 &
|
||||
\ VALUE%=SWAP%(TEMP2%) &
|
||||
\ GOSUB 3560
|
||||
3420 IF FLAGS%(OPCODE.TABLE.SUBSCRIPT%)=11% THEN &
|
||||
VALUE%=TEMP2% &
|
||||
\ GOSUB 3540
|
||||
3430 GOSUB 3630 &
|
||||
\ ARGUMENT$=RIGHT(ARGUMENT$,TEMP1%+1%) &
|
||||
\ NEXT I% &
|
||||
\ RETURN
|
||||
3440 ! -- .ASCII, .ASCIP, .ASCIZ --
|
||||
3450 ARGUMENT$=MID(ARGUMENT$,2%,BYTE.COUNT%) &
|
||||
\ ARGUMENT$=LEFT(ARGUMENT$,BYTE.COUNT%-1%)+CHR$(0%) &
|
||||
IF FLAGS%(OPCODE.TABLE.SUBSCRIPT%)=16% &
|
||||
\ FOR I%=1% TO BYTE.COUNT% STEP 3% &
|
||||
\ ADDRESS$=FNDEC.TO.HEX$(LOCATION.COUNTER%+I%-1%,0%) &
|
||||
\ VALUE%=FNCHAR%(I%) &
|
||||
\ GOSUB 3540 &
|
||||
\ VALUE%=FNCHAR%(I%+1%) &
|
||||
\ GOSUB 3560 IF I%+1%<=BYTE.COUNT% &
|
||||
\ VALUE%=FNCHAR%(I%+2%) &
|
||||
\ GOSUB 3580 IF I%+2%<=BYTE.COUNT% &
|
||||
\ GOSUB 3630 &
|
||||
\ NEXT I% &
|
||||
\ RETURN
|
||||
3460 ! -- Get character J% from ARGUMENT$
|
||||
3470 DEF* FNCHAR%(J%) &
|
||||
\ CHAR%=ASCII(MID(ARGUMENT$,J%,1%)) &
|
||||
\ CHAR%=CHAR% OR 128% IF FLAGS%(OPCODE.TABLE.SUBSCRIPT%)=15% &
|
||||
AND J%=BYTE.COUNT% &
|
||||
\ FNCHAR%=CHAR% &
|
||||
\ FNEND &
|
||||
|
||||
3480 ! -- .LIST --
|
||||
3490 LIST.FLAG%=FNEVALUATE.EXPR%(ARGUMENT$) &
|
||||
\ ADDRESS$="" &
|
||||
\ RETURN
|
||||
3500 ! -- .BLKB
|
||||
3510 TEMP1%=FNEVALUATE.EXPR%(ARGUMENT$) &
|
||||
\ IF OBJECT.OUT.FLAG% THEN VALUE%=0% &
|
||||
\ FOR X%=1% TO TEMP1% &
|
||||
\ GOSUB 3610 &
|
||||
\ NEXT X%
|
||||
3520 GOSUB 3630 &
|
||||
\ RETURN
|
||||
3530 &
|
||||
! -- Form B1 -- &
|
||||
|
||||
3540 BYTE1$=FNDEC.TO.HEX$(VALUE%,3%) &
|
||||
\ GOSUB 3610 &
|
||||
\ RETURN
|
||||
3550 &
|
||||
! -- Form B2 -- &
|
||||
|
||||
3560 BYTE2$=FNDEC.TO.HEX$(VALUE%,3%) &
|
||||
\ GOSUB 3610 &
|
||||
\ RETURN
|
||||
3570 &
|
||||
! -- Form B3 -- &
|
||||
|
||||
3580 BYTE3$=FNDEC.TO.HEX$(VALUE%,3%) &
|
||||
\ GOSUB 3610 &
|
||||
\ RETURN
|
||||
3590 ! &
|
||||
|
||||
3600 &
|
||||
! -- Output object and update checksum -- &
|
||||
|
||||
3610 OBJECT.BYTE%=VALUE% AND 255% &
|
||||
\ OBJECT.BYTE%=FNOBJECT.OUTPUT%(VALUE%) IF OBJECT.OUT.FLAG% &
|
||||
\ CHECKSUM%=CHECKSUM%+OBJECT.BYTE% &
|
||||
\ RETURN
|
||||
3620 &
|
||||
! -- Output assembled code to listing file -- &
|
||||
|
||||
3630 GOTO 3680 UNLESS ERRORS.ONLY.SWITCH% OR ERROR.LINE.FLAG%
|
||||
3640 IF ERROR.LINE.FLAG% THEN PRINT #1%,"?"; ELSE PRINT #1%," ";
|
||||
3650 IF NEW.LINE.FLAG%<LINE.NUMBER% THEN &
|
||||
PRINT #1% USING "#### ",LINE.NUMBER%; &
|
||||
ELSE PRINT #1%," ";
|
||||
3660 PRINT #1% USING"\ \ \\ \\ \\",ADDRESS$,BYTE1$,BYTE2$,BYTE3$; &
|
||||
\ IF LIST.FLAG% AND SOURCE.LINE$<>"" THEN &
|
||||
PRINT #1%,CHR$(9%);SOURCE.LINE$ &
|
||||
ELSE PRINT #1%
|
||||
3670 ! -- Set a flag, clear output strings --
|
||||
3680 NEW.LINE.FLAG%=LINE.NUMBER% &
|
||||
\ ADDRESS$,BYTE1$,BYTE2$,BYTE3$,SOURCE.LINE$="" &
|
||||
\ RETURN
|
||||
3690 &
|
||||
! -- Output binary byte to object file -- &
|
||||
|
||||
3700 DEF* FNOBJECT.OUTPUT%(X%) &
|
||||
\ OBJECT.BYTE%=X% AND 255% &
|
||||
\ PRINT #4%,FNDEC.TO.HEX$(OBJECT.BYTE%,3%); &
|
||||
\ NEW.OBJ.LINE%=NEW.OBJ.LINE%+1% &
|
||||
\ PRINT #4% IF (NEW.OBJ.LINE% AND 15%)=0% &
|
||||
\ FNOBJECT.OUTPUT%=OBJECT.BYTE% &
|
||||
\ FNEND
|
||||
3710 &
|
||||
! -- Print error count, checksum -- &
|
||||
|
||||
3720 PRINT #X% &
|
||||
\ PRINT #X%,"Errors detected ";FNDEC.TO.HEX$(ERROR.COUNT%,0%) &
|
||||
\ PRINT #X%,"Source checksum ";FNDEC.TO.HEX$(CHECKSUM%,0%) &
|
||||
\ PRINT #X%,"Total hex bytes ";FNDEC.TO.HEX$(TOTAL.BYTES%,0%) &
|
||||
\ PRINT #X% &
|
||||
\ RETURN
|
||||
3730 ! &
|
||||
|
||||
3740 &
|
||||
! -- Print sorted symbol table -- &
|
||||
|
||||
3750 TEMP1%,TEMP2%=0% &
|
||||
\ NUMBER.OF.SYMBOLS%=NUMBER.OF.SYMBOLS%-111% &
|
||||
\ RETURN IF NUMBER.OF.SYMBOLS%<0%
|
||||
3760 PRINT #1%," Symbol Table" &
|
||||
\ PRINT #1%
|
||||
3770 TEMP1%=TEMP1%+1% WHILE FLAGS%(TEMP1%)>=0% &
|
||||
\ SYMBOLS$(TEMP2%)=SYMBOLS$(TEMP1%) &
|
||||
\ VALUES%(TEMP2%)=VALUES%(TEMP1%) &
|
||||
\ FLAGS%(TEMP2%)=FLAGS%(TEMP1%) &
|
||||
\ TEMP2%=TEMP2%+1% &
|
||||
\ TEMP1%=TEMP1%+1% &
|
||||
\ GOTO 3770 UNLESS TEMP2%=NUMBER.OF.SYMBOLS%+1%
|
||||
3780 ! -- Quick sort the symbol table
|
||||
3790 TEMP1%=FNQUICKSORT%(0%,NUMBER.OF.SYMBOLS%,0%,NUMBER.OF.SYMBOLS%)
|
||||
3800 ! -- Output to listing file --
|
||||
3810 FOR I%=0% TO NUMBER.OF.SYMBOLS% &
|
||||
\ IF FLAGS%(I%)=-1% THEN S$="#" ELSE S$=" "
|
||||
3820 PRINT #1% USING " \ \ \ \ ", &
|
||||
SYMBOLS$(I%),FNDEC.TO.HEX$(VALUES%(I%),0%)+S$; &
|
||||
\ PRINT #1% IF CCPOS(1%)>63% &
|
||||
\ NEXT I%
|
||||
3830 PRINT #1% IF CCPOS(1%) &
|
||||
\ RETURN
|
||||
3840 &
|
||||
! -- Check position of char X% in SOURCE.LINE$ using tables &
|
||||
! -- DELIMITER%(). FNCHECK.SYNTAX%=-1% means in string &
|
||||
|
||||
3850 DEF* FNCHECK.SYNTAX%(X%)
|
||||
3860 GOTO 3880 IF DELIMITER%=-1% OR X%=0% &
|
||||
\ FOR X0%=0% TO DELIMITER% &
|
||||
\ GOTO 3880 IF X%<(SWAP%(DELIMITER.TABLE%(X0%)) AND 255%) &
|
||||
\ IF X%<(DELIMITER.TABLE%(X0%) AND 255%) THEN &
|
||||
FNCHECK.SYNTAX%=-1% &
|
||||
\ GOTO 3890
|
||||
3870 NEXT X0%
|
||||
3880 FNCHECK.SYNTAX%=0%
|
||||
3890 FNEND
|
||||
3900 ! &
|
||||
|
||||
4000 &
|
||||
! -- Evaluate the argument expression -- &
|
||||
|
||||
4010 DEF* FNEVALUATE.EXPR%(X$)
|
||||
4020 &
|
||||
! -- Main driver routine -- &
|
||||
|
||||
4030 EXPR$=X$ &
|
||||
\ GOSUB 4060 &
|
||||
\ GOSUB 4080 &
|
||||
\ EXP.VAL%=TERM%
|
||||
4040 GOTO 4290 UNLESS OP% &
|
||||
\ LAST.OP%=OP% &
|
||||
\ GOSUB 4060 &
|
||||
\ GOSUB 4080 &
|
||||
\ GOSUB 4190 &
|
||||
\ GOTO 4040
|
||||
4050 &
|
||||
REM ! -- Scan for the next operator { ! & % + * - / } -- &
|
||||
|
||||
4060 EXP.FLAG%=-1% &
|
||||
\ FOR TOK.PTR%=1% TO LEN(EXPR$) &
|
||||
\ TOK.CHR$=MID(EXPR$,TOK.PTR%,1%) &
|
||||
\ EXP.FLAG%= NOT EXP.FLAG% IF TOK.CHR$="'" &
|
||||
\ OP%=INSTR(1%,"!%&*+-/",TOK.CHR$) &
|
||||
\ RETURN IF OP% AND EXP.FLAG% &
|
||||
\ NEXT TOK.PTR% &
|
||||
\ OP%=0% &
|
||||
\ TOK.PTR%=TOK.PTR%+1% &
|
||||
\ RETURN
|
||||
4070 &
|
||||
! -- Get value of term -- &
|
||||
|
||||
4080 TERM$=LEFT(EXPR$,TOK.PTR%-1%) &
|
||||
\ EXPR$=RIGHT(EXPR$,TOK.PTR%+1%)
|
||||
4090 IF TERM$="" THEN TERM%=0% &
|
||||
\ RETURN
|
||||
4100 ! -- H() or L() ? --
|
||||
4110 TEMP1$=LEFT(TERM$,2%) &
|
||||
\ IF TEMP1$="H(" THEN EXP.FLAG%=1% &
|
||||
ELSE IF TEMP1$="L(" THEN EXP.FLAG%=2% &
|
||||
ELSE EXP.FLAG%=0%
|
||||
4120 IF EXP.FLAG% THEN IF RIGHT(TERM$,LEN(TERM$))=")" THEN &
|
||||
TERM$=MID(TERM$,3%,LEN(TERM$)-3%) &
|
||||
ELSE 4170
|
||||
4130 TEMP1$=LEFT(TERM$,1%)
|
||||
4140 IF TEMP1$>="A" AND TEMP1$<="Z" THEN TERM%=FNSYMBOL.LOOKUP%(TERM$) &
|
||||
ELSE IF TEMP1$="0" THEN TERM%=FNHEX.TO.DEC%(RIGHT(TERM$,2%)) &
|
||||
ELSE IF TEMP1$>="1" AND TEMP1$<="9" THEN TERM%=VAL(TERM$) &
|
||||
ELSE IF TEMP1$="'" THEN TERM%=ASCII(RIGHT(TERM$,2%)) &
|
||||
ELSE IF TEMP1$="^" THEN TERM%=FNOCT.TO.DEC%(RIGHT(TERM$,2%)) &
|
||||
ELSE IF TERM$="." THEN TERM%=LOCATION.COUNTER% &
|
||||
ELSE 4170
|
||||
4150 IF EXP.FLAG%=1% THEN TERM%=SWAP%(TERM%) AND 255% &
|
||||
ELSE IF EXP.FLAG%=2% THEN TERM%=TERM% AND 255%
|
||||
4160 RETURN
|
||||
4170 TERM%=FNERROR.PRINT%("Invalid term = "+TERM$) &
|
||||
\ RETURN
|
||||
4180 &
|
||||
! -- Carry out the arithmetic or logical operation -- &
|
||||
|
||||
4190 ON LAST.OP%+1% &
|
||||
GOTO 4270, 4200, 4210, 4220, &
|
||||
4230, 4240, 4250, 4260 &
|
||||
! or not and &
|
||||
! mult add sub div
|
||||
4200 EXP.VAL%=EXP.VAL% OR TERM% &
|
||||
\ RETURN &
|
||||
! or
|
||||
4210 EXP.VAL%=EXP.VAL%+(NOT TERM%) &
|
||||
\ RETURN &
|
||||
! not
|
||||
4220 EXP.VAL%=EXP.VAL% AND TERM% &
|
||||
\ RETURN &
|
||||
! and
|
||||
4230 EXP.VAL%=EXP.VAL%*TERM% &
|
||||
\ RETURN &
|
||||
! multiply
|
||||
4240 EXP.VAL%=EXP.VAL%+TERM% &
|
||||
\ RETURN &
|
||||
! add
|
||||
4250 EXP.VAL%=EXP.VAL%-TERM% &
|
||||
\ RETURN &
|
||||
! subtract
|
||||
4260 IF TERM%=0% THEN EXP.VAL%=FNERROR.PRINT%("Division by zero") &
|
||||
ELSE EXP.VAL%=EXP.VAL%/TERM%
|
||||
4270 RETURN
|
||||
4280 &
|
||||
! -- Exit with value of expression -- &
|
||||
|
||||
4290 FNEVALUATE.EXPR%=EXP.VAL%
|
||||
4300 FNEND
|
||||
4310 &
|
||||
! -- Find value of argument of the type TYPE% &
|
||||
|
||||
4320 DEF* FNEVALUATE.ARGUMENT%(X$,TYPE%) &
|
||||
\ EXP.VAL%=FNEVALUATE.EXPR%(X$)
|
||||
4330 IF TYPE%=1% AND (EXP.VAL%<0% OR EXP.VAL%>7%) THEN &
|
||||
EXP.VAL%=FNERROR.PRINT%("Invalid register id") &
|
||||
ELSE IF (TYPE%=2% AND EXP.VAL% AND 4%) OR &
|
||||
(TYPE%=3% AND EXP.VAL%>1%) THEN &
|
||||
EXP.VAL%=FNERROR.PRINT%("Invalid register pair") &
|
||||
ELSE IF TYPE%=7% AND (EXP.VAL%<0% OR EXP.VAL%>7%) &
|
||||
THEN EXP.VAL%=FNERROR.PRINT%("Invalid RST vector")
|
||||
4340 FNEVALUATE.ARGUMENT%=EXP.VAL% &
|
||||
\ FNEND
|
||||
4350 ! &
|
||||
|
||||
4360 &
|
||||
! -- Print the given error message to the listing file &
|
||||
|
||||
4370 DEF* FNERROR.PRINT%(X$) &
|
||||
\ PRINT #1%,"********";X$; &
|
||||
\ IF PASS.NUMBER%=1% THEN PRINT #1%," at line";LINE.NUMBER% &
|
||||
ELSE PRINT #1%
|
||||
4380 ERROR.COUNT%=ERROR.COUNT%+1% &
|
||||
\ ERROR.LINE.FLAG%=-1% &
|
||||
\ FNERROR.PRINT%=0% &
|
||||
\ FNEND
|
||||
4390 &
|
||||
! -- Look up value of symbol -- &
|
||||
|
||||
4400 DEF* FNSYMBOL.LOOKUP%(SYMBOL$) &
|
||||
\ X%=FNHASH.SYMBOL%(SYMBOL$,SYMBOL.TABLE.SIZE%)
|
||||
4410 IF SYMBOLS$(X%)=SYMBOL$ AND FLAGS%(X%)<=0% THEN &
|
||||
FNSYMBOL.LOOKUP%=VALUES%(X%) &
|
||||
ELSE IF SYMBOLS$(X%)="" THEN FNSYMBOL.LOOKUP%= &
|
||||
FNERROR.PRINT%("Undefined symbol = "+SYMBOL$) &
|
||||
ELSE X%=FNREHASH.SYMBOL%(X%,SYMBOL.TABLE.SIZE%) &
|
||||
\ GOTO 4410
|
||||
4420 FNEND
|
||||
4430 &
|
||||
! -- Dec to Hex conversion -- &
|
||||
|
||||
4440 DEF* FNDEC.TO.HEX$(X%,D%)
|
||||
4450 X$="" &
|
||||
\ FOR X1%=0% TO 3% &
|
||||
\ X0%=(X% AND (16%^(X1%+1%)-1%*(16%^X1%)))/(16%^X1%) &
|
||||
\ X0%=X0%+16% IF X0%<0% &
|
||||
\ X$=CHR$(48%+X0%)+X$ IF X0%<10% &
|
||||
\ X$=CHR$(55%+X0%)+X$ IF X0%>9% &
|
||||
\ NEXT X1% &
|
||||
\ IF D% THEN X$=MID(X$,D%,2%)
|
||||
4460 FNDEC.TO.HEX$=X$
|
||||
4470 FNEND
|
||||
4480 &
|
||||
! -- Hex to Dec conversion -- &
|
||||
|
||||
4490 DEF* FNHEX.TO.DEC%(X$) &
|
||||
\ X0%=0% &
|
||||
\ FOR X1%=1% TO LEN(X$) &
|
||||
\ X2%=ASCII(MID(X$,X1%,1%)) &
|
||||
\ IF X2%<48% OR (X2%>57% AND X2%<65%) OR X2%>70% THEN &
|
||||
FNHEX.TO.DEC%=FNERROR.PRINT%("Invalid HEX constant = "+X$) &
|
||||
\ GOTO 4510
|
||||
4500 X2%=X2%-48% &
|
||||
\ X2%=X2%-7% IF X2%>9% &
|
||||
\ X0%=X2%+X0%*16% &
|
||||
\ NEXT X1% &
|
||||
\ FNHEX.TO.DEC%=X0%
|
||||
4510 FNEND
|
||||
4520 &
|
||||
! -- Octal to Dec conversion -- &
|
||||
|
||||
4530 DEF* FNOCT.TO.DEC%(X$) &
|
||||
\ X0%=0% &
|
||||
\ FOR X1%=1% TO LEN(X$) &
|
||||
\ X2%=ASCII(MID(X$,X1%,1%))-48% &
|
||||
\ IF X2%<0% OR X2%>7% THEN &
|
||||
FNOCT.TO.DEC%=FNERROR.PRINT%("Invalid OCTAL constant = "+X$) &
|
||||
\ GOTO 4550
|
||||
4540 X0%=X0%*8% + X2% &
|
||||
\ NEXT X1% &
|
||||
\ FNOCT.TO.DEC%=X0%
|
||||
4550 FNEND
|
||||
4560 &
|
||||
! -- Calculate X1% modulo X2% -- &
|
||||
|
||||
4570 DEF* FNMOD%(X1%,X2%) &
|
||||
\ X1%=X1%-(X1%/X2%)*X2% &
|
||||
\ X1%=X1%+X2% IF X1%<0% &
|
||||
\ FNMOD%=X1% &
|
||||
\ FNEND
|
||||
4580 &
|
||||
! -- Hash symbol X$, modulo SYMBOL.TABLE.SIZE% -- &
|
||||
|
||||
4590 DEF* FNHASH.SYMBOL%(SYMBOL$,M%) &
|
||||
\ SYMBOL$=LEFT(SYMBOL$+" ",6%) &
|
||||
\ CHANGE SYMBOL$ TO SYMBOL.CHARS% &
|
||||
\ SYMBOL.CHARS%(X%)=SYMBOL.CHARS%(X%)-48% FOR X%=1% TO 6% &
|
||||
\ FNHASH.SYMBOL%=FNMOD%(SYMBOL.CHARS%(1%)*23%+ &
|
||||
SYMBOL.CHARS%(2%)*19%+SYMBOL.CHARS%(3%)*17%+ &
|
||||
SYMBOL.CHARS%(4%)*13%+SYMBOL.CHARS%(5%)*11%+ &
|
||||
SYMBOL.CHARS%(6%)*7%,M%) &
|
||||
\ FNEND
|
||||
4600 &
|
||||
! -- Rehash function, modulo X2% &
|
||||
|
||||
4610 DEF* FNREHASH.SYMBOL%(X1%,X2%)=FNMOD%(X1%+23%,X2%)
|
||||
4620 &
|
||||
! -- Quick sort symbol table &
|
||||
|
||||
4630 DEF* FNQUICKSORT%(LOW%,HIGH%,I%,J%) &
|
||||
\ I%=LOW% &
|
||||
\ J%=HIGH% &
|
||||
\ X$=SYMBOLS$((HIGH%+LOW%)/2%)
|
||||
4640 I%=I%+1% WHILE SYMBOLS$(I%)<X$
|
||||
4650 J%=J%-1% WHILE X$<SYMBOLS$(J%)
|
||||
4660 IF I%>J% THEN 4680 &
|
||||
ELSE IF I%<>J% THEN VALUE%=VALUES%(I%) &
|
||||
\ FLAG.WORD%=FLAGS%(I%) &
|
||||
\ SYMBOL$=SYMBOLS$(I%) &
|
||||
\ VALUES%(I%)=VALUES%(J%) &
|
||||
\ FLAGS%(I%)=FLAGS%(J%) &
|
||||
\ SYMBOLS$(I%)=SYMBOLS$(J%) &
|
||||
\ VALUES%(J%)=VALUE% &
|
||||
\ FLAGS%(J%)=FLAG.WORD% &
|
||||
\ SYMBOLS$(J%)=SYMBOL$
|
||||
4670 I%=I%+1% &
|
||||
\ J%=J%-1% &
|
||||
\ IF I%<=J% THEN 4640
|
||||
4680 IF LOW%<J% THEN TEMP1%=FNQUICKSORT%(LOW%,J%,LOW%,J%)
|
||||
4690 IF I%<HIGH% THEN TEMP1%=FNQUICKSORT%(I%,HIGH%,I%,HIGH%)
|
||||
4700 FNQUICKSORT%=-1% &
|
||||
\ FNEND
|
||||
4710 ! &
|
||||
|
||||
30000 &
|
||||
! CCL Entry point &
|
||||
|
||||
30010 SOURCE.FILE$=CVT$$(SYS(CHR$(7%)),188%) &
|
||||
\ I%=INSTR(1%,SOURCE.FILE$,"X80") &
|
||||
\ IF I% THEN SOURCE.FILE$=RIGHT(SOURCE.FILE$,4%) &
|
||||
ELSE PRINT "?X80 - Illegal entry" &
|
||||
\ GOTO 32767
|
||||
30020 IF SOURCE.FILE$<>"" THEN CCL.ENTRY%=-1% ELSE CCL.ENTRY%=0%
|
||||
30030 GOTO 1070
|
||||
30999 ! &
|
||||
|
||||
31000 &
|
||||
! -- Error routine -- &
|
||||
|
||||
31010 ! -- No ".END" --
|
||||
31020 IF ERR=11% AND ERL=2020% THEN OPCODE.TABLE.SUBSCRIPT%= &
|
||||
FNERROR.PRINT%("Missing .END")+ &
|
||||
FNHASH.SYMBOL%(".END",SYMBOL.TABLE.SIZE%) &
|
||||
\ SOURCE.LINE$="" &
|
||||
\ RESUME 2150
|
||||
31030 IF ERR=11% AND ERL=3040% THEN SOURCE.LINE$="" &
|
||||
\ OPCODE.TABLE.SUBSCRIPT%=FNHASH.SYMBOL%(".END", &
|
||||
SYMBOL.TABLE.SIZE%) &
|
||||
\ RESUME 3080
|
||||
31040 ! -- ^Z at filename request --
|
||||
31050 RESUME 32767 IF ERL=1160%
|
||||
31060 ! -- Illegal number in FNEVALUATE.EXPR%() --
|
||||
31070 IF ERR=51% AND ERL=4140% THEN X0%=VAL(TERM$)-65536 &
|
||||
\ RESUME 4150
|
||||
31080 RESUME 4170 IF ERR=52% AND ERL=4140%
|
||||
31090 CLOSE 1%,2%,3%,4% &
|
||||
\ RESUME 32767% IF ERR=28%
|
||||
31100 ! -- Print any unanticipated error --
|
||||
31110 ON ERROR GOTO 0
|
||||
31999 ! &
|
||||
|
||||
32000 &
|
||||
! -- Opcode data &
|
||||
|
||||
32010 ! Table is of the form: &
|
||||
! SYMBOL,value,byte count &
|
||||
! where: the low byte of value is the opcode base &
|
||||
! and the high byte a flag consisting of &
|
||||
! bits 15,14 a shift flag 0=none,2=four,3=three &
|
||||
! bits 13-11,10-8 are arg2, arg1 types &
|
||||
! 0-none, 1-register, 2-register pair, &
|
||||
! 3-limited register pair, 4-data byte, &
|
||||
! 5-data word, 6-address and 7-for RST
|
||||
32020 DATA .END, 0, 10, .BYTE, 0, 11, &
|
||||
.DBYTE, 0, 12, .WORD, 0, 13, &
|
||||
.ASCII, 0, 14, .ASCIP, 0, 15, &
|
||||
.ASCIZ, 0, 16, .LIST, 0, 17, &
|
||||
.BLKB, 0, 18
|
||||
32030 DATA CALL, 1741, 3, CC, 1756, 3, &
|
||||
CM, 1788, 3, CNC, 1748, 3, &
|
||||
CNZ, 1732, 3, CP, 1780, 3, &
|
||||
CPE, 1772, 3, CPO, 1764, 3, &
|
||||
CZ, 1740, 3
|
||||
32040 DATA JC, 1754, 3, JM, 1786, 3, &
|
||||
JMP, 1731, 3, JNC, 1746, 3, &
|
||||
JNZ, 1730, 3, JP, 1778, 3, &
|
||||
JPE, 1770, 3, JPO, 1762, 3, &
|
||||
JZ, 1738, 3
|
||||
32050 DATA LDA, 1594, 3, LHLD, 1578, 3, &
|
||||
SHLD, 1570, 3, STA, 1586, 3, &
|
||||
LXI, -22015, 3
|
||||
32060 DATA ACI, 1230, 2, ADI, 1222, 2, &
|
||||
ANI, 1254, 2, CPI, 1278, 2, &
|
||||
ORI, 1270, 2, SBI, 1246, 2, &
|
||||
SUI, 1238, 2, XRI, 1262, 2, &
|
||||
IN, 1243, 2, OUT, 1235, 2, &
|
||||
MVI, -7930, 2
|
||||
32070 DATA DJNZ, 17936, 2, JR, 17944, 2, &
|
||||
JRNZ, 17952, 2, JRZ, 17960, 2, &
|
||||
JRNC, 17968, 2, JRC, 17976, 2
|
||||
32080 DATA ADC, 392, 1, ADD, 384, 1, &
|
||||
ANA, 416, 1, CMP, 440, 1, &
|
||||
ORA, 432, 1, SBB, 408, 1, &
|
||||
SUB, 400, 1, XRA, 424, 1, &
|
||||
DAD, -32247, 1, DCX, -32245, 1, &
|
||||
INX, -32253, 1, POP, -32063, 1, &
|
||||
PUSH, -32059, 1
|
||||
32090 DATA DCR, -16123, 1, INR, -16124, 1, &
|
||||
LDAX, -31990, 1, STAX, -31998, 1, &
|
||||
MOV, -14016, 1, RST, -14393, 1
|
||||
32100 DATA CMA, 47, 1, CMC, 63, 1, &
|
||||
DAA, 39, 1, EI, 251, 1, &
|
||||
HLT, 118, 1, NOP, 0, 1, &
|
||||
DI, 243, 1, PCHL, 233, 1, &
|
||||
RAL, 23, 1, RAR, 31, 1, &
|
||||
RC, 216, 1, RET, 201, 1, &
|
||||
RLC, 7, 1, RM, 248, 1, &
|
||||
RNC, 208, 1, RNZ, 192, 1, &
|
||||
RP, 240, 1, RPE, 232, 1, &
|
||||
RPO, 224, 1, RRC, 15, 1, &
|
||||
RZ, 200, 1, SPHL, 249, 1, &
|
||||
STC, 55, 1, XCHG, 235, 1, &
|
||||
XTHL, 227, 1
|
||||
32110 DATA RIM, 32, 1, SIM, 48, 1, &
|
||||
EXX, 217, 1, EXAF, 8, 1
|
||||
32120 !--Register symbol definitions
|
||||
32130 DATA B, 0, C, 1, D, 2, &
|
||||
E, 3, H, 4, L, 5, &
|
||||
M, 6, A, 7, BC, 0, &
|
||||
DE, 1, HL, 2, SP, 3, &
|
||||
PSW, 3
|
||||
32767 END
|
||||
221
micros/X80.HLP
Normal file
221
micros/X80.HLP
Normal file
@ -0,0 +1,221 @@
|
||||
|
||||
Cross Assembler for 8080/8085 A.G. Nicholson
|
||||
----------------------------------------------
|
||||
To enable users of 8080 based systems to quickly develop
|
||||
their application programs - by eliminating the tedious task of
|
||||
hand assembling, I have written a cross assembler for the use of
|
||||
interested persons.
|
||||
The cross assembler is written in DEC's Basic-plus(I) and is
|
||||
available for use on a PDP-11 series processor using the RSTS/E
|
||||
( V06B onwards ) operating system.
|
||||
The following describes some of its features and gives the
|
||||
operating procedure using RSTS/E.
|
||||
|
||||
* General features :-
|
||||
Input to the assembler consists of lines of mnemonics which
|
||||
have the general form :-
|
||||
|
||||
label: opcode argument(s) ; comments
|
||||
|
||||
Each of these lines is formed according to the following
|
||||
syntax rules :-
|
||||
|
||||
1) The label (if any) consists of up to six alphanumeric
|
||||
characters, the first of which must be alphabetic,
|
||||
followed by a colon ":". (eg: "LOOP:")
|
||||
2) The opcode (instruction or assembler mnemonic) must
|
||||
be followed by at least one space or tab character if
|
||||
an argument is to be present. Standard mnemonics are
|
||||
used.
|
||||
|
||||
3) The argument (if required) consists of a valid
|
||||
expression, the form of which is determined by the
|
||||
opcode. For 8080/8085 instructions, these are :-
|
||||
|
||||
a/ Input/Output instructions
|
||||
(IN,OUT)
|
||||
dev
|
||||
(eg: "IN 0FB" )
|
||||
|
||||
b/ Primary memory reference
|
||||
(LDAX,STAX)
|
||||
rp
|
||||
(LDA,STA,LHLD,SHLD)
|
||||
addr
|
||||
(eg: "LHLD COUNT")
|
||||
|
||||
c/ Immediate
|
||||
(LXI rp,data16
|
||||
MVI reg,data )
|
||||
(eg: "LXI HL,0" )
|
||||
|
||||
d/ Jumps
|
||||
(JMP,JC,JNC,JZ,JNZ,JP,JM,JPE,JPO)
|
||||
addr
|
||||
( eg: "JMP LOOP" )
|
||||
(PCHL)
|
||||
|
||||
e/ Calls and returns
|
||||
(CALL,CC,CNC,CZ,CNZ,CP,CM,CPE,CPO)
|
||||
addr
|
||||
(eg: "CNC SUBR" )
|
||||
(RET,RC,RNC,RZ,RNZ,RP,RM,RPE,RPO)
|
||||
f/ Immediate operate
|
||||
(ADI,ACI,SUI,SBI,ANI,XRI,ORI,CPI)
|
||||
data
|
||||
( eg: "CPI 1" )
|
||||
|
||||
g/ Move
|
||||
( MOV reg,reg )
|
||||
( eg: "MOV B,A" )
|
||||
|
||||
h/ Accumulator
|
||||
(ADD,ADC,SUB,SBB,ANA,XRA,ORA,CMP)
|
||||
reg
|
||||
( eg: "ADD M" )
|
||||
(DAD rp)
|
||||
( eg: "DAD HL" )
|
||||
|
||||
i/ Register operate
|
||||
(INR,DCR)
|
||||
reg
|
||||
( eg: "DCR B" )
|
||||
(INX,DCX)
|
||||
rp
|
||||
( eg: "DCX DE" )
|
||||
(CMA,DAA,RLC,RRC,RAL,RAR)
|
||||
|
||||
j/ Stack
|
||||
(PUSH,POP)
|
||||
rp
|
||||
( eg: "PUSH BC" )
|
||||
|
||||
k/ Interrupt
|
||||
( RST n )
|
||||
( eg: "RST 7" )
|
||||
(EI,DI)
|
||||
and l/ Miscellaneous
|
||||
|
||||
Also included are the Z80 relative branches and exchange
|
||||
instructions.
|
||||
(JR,JRNZ,JRZ,JRNC,JRC)
|
||||
( eg: "JRNZ LOOP6" )
|
||||
(EXX,EXAF)
|
||||
|
||||
Where :-
|
||||
data,addr,data16 are arithmetic or logical expressions
|
||||
consisting of numeric constants and / or
|
||||
the operators :-
|
||||
! logical OR
|
||||
% logical NOT
|
||||
& logical AND
|
||||
* multiplication
|
||||
+ addition
|
||||
- subtraction
|
||||
/ integer division
|
||||
H( ) high order byte
|
||||
L( ) low order byte
|
||||
|
||||
Expressions are evaluated from left to
|
||||
right, and may not contain parentheses.
|
||||
|
||||
reg is one of the 8 bit registers (A,B,C,D,E,H,L,M)
|
||||
|
||||
rp is one of the register pairs (BC,DE,HL,SP,PSW)
|
||||
|
||||
n is a restart vector ( 0 to 7 )
|
||||
|
||||
Some argument examples are :-
|
||||
|
||||
03E the hexadecimal constant "3E"
|
||||
^377 the octal constant "377"
|
||||
'D' the ascii value of "D"
|
||||
-120 the decimal integer constant
|
||||
"-120". (the range allowed is
|
||||
-32768 to +32767)
|
||||
L(ADDR)-1 the low order byte of the symbol
|
||||
"ADDR", minus 1.
|
||||
|
||||
The currently available assembler directives are :-
|
||||
|
||||
i) .BYTE or assigns the byte or double byte
|
||||
.DBYTE or expressions given in the argu-
|
||||
.WORD ment to current sequential addr-
|
||||
esses. '.WORD' allocates two bytes
|
||||
in 8080 address format, low byte
|
||||
followed by the high byte.
|
||||
(eg: ".BYTE 0F,LABEL,'A'")
|
||||
|
||||
ii) = assigns to the symbol on its
|
||||
left the value of the expression
|
||||
on its right.
|
||||
(eg: "VALUE=OFFSET-START+1")
|
||||
|
||||
A period "." is a special symbol
|
||||
used to specify the location
|
||||
counter.
|
||||
(eg: " .=01C0 ; start addr")
|
||||
|
||||
iii) .ASCII translates the character string
|
||||
.ASCIP argument to ascii ( with parity
|
||||
set on the last character in the
|
||||
case of .ASCIP ) and assigns
|
||||
these values to the current
|
||||
sequential address(es).
|
||||
(eg: ".ASCII 'TEXT STRING'" )
|
||||
|
||||
iv) .LIST to enable/disable the listing of
|
||||
the source program in assembler
|
||||
output. If the value of the expr
|
||||
given is zero, the listing is
|
||||
disabled, else it is enabled.
|
||||
(eg: ".LIST 0 ; no list")
|
||||
|
||||
v) .BLKB reserves the number of bytes
|
||||
given in the argument expression
|
||||
(eg: ".BLKB 0100 ; buffer area")
|
||||
|
||||
vi) .END to tell the assembler it has
|
||||
reached the end of your source
|
||||
program. This statement must
|
||||
be included as the last line of
|
||||
source.
|
||||
|
||||
4) The (optional) comments are proceeded by a semi-colon
|
||||
";" and may contain any other character. The label,
|
||||
opcode and argument fields may be omitted for a
|
||||
comment line. A line with a dollar "$" sign as the
|
||||
first character is treated as a comment line and
|
||||
is printed to the listing file minus the "$" sign.
|
||||
|
||||
* Use of assembler on RSTS/E :-
|
||||
|
||||
After logging on to the system, perform the following steps :-
|
||||
|
||||
(1) Enter the source program into a file on the system
|
||||
using the $PIP or $EDIT programs or the "CREATE" command
|
||||
|
||||
(2) Run the cross assembler by typing "RUN !X80",
|
||||
responding to the "#" sign with a command string of the
|
||||
form: eg: LIST=PROG/switch(es)
|
||||
which directs the listing to the file "LIST.LST" from the
|
||||
source file "PROG. SRC". The switch(es) are optional but
|
||||
/E specifies an errors only listing
|
||||
/O specifies an object module output, in the format
|
||||
of a hexadecimal dump in ASCII, 16 bytes/line.
|
||||
(this is useful for later punching of paper tape)
|
||||
/S specifies that the sorted symbol table be printed.
|
||||
Only specifying the source file ( eg: PROG ) causes all
|
||||
output to the user's terminal.
|
||||
|
||||
(3) If any errors are detected, it is neccessary to edit
|
||||
the source file using the $EDIT program or the "EDIT"
|
||||
command, and repeat step 2 above until no errors are
|
||||
detected.
|
||||
|
||||
Any queries ? - don't hesitate to contact Tony Nicholson c/o
|
||||
Electrical Engineering Department, for advice or help with your
|
||||
problems regarding the cross assembler. You might also want to
|
||||
attend on the second and fourth Mondays of the month in Physics
|
||||
building room G12 at 7pm, when the Newcastle Microcomputer Club
|
||||
meets.
|
||||
BIN
micros/X80.TSK
Normal file
BIN
micros/X80.TSK
Normal file
Binary file not shown.
13
micros/X80BLD.COM
Normal file
13
micros/X80BLD.COM
Normal file
@ -0,0 +1,13 @@
|
||||
$! Command file to build X80.B2S (with Basic-Plus-2)
|
||||
$!
|
||||
$ set noOn
|
||||
$ run $bp2ic2
|
||||
SCALE 0
|
||||
OLD X80.B2S
|
||||
COMPILE X80/OBJECT/CHAIN/NODEBUG/NOCROSS/NOLIST/NOWARN
|
||||
BUILD X80
|
||||
SCRATCH
|
||||
EXIT
|
||||
$ tkb @X80
|
||||
$ del x80.odl, x80.obj, x80.cmd
|
||||
$ exit
|
||||
Loading…
x
Reference in New Issue
Block a user