[net.micro.cbm] C64DXL.M65

GMW@psuvm.BITNET (06/05/85)

.TITLE	Hxload -     Load ASCII hex files in KIM format
; For Commodore 64 with 1541 disk
; adapted from Apple version of Antonino N. J. Mione
; By Dave Dermott, Eric Lavitsky
     
; C64  Kernal entry points
     
chrin	=	$ffcf		; input a character
chrout	=	$ffd2		; ouput a byte to current channel
chkin	=	$ffc6		; change Kernal input channel
setlfs	=	$ffba		; set open parameters
setnam	=	$ffbd		; set file name
open	=	$ffc0		; open a channel
close	=	$ffc3		; close a channel
clall	=	$ffe7		; Close all channels
ioinit	=	$ff84		; Initialize I/O devices
restoi	=	$ff8a		; Restore default I/O vectors
stop	=	$ffe1		; Scan for stop key
clrchn	=	$ffcc		; clear channel
readst	=	$ffb7		; read the status word
getin	=	$ffe4		; input a character
dos	=	$a002		; BASIC NMI vector
     
buff	=	$200		; Buffer for disk message
space	=	$20		; <sp>
comma	=	$2c		; ','
semi	=	$3b		; ';'
cr	=	$0d		; <cr>
spc	=	$20		; <sp>
stat	=	$90		;
laddr	=	$fb		; Zero page pointer for load
saddr	=	$fd		; Zero page pointer for prstr
count	=	$c3
lind	=	$17
hold	=	$19
     
staddr	=	$c000		; Address for high loader
;staddr	=	$0810		; Address for low loader
     
	.ifeq <staddr-$0810>
;	When starting at $0810 include BASIC calling sequence
;	10 SYS(2064)
     
	.=	$0801
     
	.byte	$0d,$08,$0a,$00		; Line 10 in BASIC
	.byte	$9e			;SYS
	.ascii	/(2064)/
	.byte	$00,$00,$00		;End of line
	.byte	$00
	.endc
     
	.=	staddr
     
dxst:	jmp	start		; Jump to start of code
     
; Working storage areas
     
chksum:	.byte	$00,$00
add2:	.byte	$00,$00
sav2:	.byte	$00
fnerc:	.byte	'I,'0
fnam:	.byte	$00
.=.+17
len:	.byte	$00
hxwrk1:	.byte	$00
hxwrk2:	.byte	$00
hxwrk3:	.byte	$00
     
     
; Message area
mess1:	.byte	$0d
	.ascii	/HEX OBJECT LOADER/
	.byte	$0d
	.asciz	/OBJECT FILE NAME? /
mess2:	.byte	$0d
	.asciz	/CHECKSUM ERROR/
mess3:	.byte	$0d
	.asciz	/DISK ERROR/
mess4:	.byte	$0d
	.asciz	/ABORT/
mess5:	.asciz	/ [OK]/
eol:	.byte	$0d
	.asciz	/END OF LOAD/
     
; Macros
; Macro to load address in X,Y
     
.macro  ldadr 	adr
	ldx	#adr\	;load low addr.
	ldy	#adr^	;load high
.endm
     
;Macro to open file
.macro	openm	 lun,dev,scadr,name,len
	lda	lun		;Log. unit no.
	ldx	dev		;Dev. no.
	ldy	scadr		;Sec. address
	jsr	setlfs
	ldadr	name		;File-name
	lda	len		;No. of bytes in file-name
	jsr	setnam
	jsr 	open
.endm
     
start:  jsr	clall		; close all channels
	lda	#$00		; clear status
	sta	stat		; 		...
	ldadr	mess1		; Print start message
	jsr	prstr		;		...
	ldx	#0		; Clear len of file name
	stx	len		;		...
gtfnm:	jsr	chrin		; Get a character from keyboard
	cmp	#cr		; Stop on cr
	beq	gtfn2		;		...
	cmp	#spc		; Ignore spaces
	beq	gtfnm		;		...
	sta	fnam,x		; Put in fnam
	stx	len		;
	inx			;
	bne	gtfnm		;
gtfn2:	ldx	len		;
	inx			;
	lda	#comma		;
	sta	fnam,x		; put in comma
	inx			;
	lda	#'S		; put in S
 	sta	fnam,x		;
	inx			;
	stx	len		; final length
	lda	#cr		;
	jsr	chrout		; print a cr
	lda	#cr
	jsr	chrout
     
	openm	#15,#8,#15,fnerc,#2	; open error channel
	jsr	readst			; check IO status
	beq	dskok			;
	cmp	#$40			;
	bne	dskerr			;
dskok:	openm	#7,#8,#7,fnam,len	; open input file
	jsr	readst			; check IO status
	beq	dok2		; no error
	cmp	#$40		; 64
	beq	dok2		;
