A TDL Relocatable Object Code Loader.
Simple, stupid, and dangerous!
It can overwrite your system, if you say so :-)
I tried to pack all details directly into comments.
Just assemble with the CP/M asm/load.
Here is the source, hope someone can use it.
Martin
TDLLOAD.ASM:I also made a CP/M version of TDLoader. I'll try to compare our two versions of the code. Been a while since I used it mainly for making a CP/M version of TDL Basic.
==== 8< ====
;
; TDL RELOCATABLE OBJECT / INTEL HEX LOADER
;
; The loader was taken from the 8080 apple monitor
; and code added for CP/M file I/O using SEQIO.
;
; "APPLE MONITOR" COPYRIGHT 1975,1976,1977
; BY ROGER AMIDON
;
; This loader is powerful because it supports
; two relocation bases.
;
; It allows loading of programs with split
; .PROG. and .DATA. segments, as introduced
; in version 2.X of the TDL assembler.
;
; Command syntax:
; tdlload
; filename.ext
; [<loading bias>[,<rel base 1>[,<rel base 2>]]]
;
; <loading bias>
; is an optional bias, which will be added to
; the load address
; <rel base 1> and <rel base 2>
; are optional relocation bases which are used
; only with relocatable files.
;
; The binary output file is named filename.BIN
; It only contains the range of bytes loaded.
;
; "tdlload" reads a normal hex file, or a
; relocatable hex file. On both files, a "bias"
; (a shift in the address) may be added which will
; allow the object code to by placed in a location
; other than its intended execution location.
; The bias is added to what would hav been the
; normal loading location and may wrap around.
;
; When used with the TDL relocating assembler, it
; allows generating a program to execute anywhere,
; and to be stored anywhere else in memory.
; When loading a relocatable file, two additional
; parameters may be added which represent the
; actual execution addresses desired. This may
; also be any location in memory.
;
; NOTE:
; These values tgether with the current record
; offset determine the actual loading location
; which is used *WITHOUT* any checks!
;
; Example source with split code and data:
; ==== 8< ====
; .phex
; .loc .prog.
; start:
; lxi d,msg
; mvi c,9
; call 5
; jmp 0
; .loc .data.
; msg:
; .ascii 'Testing Relocation'
; .byte 0dh,0ah
; .ascii '$'
; .end
; ==== 8< ====
;
; Command to load:
; tdlload example.rel 1000,100,110
;
;
BOOT EQU 0
BDOS EQU 5
TBUF EQU 80H
;
ORG 0100H
;
MACLIB SEQIO
;
LXI SP,STACK
;
FILE INFILE,DSKI,,1,
;
LXI H,BUFFERS+@NXTB ;FREE MEMORY
XCHG
LHLD BDOS+1 ;TOP OF MEMORY
XRA A ;PAGE BOUNDARY
SUB E
MOV C,A
MOV A,H
SBB D
MOV B,A
XCHG
INIMEM: MVI M,0FFH ;WHATEVER
INX H
DCX B
MOV A,B
ORA C
JNZ INIMEM
;
LXI H,0 ;INIT MIN/MAX
SHLD MMAX
DCX H
SHLD MMIN
;
LXI H,TBUF
MOV C,M
INX H
MOV A,C
ORA A
JZ L4
CALL SKBLNK ;SKIP OVER BLANKS
JZ L4
CALL SKARG ;SKIP OVER ARGUMENT AND BLANKS
;
L4: MOV D,H ;PARAMETER FOR READ
MOV E,L
MVI B,0 ;CR TERMINATED
DAD B
MVI M,CR
;
CALL READ ;TDL RELOCATABLE OBJECT LOADER
;
FINIS DSKI
;
FILE OUTFILE,DSKO,,1,BIN
;
LHLD MMIN ;START AT MIN
SV1: LDA MMAX ;STOP AFTER MAX
SUB L
LDA MMAX+1
SBB H
JC SV2 ;DONE
MOV A,M
INX H
PUSH D
PUSH H
PUT DSKO
POP H
POP D
JMP SV1
;
SV2: FINIS DSKO
JMP BOOT
;
ERROR: MVI C,'*'
CALL CO
;
FINIS DSKI
JMP BOOT
;
SKBLNK: MOV A,M ;SKIP OVER BLANKS
CPI ' '
RNZ
INX H
DCR C
JNZ SKBLNK
RET
;
SKARG: MOV A,M ;SKIP OVER ARGUMENT AND BLANKS
CPI ' '
JZ SKBLNK
INX H
DCR C
JNZ SKARG
RET
;
UPDMM: PUSH PSW ;UPDATE MIN/MAX
LDA MMAX
SUB L
LDA MMAX+1
SBB H
JNC UNMAX
SHLD MMAX
UNMAX: LDA MMIN
SUB L
LDA MMIN+1
SBB H
JC UNMIN
SHLD MMIN
UNMIN: POP PSW
RET
;
READ: CALL EXPR ;GET BIAS
LXI H,0 ;SET-UP DEFAULT BASE[1]
PUSH H ;AND DEFAULT BASE[2]
JC RD0 ;CR
CALL EXPR ;GET ACTUAL BASE[1]
POP H ;HL=BASE[1]
JC RD0 ;CR
XTHL ;GET DEFAULT BASE[2]
CALL EXPR ;GET ACTUAL BASE[2]
POP H
XTHL ;(SP)=BASE[2]
RD0: POP D
POP B
PUSH D ;BASE[2]
PUSH H ;BASE[1]
PUSH B ;BIAS
JMP RD1
;
RD1A: MOV A,B
ADI ':'
JMP RD1C
RD1B: CALL RIX ;GET READER CHARACTER
RD1C: CPI CR
JNZ RD1B ;NOT CR
CALL RIX ;GET READER CHARACTER
CPI LF
JNZ RD1C ;NOT LF
RD1: CALL RIX ;GET READER CHARACTER
SUI ':' ;GET FILE TYPE CUE
MOV B,A ;SAVE CUE CLUE
ANI 0FEH ;KILL BIT 0
JNZ RD1A ;NOT ':' OR ';'
MOV D,A ;ZERO CHECKSUM STORAGE
CALL BYTE ;GET FILE LRNGTH
MOV E,A ;SAVE IN E
CALL BYTE ;GET LOAD MSB
PUSH PSW ;SAVE IN STACK
CALL BYTE ;GET LOAD LSB
POP H ;H=MSB
MOV L,A ;HL=LOAD ADDR
CALL BYTE ;GET FILE TYPE
;
; FIX: SET THE RELOCATION BASE FOR THE RECORD
DCR A ;TEST FILE TYPE
JM RD2 ;M=ABSOLUTE LOAD
PUSH D
XCHG ;RELOCATE LOAD ADDR.
LXI H,4 ;POINT TO BASE[1]
JZ RD2A ;Z=BASE[1]
INX H
INX H ;POINT TO BASE[2]
RD2A: DAD SP ;IN STACK
MOV A,M
INX H
MOV H,M
MOV L,A
DAD D ;ADD BASE[N] TO LOAD
POP D
RD2: MOV A,B ;GET CUE
POP B ;BC=BIAS
;
INR E ;TEST LENGTH
DCR E ;ZERO?
JZ DONE
DAD B ;ADD BIAS TO LOAD
PUSH B ;SAVE BIAS
MOV B,A ;SET-UP B
DCR A ;TEST CUE CLUE
JZ RD6 ;Z=REL. FILE, NZ=ABS.
RD3: CALL BYTE ;GET NEXT DATA BYTE
MOV M,A ;WRITE TO MEMORY
CALL UPDMM ;UPDATE MIN/MAX
INX H ;BUMP UP LOAD POINT
DCR E ;BUMP DOWN BYTE COUNT
JNZ RD3 ;CONTINUE
RD4: CALL BYTE ;TEST CHECKSUN
JZ RD1B ;OK; CONTINUE W/NEXT
RD5: CALL LADR ; ELSE PRINT LOAD ADDR
JMP ERROR ; & ABORT
RD6: CALL RD10 ;GET NEXT DATA BYTE
MOV M,A ;STORE IT
CALL UPDMM ;UPDATE MIN/MAX
JNC RD9 ;NORMAL BYTE
PUSH H ;CARRY=RELOCATE NEXT WORD
LXI H,5 ;POINT TO BASE[1]
DAD SP ;IN STACK
RD7: CALL RD10 ;GET HIGH BYTE
JNC RD8 ;USE BASE[N]
DCR E ;COUNT EXTRA BYTE
XTHL ;GET LOAD ADDR
DCR M ;TEST FOR BASE[1]
MOV M,A ;NEW LOW BYTE
XTHL ;SAVE LOAD AGAIN
JZ RD7 ;BASE[1]
INX H
INX H ;POINT TO BASE[2]
JMP RD7 ;AND TRY AGAIN
;
RD8: ADD M ;ADD IN MSB
XTHL
INX H ;STICK AT LOAD+1
MOV M,A
DCX H ;GET LOAD BYTE
MOV A,M ;IN A
XTHL
DCX H
ADD M ;RELOCATE LSB
POP H ;GET LOAD ADDR
MOV M,A ;STORE IT
CALL UPDMM ;UPDATE MIN/MAX
INX H ;GET MSB
MOV A,M ;IN A
ACI 0 ;ADJUST FOR CARRY
MOV M,A ;STORE IT
CALL UPDMM ;UPDATE MIN/MAX
DCR E ;COUNT IT
RD9: INX H ;BUMP THE COUNT
DCR E ;MORE?
JNZ RD6 ; & CONTINUE
JMP RD4 ;TEST CHECKSUM
;
RD10: DCR B ;COUNT BITS/BYTES
JNZ RD11 ;NEXT IS DATA BYTE
CALL BYTE ;GET RELOC. MAP
DCR E ;BUMP DOWN BYTE COUNT
MOV C,A ;MAP IN C
MVI B,8 ;RESET FOR NEXT 8
RD11: CALL BYTE ;NEXT DATA BYTE
PUSH D ;SAVE DE
MOV D,A ;SAVE DATA BYTE
MOV A,C ;TEST FOR RELOC.
RAL ;IN CARRY FLAG
MOV C,A ;UPDATE C
MOV A,D ;RESTORE DATA BYTE
POP D ;RESTORE DE
RET ;CONTINUE
;
BYTE: PUSH B ;SAVE BC
CALL RIBBLE ;GET A CONVERTED CHAR.
RLC
RLC
RLC
RLC ;MOVE IT TO HIGH NIBBLE
MOV C,A ;SAVE IT
CALL RIBBLE ;GET OTHER HALF
ORA C ;MAKE WHOLE
MOV C,A ;SAVE IN C
ADD D ;UPDATE CHECKSUM
MOV D,A ;NEW CHECKSUM
MOV A,C ;RESTORE DATA BYTE
POP B ;RESTORE BC
RET ;CONTINUE
;
DONE: POP B ;BASE[1]
POP B ;BASE[2]
CALL LADR ;EXECUTION ADDRESS
RET
;
CONV: ANI 0FH
ADI 90H
DAA
ACI 40H
DAA
MOV C,A
RET
;
EXPR: LDAX D
INX D
EXF: LXI H,0 ;INITIALIZE HL
XF1: MOV B,A ;SAVE KEYBOARD
CALL NIBBLE ;CONVERT ASCII TO HEX
JC XF2 ;BOT LEGAL
DAD H ;HL*16
DAD H
DAD H
DAD H
ORA L ;ADD IN NIBBLE
MOV L,A
LDAX D
INX D
JMP XF1 ;AND CONTINUE
XF2: XTHL ;STICK PARAMETER IN STACK
PUSH H ;REPLACE RETURN
MOV A,B ;TEST CHARACTER
CALL QCHK ;FOR DELIMITERS
JNZ ERROR ;ILLEGAL
RET
;
LADR: MOV A,H
CALL LBYTE
MOV A,L
;
LBYTE: PUSH PSW
RRC
RRC
RRC
RRC
CALL LB
POP PSW
LB: CALL CONV
JMP CO
;
RIBBLE: CALL RIX
NIBBLE: SUI '0'
RC
CPI 'G'-'0'
CMC
RC
CPI 10
CMC
RNC
SUI 'A'-'9'-1
CPI 10
RET
;
QCHK: CPI ' '
RZ
CPI ','
RZ
CPI CR
STC
RZ
CMC
RET
;
RIX: CALL RIFF
ANI 7FH
RET
;
RIFF: PUSH B
PUSH D
PUSH H
GET DSKI
POP H
POP D
POP B
CPI EOF
JZ ERROR
CMP D
RET
;
CO: PUSH B
PUSH D
PUSH H
MOV A,C
PUT CON
POP H
POP D
POP B
RET
;
MMIN: DS 2
MMAX: DS 2
DS 32
STACK:
;
BUFFERS:
END
==== 8< ====
On Saturday, August 20, 2022 at 10:55:14 AM UTC-4, Martin wrote:I'll try to compare our two versions of the code.
A TDL Relocatable Object Code Loader.I also made a CP/M version of TDLoader.
Simple, stupid, and dangerous!
It can overwrite your system, if you say so :-)
I tried to pack all details directly into comments.
Just assemble with the CP/M asm/load.
Here is the source, hope someone can use it.
Martin
Lars
...
Couldn't believe that there is absolutely no small CP/M loader
for the TDL RELOCATABLE OBJECT format in the CP/M archives.
On 11/09/2022 11:48 pm, Martin wrote:
...
Couldn't believe that there is absolutely no small CP/M loader
for the TDL RELOCATABLE OBJECT format in the CP/M archives.
Perhaps not that much interest given CP/M apps generally ORG'd at
$100 and TDL ZAPPLE was from an earlier era. Nevertheless it's
impressive what Colvin achieved in such a short space of time.
Nice work on your program! I wrote a simple TDL REL V1 to binary
app sometime ago as a fun exercise. Given your efforts, I can
forego adapting it to V2 :)
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 490 |
Nodes: | 16 (2 / 14) |
Uptime: | 66:02:19 |
Calls: | 9,676 |
Files: | 13,719 |
Messages: | 6,171,846 |