; DASM V2.12.04 source

; Burst loader routine, minimal version to allow loading of programs upto
; 63k in length. Directory is loaded with the normal load routine.
;
; (c)1987-99 Pasi Ojala, Use where you want, but please give me some credit
;
; This program needs SRQ to be connected to CNT1 and DATA to SP1 (CIA1).
; Cassette drive won't work with those wires connected if the disk drive
; is turned on. (SRQ is connected to cassette read line.)
;
; SRQ = Bidirectional fast clock line for fast serial bus
; DATA= Slow/Fast serial data (software clocked in slow mode)
;
; In C128D (64-mode) you should use CIA2, because it has special hardware
; which inhibits the use of CIA1 (or so I'm told). References to CIA in this
; program should be changed accordingly and some enable-disable stuff must
; be rewritten. Some other burst implementations may also use CIA2.
;
; A short description of the burst protocol and commands can be found
; from the "1581 Disk Drive User's Guide".

	processor 6502

	ORG $0801
	DC.B $b,8,$ef,0	; '239 SYS2061'
	DC.B $9e,$32,$30,$36,$31
	DC.B 0,0,0

install:
	; copy first block to $2a7..$2ff
	ldx #block1_end-block1-1	; Max $58
0$	lda block1,x
	sta _block1,x
	dex
	bpl 0$
	; copy second block to $334..$3ff
	ldx #block2_end-block2		; Max $cc
1$	lda block2-1,x
	sta _block2-1,x
	dex
	bne 1$

	lda $0330	; load vector
	ldx $0331
	cmp #<MyLoad
	bne 2$
	cpx #>MyLoad
	beq 3$
2$	sta OldVrfy+1	; chain the old load vector
	stx OldVrfy+2
	lda #<MyLoad	; install our loader
	sta $0330
	lda #>MyLoad
	sta $0331
3$	rts

block1
#rorg $02a7
_block1
OldLoad	lda #0
OldVrfy	jmp $f4a5	; The 'normal' load.

MyLoad:	;sta $93
	cmp #0		; Is it a prg-load-operation ?
	bne OldVrfy	; If not, use the normal routine
	stx $ae		; Store the load address
	sty $af
	tay		; ldy #0
	lda ($bb),y	; Get the first char from filename
	ldy $af
	cmp #$24	; Do we want a directory ($) ?
	beq OldLoad	; Use the old routine if directory
	cmp #58		; ':'
	beq OldLoad

	; Activate Burst, the drive then knows we can handle it
	sei		; We are polling the serial reg. intr. bit
	ldy #1		; Set the clock rate to the fastest possible
	sty $dc04
	dey		; = ldy #0
	sty $dc05
	lda #$c1
	sta $dc0e	; Start TimerA, Serial Out, TOD 50Hz
	bit $dc0d	; Clear interrupt register
	lda #8		; Data to be sent, and interrupt mask
	sta $dc0c	; (actually we just wake up the other end,
0$	bit $dc0d	;  so that it believes that we can do
			;  burst transfers, data can be anything)
	beq 0$		; Then we poll the serial (data sent)
	; Clears the interrupt status

	; This program assumes you don't try to use it on a 1541
	; If you try anyway, your machine will probably lock up..

	lda #$25	; Set the normal (PAL) frequence to TimerA
	sta $dc04	; Change if you want to preserve NTSC-rate
	lda #$40
	sta $dc05
	lda #$81
	jmp LoadFile

GetByte	lda #8		; Interrupt mask for Serial Port
0$	bit $dc0d	; Wait for a byte
	beq 0$		;  (Serial port int. bit changes, hopefully)
	;ldy $dc0c	; Get the byte from Serial Port Register
ToggleClk:
	lda $dd00	; Toggle the old serial clock (=send Ack)
	eor #$10	;  so that the disk  drive will start
	sta $dd00	;  sending the next byte immediately
	;tya		; return the value in Accumulator, update flags
	lda $dc0c	; Get the byte from Serial Port Register
	rts
#rend
block1_end


block2
#rorg $0334
_block2

LoadFile:
	sta $dc0e	; Start TimerA, Serial IN, TOD 50Hz (PAL)
	;cli

	jsr $f5af	; searching for ..

	lda $b7		; Preserve the filename length
	pha
	lda $b9		; Do the same with secondary address
	sta $a5		; We store it to cassette sync countdown..
			;  No cassette routines are used anyway, as
	lda #0		;  this prg is in cassette buffer..
	sta $b7		; No filename for command channel
	lda #15
	sta $b9		; Secondary address 15 == command channel
	lda #239
	sta $b8		; Logical file number (15 might be in use?)
	jsr $ffc0	; OPEN
	sta ErrNo+1
	pla
	sta $b7		; Restore filename length
	bcs ErrNo	; "device not present",
			; "too many open files" or "file already open"
	; Send Burst command for Fastload
	ldx #239
	jsr $ffc9	; CHKOUT Set command channel as output
	sta ErrNo+1
	bcs NoDev	; "device not present" or other errors

	; Bummer, the interrupt status register bit indicating fast serial
	; will be cleared when we get here..

	ldy #3
3$	lda BCMD-1,y	; Burst Fastload command
	jsr $ffd2
	dey
	bne 3$
	; ldy #0
1$	lda ($bb),y
	jsr $ffd2	; Send the filename byte by byte
	iny
	cpy $b7		; Length of filename
	bne 1$
	jsr $ffcc	; Clear channels

	sei
	jsr $ee85	; Set serial clock on == clk line low
	bit $dc0d	; Clear intr. register
	jsr ToggleClk	; Toggle clk

	jsr HandleStat	; Get Initial status
	pha		; Store the Status

	;jsr $f5d2	; loading/verifying
	; (uses CHROUT, which does CLI, so we can't use it)

; We could add a check here..
; if we don't have at least two bytes, we cannot read load address..

; It seems that for files shorter than 252 bytes the 1581 does not count
; the loading address into the block size.

	jsr GetByte	; Get the load address (low) - We assume
			; that every file is at least 2 bytes long
	tax
	jsr GetByte	; Get the load address (high)
	tay		; already in Y
	lda $a5		; The secondary address - do we use load
			;  address in the file or the one given to
	bne Our		;  us by the caller ?
	stx $ae		; We use file's load addr. -> store it.
	sty $af
Our	ldx #252	; We have 252 bytes left in this block
	pla		; Restore the Status
	bne Last	; If not OK, it has to be bytes left
Loop	jsr GetAndStore	; Get X bytes and save them
	jsr HandleStat	; Handle status byte
	beq Loop	; If all was OK, loop..
Last	tax		; Otherwise it is bytes left. Do the last..
	jsr GetAndStore	; Get X number of bytes and save them
	jsr $ee85	; Serial clock on (the normal value)
	lda #239
	jsr $ffc3	; Close the command channel
	clc		; carry clear -> no error indicator
	bcc End

FileNotFound:
	pla		; Pop the return address
	pla
	jsr $ee85	; Serial clock on (the normal value)
	lda #4		; File not found
	sta ErrNo+1
NoDev	lda #239
	jsr $ffc3	; Close the command channel
ErrNo	lda #5		; Device not present
	sec		; carry set -> error indicator
End	ldx $ae		; Loader returns the end address,
	ldy $af		;  so get it into regs..
	cli
	rts		; Return from the loader

HandleStat:
	jsr GetByte	; Get a byte (and toggle clk to start the
			;  transfer for next byte)
	cmp #$1f	; EOI ?
	bne 0$
	jmp GetByte	; Get the number of bytes to follow and RTS
0$	cmp #2		; File Not Found ?
	bcs FileNotFound	; file not found or read error
	; code 0 or 1 -> OK
	ldx #254	; So, the whole block is coming
	lda #0		; No error -> Z set
	rts

GetAndStore:
	jsr GetByte	; Get a byte & toggle clk
	;sta $d020
	ldy #$34
	sty 1		; ROMs/IO off (hopefully no NMI:s occur..)
	ldy #0
	sta ($ae),y	; Store the byte
	ldy #$37
	sty 1		; Restore ROMs/IO (Should preserve the
			;  state, but here it doesn't..)
	inc $ae		; Increase the address
	bne 0$
	inc $af
0$	dex		; X= number of bytes to receive
	bne GetAndStore
	rts

BCMD:	dc.b $1f, $30, $55	; 'U0',$1F == Burst Fastload command
				; If $9F, Doesn't have to be a prg-file
#rend
block2_end