dskerr:	ldadr	mess3		; IO error
	jmp	errors		;
dok2:	jsr 	rddst		; Read disk status
	ldx	#$07		; Open channel 7 for disk input
	jsr	chkin		;		...
     
inloop:	jsr	stop		; stop key pressed?
	bne	receve		; no
	ldadr	mess4		; yes, set 'abort' message
	jmp	errors		; abort the load
receve:	jsr	fgetc		; get a character from disk
	 jmp	clsit		; Close the file and leave
	cmp	#semi		; Is it the beginning of a line?
	bne 	inloop		; keep looking
	lda	#cr		;
	jsr	chrout		;
	lda	#semi		; Print a semi-colon
	jsr	chrout		;		...
	jsr	doline		; Otherwise read a line of ascii hex
	jmp	receve		; If no error or done, go back for next line
clsit:	jsr	closem		; end
	jmp	(dos)		; Restart BASIC
     
;
;	Doline routine
;
     
doline:	ldy	#$00		; Zero the
	sty	lind		;	load point index
	sty	chksum		;	and the checksum
	sty	chksum+1	;		...
     
dolin1:	jsr	getbyt		; Get a hex byte
	pha			; Save it on the stack
	jsr	by2hx		; Display it on the screen
	pla			; Fetch it back
	cmp	#$00		; Is it zero?
	bne	norskp		; If not, continue gobbling line
	jmp	rskp		; Otherwise, return with a skip
norskp:	pha			; Save it on the stack
	lda	#space		; Get a space
	jsr	chrout		; And print it
	pla			; Fetch the character back
	jsr	chksad		; Add it to the checksum
	sta	count		; The first byte is a count, store it
	jsr	getbyt		; Get the next hex byte
	jsr	chksad		; Add it to the checksum
	sta	laddr+1		; That is the H.O. byte of the load address
	jsr	getbyt		; Get the next byte
	jsr	chksad		; Add that into the checksum
	sta	laddr		; That is the L.O. byte of the load address
	jsr	prnyb		; Print the load address on the screen
dolin3:	dec	count		; Decrement the count
	ldx	count		; Load it into X
	bmi	dolchk		; If we are done, do the checksum stuff
	jsr	getbyt		; Get a byte
	ldy	lind		; Get the load point index
	sty	len		; Save it for end of program pointer
	jsr	chksad		; Add the data into the checksum
	sta	(laddr),y	; Stuff the data where it belongs
	jsr	by2hx		; Print it
	inc	lind		; Up the load point index once
	jmp	dolin3		; Loop for more data
dolchk:	jsr	getbyt		; Get another byte from disk
	pha			; Stuff it on the stack
	jsr	by2hx		; Print it
	pla			; Fetch back the character
	cmp	chksum+1	; Compare that with the checksum
	bne	chkerr		; If they don't match, we have problems
	lda	chksum+1	; Get the H.O. byte of the checksum
	jsr	by2hx		; Print it as hex
	lda	#space		; Get a space
	jsr	chrout		; and print it
	jsr	getbyt		; Get another byte from disk
	pha			; Hold it on the stack
	jsr	by2hx		; Print it
	pla			; Fetch the data back
	cmp	chksum		; Compare that to the L.O. byte of the checksum
	bne	chkerr		; If they don't match, tell the user
	lda	chksum		; Fetch the L.O. byte of the checksum
	jsr	by2hx		; Print that as hex
	ldx	#mess5\		; Get the address of the 'OK' message
	ldy	#mess5^		;		...
	jsr	prstr		; Print that text
	lda	#cr		; Print a cr
	jsr	chrout		;		...
	rts			; Return, this line is OK
     
chksad:	pha			; save the accumulator accross this call
	clc			; clear the carry flag for addition
	adc	chksum		; add in the checksum
	sta	chksum		; stuff that back
	lda	chksum+1	; adjust the h.o. byte of the checksum
	adc	#$00		;	by whatever is in the carry
	sta	chksum+1	;		...
	pla			; restore the AC
	rts			; return
     
chkerr:	ldadr	mess2		; get the address of the 'checksum error' mess.
	jsr	prstr		; print that error text
	rts			; Return
     
errors: jsr	prstr		; print error message
closem:	lda	#7		; close the disk file
	jsr	close		;		...
	lda	#15		; and the error channel
	jsr	close		;		...
	clc			;
	lda	len		;
	adc	laddr		; form last load address
	sta	laddr		;
	lda	laddr+1		;
	adc	#$00		;
	sta	laddr+1		;
	lda	#cr		; Print a <cr>
	jsr	chrout		;		...
	jsr	prnyb		; Print laddr
	ldadr	eol		; Get the address of the message
	jsr	prstr		; Print end of load
	jsr	clall		; Close all channels
	brk			; Give control back to whoever is
				; Servicing interrupts (BASIC,Supermon etc.)
     
     
