mirror of https://github.com/dschmenk/VM02.git
1 line
9.2 KiB
Plaintext
Executable File
1 line
9.2 KiB
Plaintext
Executable File
CONST FALSE = 0
|
|
CONST TRUE = NOT FALSE
|
|
CONST OK = 0
|
|
CONST ERROR = -1
|
|
CONST INPUTSTR = $01FF
|
|
CONST INBUFF = $0800
|
|
CONST OUTBUFF = $0C00
|
|
CONST SYMTABLE = $B000
|
|
CONST SYMSIZE = $0A00
|
|
CONST DATABUFF = $A000
|
|
WORD NEXTENTRY = SYMTABLE
|
|
BYTE PLASMASTR[] = "PLASMA LINKER 0.8"
|
|
BYTE NULLSTR[] = ""
|
|
BYTE BADMODSTR[] = "MODULE NOT FOUND"
|
|
BYTE ASMADR[] = "ASM ADDRESS: $"
|
|
BYTE LOADADR[] = "LOAD ADDRESS: $"
|
|
BYTE DATASZ[] = "DATA SIZE: $"
|
|
BYTE RELOFSTSTR[] = "REL OFFSET: $"
|
|
BYTE FIX16STR[] = "FIXUP 16-BIT ADDRESS: $"
|
|
BYTE FIX8STR[] = "FIXUP 8-BIT ADDRESS: $"
|
|
BYTE RLDLBL[] = "RELOCATION DIRECTORY:"
|
|
BYTE ESDLBL[] = "SYMBOL TABLE:"
|
|
BYTE MATCHEXTRNSTR = "MATCH EXTRN: "
|
|
BYTE INPUTFILESTR = "INPUT FILE"
|
|
BYTE OUTPUTFILESTR = "OUTPUT FILE"
|
|
BYTE ERROUTSTR = "ERROR CREATING OUTPUT FILE"
|
|
BYTE PRESSANYKEY[] = "PRESS ANY KEY TO CONTINUE..."
|
|
BYTE MODCOUNT, MODI
|
|
BYTE BINREF, BINTYPE
|
|
WORD MODBUFF,MODLEN,MODADDR,LINKADDR
|
|
BYTE MODFILES[170]
|
|
BYTE PERR
|
|
;
|
|
; SYMBOL TABLE TYPE CONSTANTS
|
|
;
|
|
CONST LOBYTE_TYPE = $01
|
|
CONST HIBYTE_TYPE = $02
|
|
CONST WORD_TYPE = $03
|
|
CONST FUNC_TYPE = $04
|
|
CONST CONST_TYPE = $08
|
|
;
|
|
; CONVERT CHARACTER TO UPPER CASE (AND STRIP MSB)
|
|
;
|
|
DEF TOUPPER(CH)
|
|
|
|
CH = CH & $7F
|
|
IF CH >= 'a' AND CH <= 'z'
|
|
CH = CH - $20
|
|
FIN
|
|
RETURN CH
|
|
END
|
|
DEF CROUT
|
|
COUT($0D)
|
|
END
|
|
DEF BADMOD
|
|
PRSTR(@BADMODSTR)
|
|
CROUT()
|
|
END
|
|
DEF PRBYTE(VAL)
|
|
DROP ROMCALL(VAL, 0, 0, 0, $FDDA)
|
|
END
|
|
DEF PRWORD(VAL)
|
|
DROP ROMCALL(VAL >> 8, VAL, 0, 0, $F941)
|
|
END
|
|
;
|
|
; BASIC FILE I/O
|
|
;
|
|
DEF GETFILEINFO(PATH, INFOPTR)
|
|
BYTE PARAMS[18]
|
|
|
|
PARAMS.0 = 10
|
|
PARAMS:1 = PATH
|
|
PERR = SYSCALL($C4, @PARAMS)
|
|
IF NOT PERR
|
|
MEMCPY(@PARAMS.3, INFOPTR, 15)
|
|
FIN
|
|
RETURN PERR
|
|
END
|
|
DEF DESTROY(PATH)
|
|
BYTE PARAMS[3]
|
|
|
|
PARAMS.0 = 1
|
|
PARAMS:1 = PATH
|
|
PERR = SYSCALL($C1, @PARAMS)
|
|
RETURN PERR
|
|
END
|
|
DEF CREATE(PATH, ACCESS, TYPE, AUX)
|
|
BYTE PARAMS[12]
|
|
|
|
PARAMS.0 = 7
|
|
PARAMS:1 = PATH
|
|
PARAMS.3 = ACCESS
|
|
PARAMS.4 = TYPE
|
|
PARAMS:5 = AUX
|
|
PARAMS.7 = $1
|
|
PARAMS:8 = 0
|
|
PARAMS:10 = 0
|
|
PERR = SYSCALL($C0, @PARAMS)
|
|
RETURN PERR
|
|
END
|
|
DEF OPEN(PATH, BUFF)
|
|
BYTE PARAMS[6]
|
|
|
|
PARAMS.0 = 3
|
|
PARAMS:1 = PATH
|
|
PARAMS:3 = BUFF
|
|
PARAMS.5 = 0
|
|
PERR = SYSCALL($C8, @PARAMS)
|
|
RETURN PARAMS.5
|
|
END
|
|
DEF CLOSE(REFNUM)
|
|
BYTE PARAMS[2]
|
|
|
|
PARAMS.0 = 1
|
|
PARAMS.1 = REFNUM
|
|
PERR = SYSCALL($CC, @PARAMS)
|
|
RETURN PERR
|
|
END
|
|
DEF READ(REFNUM, BUFF, LEN)
|
|
BYTE PARAMS[8]
|
|
|
|
PARAMS.0 = 4
|
|
PARAMS.1 = REFNUM
|
|
PARAMS:2 = BUFF
|
|
PARAMS:4 = LEN
|
|
PARAMS:6 = 0
|
|
PERR = SYSCALL($CA, @PARAMS)
|
|
RETURN PARAMS:6
|
|
END
|
|
DEF WRITE(REFNUM, BUFF, LEN)
|
|
BYTE PARAMS[8]
|
|
PARAMS.0 = 4
|
|
PARAMS.1 = REFNUM
|
|
PARAMS:2 = BUFF
|
|
PARAMS:4 = LEN
|
|
PARAMS:6 = 0
|
|
PERR = SYSCALL($CB, @PARAMS)
|
|
RETURN PARAMS:6
|
|
END
|
|
;
|
|
; REL MODULE FIXUPS
|
|
;
|
|
DEF DUMPRLD(RLD)
|
|
COUT('$')
|
|
PRBYTE(^RLD)
|
|
COUT(':')
|
|
COUT(' ')
|
|
COUT('$')
|
|
PRWORD(*(RLD + 1))
|
|
COUT(' ')
|
|
COUT('$')
|
|
PRBYTE(^(RLD + 3))
|
|
CROUT
|
|
RETURN RLD + 4
|
|
END
|
|
DEF DUMPESD(ESD)
|
|
WHILE ^ESD & $80
|
|
COUT(^ESD)
|
|
ESD = ESD + 1
|
|
LOOP
|
|
COUT(^ESD)
|
|
COUT(':')
|
|
COUT(' ')
|
|
COUT('$')
|
|
PRBYTE(^(ESD + 1))
|
|
COUT(' ')
|
|
COUT('$')
|
|
PRWORD(^(ESD + 2))
|
|
CROUT
|
|
RETURN ESD + 4
|
|
END
|
|
DEF MATCHSTR(STR1, STR2)
|
|
BYTE I
|
|
IF ^STR1 == ^STR2
|
|
FOR I = ^STR1 DOWNTO 1
|
|
IF (STR1).[I] <> (STR2).[I]
|
|
RETURN FALSE
|
|
FIN
|
|
NEXT
|
|
RETURN TRUE
|
|
FIN
|
|
RETURN FALSE
|
|
END
|
|
;
|
|
; THE GLOBAL SYMBOL DICTIONARY HAS THE FORMAT OF:
|
|
; STRING: NAME (VARIABLE LENGTH)
|
|
; WORD: ADDRESS
|
|
;
|
|
DEF DUMPDICT
|
|
WORD DICTPTR
|
|
|
|
DICTPTR = SYMTABLE
|
|
CROUT()
|
|
WHILE ^DICTPTR
|
|
PRSTR(DICTPTR)
|
|
COUT(':')
|
|
COUT(' ')
|
|
COUT('$')
|
|
PRWORD(*(DICTPTR + ^DICTPTR + 1))
|
|
CROUT()
|
|
DICTPTR = DICTPTR + ^DICTPTR + 3 ; NEXT ENTRY
|
|
LOOP
|
|
END
|
|
DEF ADDSYM(SYMSTR, ADDR)
|
|
MEMCPY(SYMSTR, NEXTENTRY, ^SYMSTR + 1)
|
|
NEXTENTRY = NEXTENTRY + ^NEXTENTRY
|
|
(NEXTENTRY):1 = ADDR
|
|
NEXTENTRY = NEXTENTRY + 3
|
|
END
|
|
DEF SEARCHDICT(SYMSTR)
|
|
WORD DICTPTR
|
|
|
|
DICTPTR = SYMTABLE
|
|
;
|
|
; SEARCH GLOBAL DICTIONARY LOOKING FOR MATCH
|
|
;
|
|
WHILE ^DICTPTR
|
|
; CROUT
|
|
; PRSTR(DICTPTR)
|
|
IF MATCHSTR(DICTPTR, SYMSTR)
|
|
; COUT('$')
|
|
; PRWORD(*(DICTPTR + ^DICTPTR + 1))
|
|
RETURN DICTPTR + ^DICTPTR + 1
|
|
FIN
|
|
DICTPTR = DICTPTR + ^DICTPTR + 3 ; NEXT ENTRY
|
|
LOOP
|
|
RETURN 0
|
|
END
|
|
DEF MATCHEXTRN(INDEX, ESD)
|
|
BYTE SYMSTR[$81], I
|
|
WORD SYMPTR
|
|
|
|
;
|
|
; FIND MATCHING ESD INDEX
|
|
;
|
|
WHILE ^ESD
|
|
; DUMPESD(ESD)
|
|
SYMPTR = ESD
|
|
I = 1
|
|
WHILE ^ESD & $80
|
|
SYMSTR[I] = TOUPPER(^ESD)
|
|
I = I + 1
|
|
ESD = ESD + 1
|
|
LOOP
|
|
SYMSTR[I] = TOUPPER(^ESD)
|
|
SYMSTR = I
|
|
; CROUT
|
|
IF ^(ESD + 1) & $10
|
|
; PRSTR(@MATCHEXTRNSTR)
|
|
; PRSTR(@SYMSTR)
|
|
IF ^(ESD + 2) == INDEX
|
|
RETURN SEARCHDICT(@SYMSTR)
|
|
FIN
|
|
FIN
|
|
ESD = ESD + 4
|
|
LOOP
|
|
RETURN 0
|
|
END
|
|
DEF FIXUP(SEGPTR, RLD, OFST, ESD, PASS)
|
|
WORD FIXVAL, FIXADDR, EXTRNVAL
|
|
|
|
WHILE ^RLD
|
|
; DUMPRLD(RLD)
|
|
FIXADDR = SEGPTR + *(RLD + 1)
|
|
IF ^RLD & $80
|
|
;
|
|
; 16 BIT FIXUP
|
|
;
|
|
; PRSTR(@FIX16STR)
|
|
; PRWORD(FIXADDR)
|
|
; CROUT
|
|
FIXVAL = *FIXADDR
|
|
IF ^RLD & $10
|
|
;
|
|
; EXTERNAL SYMBOL
|
|
;
|
|
EXTRNVAL = MATCHEXTRN(^(RLD + 3), ESD)
|
|
IF EXTRNVAL
|
|
FIXVAL = FIXVAL + *EXTRNVAL
|
|
ELSIF PASS == 2
|
|
RETURN ERROR
|
|
FIN
|
|
ELSE
|
|
FIXVAL = FIXVAL + OFST
|
|
FIN
|
|
IF ^RLD & $20 ; REVERSE HI AND LO BYTES
|
|
FIXVAL = ((FIXVAL >> 8) & $FF) ? (FIXVAL << 8)
|
|
FIN
|
|
*FIXADDR = FIXVAL
|
|
ELSE
|
|
;
|
|
; 8 BIT FIXUP
|
|
;
|
|
; PRSTR(@FIX8STR)
|
|
; PRWORD(FIXADDR)
|
|
; CROUT
|
|
IF ^RLD & $10
|
|
;
|
|
; EXTERNAL SYMBOL
|
|
;
|
|
EXTRNVAL = MATCHEXTRN(^(RLD + 3), ESD)
|
|
IF EXTRNVAL
|
|
FIXVAL = FIXVAL + ^EXTRNVAL
|
|
ELSIF PASS == 2
|
|
RETURN ERROR
|
|
FIN
|
|
ELSE
|
|
IF ^RLD & $40
|
|
FIXVAL = ^FIXADDR << 8 ? ^(RLD + 3)
|
|
FIXVAL = FIXVAL + OFST
|
|
ELSE
|
|
FIXVAL = ^(RLD + 3) << 8 ? ^FIXADDR
|
|
FIXVAL = FIXVAL + OFST
|
|
FIN
|
|
FIN
|
|
IF ^RLD & $40
|
|
^FIXADDR = FIXVAL >> 8
|
|
ELSE
|
|
^FIXADDR = FIXVAL
|
|
FIN
|
|
FIN
|
|
RLD = RLD + 4
|
|
LOOP
|
|
RETURN OK
|
|
END
|
|
DEF LOADMOD(MODSTR, PASS)
|
|
BYTE REFNUM, I, INFO[15], SYMSTR[81]
|
|
WORD RELOFST, MODPTR, MODSYMTBL, MODSYMSZ, LEN, DATALEN, RLD, ESD
|
|
|
|
DROP GETFILEINFO(MODSTR, @INFO)
|
|
IF PERR OR INFO.1 <> $FE ; REL FILE TYPE
|
|
RETURN 0, 0
|
|
FIN
|
|
;
|
|
; READ REL FILE
|
|
;
|
|
REFNUM = OPEN(MODSTR, INBUFF)
|
|
LEN = READ(REFNUM, DATABUFF, 32768)
|
|
DROP CLOSE(REFNUM)
|
|
;
|
|
; GET POINTERS TO IMPORTANT SECTIONS
|
|
;
|
|
DATALEN = *DATABUFF
|
|
MODPTR = DATABUFF + 2
|
|
RLD = MODPTR + DATALEN
|
|
ESD = RLD
|
|
IF MODADDR
|
|
RELOFST = MODADDR - INFO:2
|
|
ELSE
|
|
MODADDR = INFO:2
|
|
LINKADDR = MODADDR
|
|
RELOFST = 0
|
|
FIN
|
|
MODADDR = MODADDR + DATALEN
|
|
WHILE ^ESD ; SKIP OVER RLD
|
|
ESD = ESD + 4
|
|
LOOP
|
|
ESD = ESD + 1
|
|
; PRSTR(@RELOFSTSTR)
|
|
; PRWORD(RELOFST)
|
|
; CROUT()
|
|
;
|
|
; RUN THROUGH DATA FIXUP TABLE
|
|
;
|
|
IF FIXUP(MODPTR, RLD, RELOFST, ESD, PASS)
|
|
RETURN 0, 0
|
|
FIN
|
|
;
|
|
; CREATE SYMBOL TABLE FOR EXPORTS
|
|
;
|
|
IF PASS == 1
|
|
WHILE ^ESD
|
|
; DUMPESD(ESD)
|
|
I = 1
|
|
WHILE ^ESD & $80
|
|
SYMSTR[I] = TOUPPER(^ESD)
|
|
I = I + 1
|
|
ESD = ESD + 1
|
|
LOOP
|
|
SYMSTR[I] = TOUPPER(^ESD)
|
|
SYMSTR = I
|
|
IF ^(ESD + 1) & $08 ; ENTRY SYMBOL
|
|
ADDSYM(@SYMSTR, *(ESD + 2) + RELOFST)
|
|
FIN
|
|
ESD = ESD + 4
|
|
LOOP
|
|
FIN
|
|
RETURN DATABUFF + 2, DATALEN
|
|
END
|
|
|
|
CROUT()
|
|
PRSTR(@PLASMASTR)
|
|
CROUT()
|
|
MEMSET(0, SYMTABLE, SYMSIZE)
|
|
MODCOUNT = 0
|
|
MODADDR = 0
|
|
PRSTR(@INPUTFILESTR)
|
|
WHILE LOADMOD(RDSTR($BA), 1)
|
|
DROP
|
|
MEMCPY(INPUTSTR, @MODFILES[MODCOUNT * 17], ^INPUTSTR + 1)
|
|
MODCOUNT = MODCOUNT + 1
|
|
LOOP
|
|
DROP
|
|
IF MODCOUNT
|
|
MODADDR = 0
|
|
IF LINKADDR == $2000
|
|
BINTYPE = $FF
|
|
ELSE
|
|
BINTYPE = $06
|
|
FIN
|
|
PRSTR(@OUTPUTFILESTR)
|
|
DROP DESTROY(RDSTR($BA))
|
|
DROP CREATE(INPUTSTR, $C3, BINTYPE, LINKADDR)
|
|
BINREF = OPEN(INPUTSTR, OUTBUFF)
|
|
IF BINREF == 0
|
|
PRSTR(@ERROUTSTR)
|
|
ELSE
|
|
FOR MODI = 0 TO MODCOUNT - 1
|
|
MODBUFF =, MODLEN = LOADMOD(@MODFILES[MODI * 17], 2)
|
|
DROP WRITE(BINREF, MODBUFF, MODLEN)
|
|
NEXT
|
|
DROP CLOSE(BINREF)
|
|
DUMPDICT()
|
|
FIN
|
|
PRSTR(@PRESSANYKEY)
|
|
WHILE ^$C000 < 128
|
|
LOOP
|
|
DROP ^$C010
|
|
FIN
|
|
DONE
|