getbyt:	jsr	getnib		; Get the first nibble of the two
	bcc	gterr		; Error
	sta	hold		; Stuff that here
	jsr	getnib		; Get the second nibble
	bcc	gterr		;
	sta	hold+1		; Hold that here
	lda	hold		; Get the first of the two
	asl	a		; Shift it to the left side
	asl	a		;		...
	asl	a		;		...
	asl	a		;		...
	ora	hold+1		; Combine that with the second nibble
	sec			; Set no error
	rts			;	and return
gterr:  clc			;		...
        rts			; Error return
     
;
;	Getnib routine
;
     
getnib:	jsr	fgetc		; Read a character from the file
	 jmp	clsit		; Error!
getnb:	cmp	#$30		; is it in the proper range?
	bcc	badchr		;	0<=char<=f
	cmp	#$3a		;		...
	bcc	getnb3		; This is good, no special adjustment
	cmp	#$41		;		...
	bcc	badchr		;		...
	cmp	#$47		;		...
	bcc	getnb2		; This is good, but adjust it down a bit
	jmp	badchr		; Bad character in input
     
getnb2:	sec			; Set the carry flag
	sbc	#$07		; Adjust the letters into the proper range
     
getnb3:	sec			; Set the carry flag
	sbc	#$30		; Make the character numeric
	sec			; Set C for no error
	rts			;	and return
     
badchr:	pla			;
	pla			;
	pla			;
	pla			;
	pla			;
	pla			;
	jmp	receve		;
     
fgetc:	jsr	chrin		; Get char.
	pha			; Save it
	jsr	readst		; Check status
	and	#$bf		;		...
	beq	getok		; No error
        ldadr	mess3		; Print error message
	rts			; Return
getok:  pla			; Retrieve char
	jmp	rskp		; Skip return
     
     
prnyb:	lda	laddr		; Save low order
	pha			;   on stack
	lda	laddr+1		; Get high order
	jsr	by2hx		; Print high order
	pla			; Retreive low order
     
by2hx:  pha			; Save byte
	lsr	a		;
	lsr	a		;
	lsr	a		;
	lsr	a		;
	jsr	ny2hx		; High nyble
	tax			;   to X
	pla			; Get back
	and	#$0f		; Low nyble
	jsr	ny2hx		;
	pha			;
	txa			;
	jsr	chrout		; Print first nyble
	pla			;
	jmp	chrout	        ; Print second nyble
     
ny2hx:  clc			; Translate nyble to hex
	adc	#$f6		;
	bcc	ny2h2		;
	adc	#$06		;
ny2h2:  adc	#$3a		;
	rts			;
     
;	Print to screen
     
prstr:	stx	saddr		;
	sty	saddr+1		;
	ldy	#$00		;
     
prst1:	lda	(saddr),y	;
	beq	prn3		; Stop on null
	jsr	chrout		; Output the character
	iny			;
	bne	prst1		;
prn3:	rts			;
     
; Read disk status
     
rddst:	ldx	#15		;
	jsr	chkin		;
	ldy	#0		;
rdds1:	jsr	getin		; Set byte from disk status
	cmp	#cr		; End at cr
	beq	rdds2		;
	sta	buff,y		; Save in buff
	iny			;
	bne	rdds1		;
rdds2:	lda	#0		;
	sta	buff,y		;
	lda	buff		; Get 1st digit
	sec			;
	sbc	#$30 		; Convert to binary
	beq	rddex 		; If error=0 exit
	pla			;
	pla			; Restore stack
	ldadr	buff		; Point to disk error
	jmp	errors		;
rddex:	rts			;
     
;
;	Rskp - do a skip return
;
     
rskp:	sta	hxwrk1		; Hold the accumulator
	stx	hxwrk2		; Hold x
	sty	hxwrk3		; Hold y
	pla			; Fetch the L.O. byte of the return address
	tax			; Put that in X
	pla			; Get the H.O. byte of the return address
	tay			; Stuff that in Y
	txa			; Get the L.O. byte back again
	clc			; Clear the carry flag
	adc	#$04		; Add in 4 (3 byte inst. + 1 for not doing rts)
	bcc	rskp2		; If there was no carry, continue
	iny			; Increment the H.O. byte
rskp2:	sta	saddr		; Store the L.O. byte
	sty	saddr+1		;	and the H.O. byte
	lda	hxwrk1		; Restore the accumulator
	ldx	hxwrk2		; Restore x
	ldy	hxwrk3		; Restore y
	jmp	(saddr)		; Jump to the new return address
	.end