





;*                          ------------------                          *
;*  ----------------------  BURST  SUBROUTINES  -- (rev 2) -----------  *
;*                          ------------------                          *
;*                                                                      *
;*   These assembly language sub-routines are designed for use in your  *
;* BASIC and machine code programs.  A BASIC program needs simply to    *
;* POKE the appropriate values into the variable locations shown below, *
;* and then SYS to the desired routine.  All of the BURST protocol and  *
;* handshaking is done for you.  The BASIC program can then PEEK any    *
;* values returned.                                                     *
;*
;*  The routines in this listing that require data buffer storage areas *
;* are passed the location of the buffer in BUFLOC.  BUFLOC points to   *
;* RAM location in RAM bank 0 of the start of the buffer.  Since the    *
;* KERNEL and I/O are needed, you must put BUFLOC below $C000.  But be  *
;* sure to put it in RAM above your BASIC text.  As a general rule,     *
;* work your way back from $C000 and you'll be OK.                      *
;*
;* To use these routines, your BASIC program must first BLOAD the file  *
;* 'BURST SUBS.BIN'.  The routines load at $1300, so they are in a      *
;* safe place below BASIC text area.                                    *
;*
;* There is no BURST FORMAT routine provided.  The following BASIC      *
;* commands will format physical tracks 10 through 20 of the disk with  *
;* 5 1024 byte sectors:                                                 *
;* 
;*     OPEN 1,8,15                                                      *
;*     PRINT#1,"U0";CHR$(3);CHR$(20);CHR$(5);CHR$(10);                  *
;* 
;*    Note the use of the semicolon (;) at the end of the statement.    *
;* This is very important!  If there was no semicolon, the C128 would   *
;* send a carriage return after the last parameter.  Since the 1581     *
;* counts the number of bytes sent to determine the number of optional  *
;* parameters that are being sent, it would misinterpret the carriage   *
;* return as the next optional parameter.  In this case, it would be    *
;* fill byte.  Any formatting errors can be checked via the command     *
;* channel.                                                             *
;*
;*   Since the BURST commands make use of the command channel to the    *
;* drive, the command channel must first be OPENed in your BASIC        *
;* program.  The logical file number which you assigned to the command  *
;* channel should be poked to LF before calling any of these routines.  *
;*                                                                      *
 







;********************************************************************
;  Variables - Values from BASIC can be POKEd, PEEKed to these areas.
;********************************************************************

        *=$1300

STATUS  .byte 0               ; status byte
DEV     .byte 8               ; device number
LF      .byte 8               ; logical file number
TRACK   *=*+1                 ; track 
SECTOR  *=*+1                 ; sector
NUMSEC  *=*+1                 ; Number of sectors.
BUFLOC  *=*+2                 ; Page # of buffer to get/put data.
SECSIZE *=*+1                 ; Sector size (1=256, 2=512, 4=1024)
SIDE    *=*+1                 ; Physical side of the disk (0 or 1).
MINSEC  *=*+1                 ; Minimum logical sector found in QUERY.
MAXSEC  *=*+1                 ; Maximum logical sector found in QUERY.
INTLV   *=*+1                 ; Physical interleave found in QUERY.
FLAG    *=*+1                 ; Empty track flag.
                              ;  This flag is used to indicate that the
;  track or data just read contains all 0's.  This is handy in some cases,
; such as during a disk copy program.  When a disk is formatted, the sectors
; are filled with 0's.  If a sector to be copied contains all 0's, then we 
; don't bother to write it to the destination disk


;****************************************************
;  Other variables used in the following routines....
;****************************************************


cmdline
        .byte 'u0'            ; Burst prefix.
        *=*+10                ; Parameter space for burst command.
cmdlen  *=*+1                 ; Length of the command string (# of bytes).
oldclk  *=*+1                 ; Status of clock line.
temp    *=*+1

;******************************************************************
;  JUMP TABLE of available burst routines.  SYS to these locations  
;  from BASIC.  The BURST routines themselves can then be modified
;  or customized without affecting the SYS locations from BASIC.
;******************************************************************

        *=$1340

J_INQUIRE_FORMAT        
        jmp INQUIRE_FORMAT              
J_PHYSICAL_READ
        jmp PREAD
J_LOGICAL_READ
        jmp LREAD
J_PHYSICAL_WRITE
        jmp PWRITE
J_LOGICAL_WRITE
        jmp LWRITE


J_MEMORY_READ
        jmp MEMORY_READ
J_MEMORY_WRITE
        jmp MEMORY_WRITE
J_DUMP_CACHE
        jmp DUMP_CACHE
J_QUERY_FORMAT
        jmp QUERY_FORMAT
J_COMPARE_MEMORY
        jmp COMPARE_MEMORY

;***************************************
;  Locations of important C128 stuff...
;***************************************

chkout=$ffc9                  ; kernel channel output 
clrchn=$ffcc                  ; kernel clear channel
setlfs=$ffba                  ; kernel set logical file number
setnam=$ffbd                  ; kernel set filename
bsout =$ffd2                  ; kernel basic input/output
spin_out=$ff47                ; Set up fast serial for input or output.
                              ;  SEC for output, CLC for input.
d2pra =$dd00                  ; C128 serial port location
clkout=$10                    ; slow serial clock output bit mask
clkin =$40                    ; slow serial clock input bit mask
d1icr =$dc0d                  ; 6526 CIA interrupt control register
d1sdr =$dc0c                  ; 6526 CIA serial data register
buffer=$fa                    ; zero page pointer variable
buffer2=$fc                   ; zero page pointer variable

;******************************
;  BURST command primitives
;******************************

PBURSTRD =$00                 ; Physical burst read.
PBURSTWR =$02                 ; Physical burst write.
LBURSTRD =$80                 ; Logical burst read
LBURSTWR =$82                 ; Logical burst write.
BURST_INQUIRE  =$04           ; Burst inquire.
DUMPCACHE =$9D                ; Dump track cache ('force' bit set)
BURST_QUERY =$8A              ; Query disk format.

;*********************************************************
;* ---------------  BURST ROUTINES  -------------------- *
;*********************************************************

LREAD         ;Logical sector read from the device indicated by LF.
              ;The track and sector are in TRACK, SECTOR. The location
              ;Status byte from drive is returned in STATUS.

        lda  #lburstrd        ;logical burst read command
        sta  cmdline+2          
        lda #$01
        sta SECSIZE           ;Logical sector size is always 256 bytes.
        jmp READ



PREAD         ;Physical sector read from device indicated by LF.
              ;The track and sector are in TRACK, SECTOR. The location
              ;of start of the C128 buffer to put the read data in BUFLOC.
              ;The physical sector size in SECSIZE (1=256,2=512,4=1024).
              ;Number of sectors in NUMSEC. 
              ;Physical side of the disk in SIDE (0 or 1).
              ;Status byte from drive is returned in STATUS.

        lda #PBURSTRD         ;Physical burst read command.
        ldx SIDE              ; Check which side to read from.
        beq 1$
        ora #$10              ; If side 1, then set bit in the command byte.
1$      sta  cmdline+2


READ

        lda $ff00             ;Save old MMU setup.
        pha

        lda #$0e              ;Set MMU for RAM0,KERNEL,I/O.
        sta $ff00

        jsr SETU0             ;Put "U0" at start of command string.

        lda TRACK       
        sta CMDLINE+3         ; track
        lda SECTOR
        sta CMDLINE+4         ; sector
        lda NUMSEC
        sta CMDLINE+5         ; Number of sectors to read.

        lda #$06              ; Length of command string.
        sta CMDLEN
        jsr  sendcmd          ; send cmd string

        lda  BUFLOC           ; Set up zero page indirect pointer.
        sta  BUFFER
        lda  BUFLOC+1
        sta  BUFFER+1

        ldy  #0               ; clear the 'empty sector(s)' flag.
        sty  flag

        sei                   ; No irq's allowed during handshake.
        bit  d1icr            ; clear pending

        jsr CLK_CHNG          ;Change state of clock.
 
1$      ldx  SECSIZE          ; Sector size gives # of pages per sector.

        jsr WAIT              ;Wait for fast byte (1st is status).
        lda  d1sdr            ;Get status byte.
        sta STATUS



        and  #15              ;Was there an error?
        cmp  #2               ; 
        bcs  5$               ; branch if error occured.

        jsr CLK_CHNG          ;Change clock so next byte is sent.

3$      jsr WAIT              ;Wait for the next byte.
        
        jsr CLK_CHNG          ;Change state of clock so next byte is sent.
        lda  D1SDR            ;Get the data byte
        sta  (buffer),y       ; and save it 
                              ;  while next byte is being transmitted.

        ora  flag             ;Update 'zero' sector flag.
        sta  flag

        iny                   ;Any more in this page?
        bne  3$

        inc BUFFER+1
        dex                   ;Loop for the # of pages per sector.
        bne 3$

        dec CMDLINE+5         ;Loop for the number of sectors.
        bne 1$

5$      cli

        pla                   ;Restore MMU to old configuration.
        sta $ff00

        rts

;****************************************************************

LWRITE        ;Logical sector write to the device indicated by LF.
              ;The track and sector are in TRACK, SECTOR. The location
              ;of start of C128 buffer containing write data in BUFLOC. 
              ;Status byte from drive is returned in STATUS.

        lda  #lburstwr
        sta  cmdline+2        ; burst write
        lda #$01
        sta SECSIZE           ; Logical sector size is always 256 bytes.
        jmp WRITE


PWRITE        ;Physical sector write to the device indicated by LF.
              ;The track and sector are in TRACK, SECTOR. The location
              ;of start of C128 buffer containing write data in BUFLOC.
              ;The physical sector size in SECSIZE (1=256,2=512,4=1024).
              ;Number of sectors in NUMSEC. 
              ;Physical side in SIDE.
              ;Status byte from drive is returned in STATUS.



        lda #PBURSTWR         ;Physical burst write command.
        ldx SIDE              ; Check which side to write to.
        beq 1$
        ora #$10              ; If side 1, then set bit in the command byte.
1$      sta  cmdline+2


WRITE   
        
        lda $ff00             ;Save old MMU setup.
        pha

        lda #$0e              ;Set MMU for RAM0,KERNEL,I/O.
        sta $ff00

        jsr SETU0             ;Put "U0" at start of command string.
        lda TRACK
        sta CMDLINE+3         ; track
        lda SECTOR
        sta CMDLINE+4         ; sector
        lda NUMSEC
        sta CMDLINE+5         ; Number of sectors to write.

        lda #$06
        sta CMDLEN            ;Command length.
        jsr  sendcmd          ; send cmd string

        lda  BUFLOC           ; Set up zero page indirect pointer.
        sta  BUFFER
        lda BUFLOC+1
        sta BUFFER+1

        lda  #clkin           ;Initial clock status.
        sta  oldclk

        ldy  #0
        sei                   ; no irq's during burst handshake

1$      ldx  SECSIZE          ; Sector size gives # of pages per sector.

        sec                   ;Turn fast serial to output mode.
        jsr  spin_out

2$      lda  d2pra            ;Wait for state change.
        eor  oldclk
        and  #clkin
        beq  2$

        eor  oldclk           ;Change status of OLDCLK.
        sta  oldclk

        lda  (buffer),y       ; get data 
        sta  d1sdr            ;  & send it

        jsr WAIT              ;Wait for the byte to be transmitted.


        iny
        bne  2$               ;Any more left in this page?

        inc  buffer+1
        dex                   ;Loop for the # of pages per sector.
        bne  2$

        clc                   ;Turn around to input mode to get STATUS.
        jsr  spin_out

        bit  d1icr            ; clear pending

        jsr  clklo            ; set clock low when ready for status

        jsr WAIT              ;Wait for the byte to be shifted in.
        lda  d1sdr            ;Get the status byte.
        sta STATUS            ;Save it.
        pha
        jsr  clkhi            ;Release the slow clock line.
        pla

        and  #15              ;Check for any error.
        cmp  #2 
        bcs  7$               ;  branch if there was an error.
        
        dec  CMDLINE+5        ;Loop for the number of sectors.
        bne  1$

7$      cli
        pla                   ;Restore old memory configuration.
        sta $ff00
        rts

;************************************************************

INQUIRE_FORMAT  ;Sends an INQUIRE DISK command to the drive indicate by
                ;the logical file (LF).  Status is returned in STATUS.

        jsr SETU0             ;Put "U0" at start of command string.
        lda  #BURST_INQUIRE   ; inquire burst command
        sta  cmdline+2
        lda #$03              ; length of command.
        sta CMDLEN
        jsr  sendcmd          ; send cmd string

        sei                   ;Disable interrupts during handshake.

        bit D1ICR             ;Clear any byte ready that's pending.

        jsr CLK_CHNG          ;Change clock so 1581 sends next.
        jsr WAIT              ;Wait for the byte to be shifted in.
        lda D1SDR             ;Get the status byte.
        sta STATUS            ;Save it off.
        cli
        rts


;************************************************************

QUERY_FORMAT  ;Sends a QUERY DISK FORMAT command to the drive indicate by
              ;the logical file (LF).  Physical track number to query 
              ;should be provided in TRACK.  Physical side should
              ;be provided in SIDE.  Status is returned in STATUS.
              ;Number of sectors found on the track returned in NUMSEC.
              ;Logical track number found in the sector headers returned
              ;in TRACK.  Minimum logical sector number found in the
              ;sector headers is returned in MINSEC.  The maximium
              ;logical sector is returned MAXSEC.  Physical interleave
              ;is returned in INTLV. 
              ;If an error is encountered in compiling this information
              ;(as indicated by STATUS), then none of the return values
              ;are valid (except STATUS).

        jsr SETU0             ;Put "U0" at start of command string.

        lda  #BURST_QUERY     ;QUERY DISK burst command
        ldx SIDE              ; Set the side bit accordingly.
        bne 4$
        ora #$10
4$      sta cmdline+2

        lda TRACK             ; Physical track offset.
        sta cmdline+3
        lda #$04              ; length of command.
        sta CMDLEN
        jsr  sendcmd          ; send cmd string

        sei                   ;Disable interrupts during handshake.
        bit D1ICR             ;Clear any byte ready that's pending.

        jsr CLK_CHNG          ;Change state of clock so 1581 sends next.
        jsr WAIT              ;Wait for the first status byte.
        lda D1SDR             ;Get the status byte (status of track 0).
        sta STATUS            ;Save it off.

        and #$0f              ;Was there an error?
        cmp #2
        bcs 5$                ; branch if there was an error.

        jsr CLK_CHNG          ;Change state of clock, so 1581 sends next.
        jsr WAIT              ;Wait for next status byte to be ready.
        lda D1SDR             ;Get it (status of track TRACK).
        sta STATUS            ;Save it.

        and #$0f              ;Was there an error?
        cmp #2  
        bcs 5$                ; branch if an error.
 
        jsr CLK_CHNG          ;Change state of clock, so 1581 sends next.
        jsr WAIT              ;Wait for 'number of sectors byte' to be ready.
        lda D1SDR             ;Get it.
        sta NUMSEC            ;Save it.


        jsr CLK_CHNG          ;Change state of clock, so 1581 sends next.
        jsr WAIT              ;Wait for 'logical track #' byte to be ready.
        lda D1SDR             ;Get it.
        sta TRACK             ;Save it.

        jsr CLK_CHNG          ;Change state of clock, so 1581 sends next.
        jsr WAIT              ;Wait for 'minimum sector #' byte to be ready.
        lda D1SDR             ;Get it.
        sta MINSEC            ;Save it.

        jsr CLK_CHNG          ;Change state of clock, so 1581 sends next.
        jsr WAIT              ;Wait for 'maximum sector #' byte to be ready.
        lda D1SDR             ;Get it.
        sta MAXSEC            ;Save it.

        jsr CLK_CHNG          ;Change state of clock, so 1581 sends next.
        jsr WAIT              ;Wait for 'interleave' byte to be ready.
        lda D1SDR             ;Get it.
        sta INTLV             ;Save it.

5$      cli
        rts

;***************************************************************

MEMORY_READ   ;Burst memory read of the 1581.  Page in 1581 memory to
              ;start reading at in .X, number of pages to read in .Y,
              ;location to store data in C128 memory in BUFLOC.  
              ;Logical file to be read from in LF.

        lda $ff00             ;Save old MMU setup.
        pha

        lda #$0e              ;Set MMU for RAM0,KERNEL,I/O.
        sta $ff00

        jsr SETU0             ;Put "U0" at start of command string.
        lda #$3E              ;('>') 'burst memory read' command string.
        sta CMDLINE+2         ;  ( "U0>MR" )
        lda #$4D              ;('M')
        sta CMDLINE+3
        lda #$52              ;('R')
        sta CMDLINE+4
        stx CMDLINE+5         ; 1581 page to start reading from.
        sty CMDLINE+6         ; # of pages to read.

        lda #$07              ; Length of command string.
        sta CMDLEN
        jsr  sendcmd          ; send cmd string

        lda  BUFLOC           ; Set up zero page indirect pointer.
        sta  BUFFER
        lda  BUFLOC+1
        sta  BUFFER+1


        lda  #0               ; clear the 'empty sector(s)' flag.
        sta  flag

        sei                   ; No irq's allowed during handshake.

        bit  d1icr            ; clear pending

        jsr CLK_CHNG          ;Change state of clock.

        ldy #0
3$      jsr WAIT              ;Wait for the byte to be shifted in.

        jsr CLK_CHNG          ;Change clock so next byte is sent.
        lda  d1sdr            ; get data
        sta  (buffer),y       ;  and save it while next byte is transmitted.

        ora  flag             ; Update 'zero' flag.
        sta  flag

        iny
        bne  3$               ;Any more in this page?

        inc BUFFER+1
        dec CMDLINE+6         ;Any more pages to do?
        bne 3$

5$      cli

        pla                   ;Restore old memory configuration.
        sta $ff00

        rts

;************************************************************

MEMORY_WRITE  ;Burst memory write to the 1581's memory.  The
              ;location in C128 memory to send data from in BUFLOC.
              ;The page in 1581 memory to start writing to in .X.
              ;The number of pages to write in .Y.  
              ;Logical file to be written to in LF.

        lda $ff00             ;Save old MMU setup.
        pha

        lda #$0e              ;Set MMU for RAM0,KERNEL,I/O.
        sta $ff00

        jsr SETU0             ;Put "U0" at start of command string.
        lda #$3E              ;('>') 'burst memory write' command string.
        sta CMDLINE+2         ;  ( "U0>MW" )
        lda #$4D              ;('M')
        sta CMDLINE+3
        lda #$57              ;('W')
        sta CMDLINE+4
        stx CMDLINE+5         ; 1581 page to start writing to.
        sty CMDLINE+6         ; # of pages to write.


        lda #$07              ; Length of command string.
        sta CMDLEN

        jsr  sendcmd          ; send cmd string

        lda  BUFLOC           ; Set up zero page indirect pointer.
        sta  BUFFER
        lda  BUFLOC+1
        sta  BUFFER+1

        lda  #clkin           ;Initial clock status.
        sta  oldclk

        ldy #0
        sei                   ;No IRQ's allowed during handshake.

        sec                   ; Set to output mode.
        jsr SPIN_OUT

2$      lda d2pra             ;Wait for state (slow clock line) change.
        eor OLDCLK
        and #CLKIN
        beq 2$

        eor OLDCLK            ;Change status of OLDCLK variable.
        sta OLDCLK

        lda (BUFFER),y        ;Get data to write.
        sta D1SDR             ;Send it.

        jsr WAIT              ;Wait for the byte to be sent.

        iny
        bne 2$                ;More in this page?

        inc BUFFER+1
        dec CMDLINE+6           
        bne 2$                ;Any more pages to send?

        cli

        pla                   ;Restore old memory configuration.
        sta $ff00

        rts


;**********************************************************


DUMP_CACHE    ;Dumps the track cache at 1581 $0C00 to the physical track
              ;specified in TRACK, on the side specified in SIDE.  The
              ;'force' bit is set, so it is written whether dirty or not.



        jsr SETU0
        lda #DUMPCACHE        ;Dump track cache command.

        ldx SIDE              ;  Set SIDE bit accordingly.
        beq 1$
        ora #$40

1$      sta CMDLINE+2         ;  Put the command byte into command string.
        lda TRACK
        sta CMDLINE+3         ;  Physical track to dump cache to.

        lda #4
        sta CMDLEN            ;Length of the command string.
        jsr SENDCMD

        sei                   ;Disable interrupts during handshake.

        bit D1ICR             ;Clear any byte ready that's pending.

        jsr CLK_CHNG          ;Change clock so 1581 will send status byte.
        jsr WAIT              ;Wait for byte to be shifted in.
        lda D1SDR             ;Get the status byte.
        sta STATUS            ;Save it off.

        cli
        rts


;*************************************************************

COMPARE_MEMORY  ;Compares memory blocks in the C128 memory.
              ;Number of pages to compare in .A.
              ;First page of first memory block in .X.
              ;First page of second memory block in .Y.
              ;If they are equal, then STATUS=0.

        sta temp

        lda $ff00             ;Save old MMU setup.
        pha

        lda #$0e              ;Set MMU for RAM0,KERNEL,I/O.
        sta $ff00

        stx buffer+1          ;Set up MSB of 1st memory pointer.
        sty buffer2+1         ;Set up MSB of 2nd memory pointer.
        ldx temp              ;Number of pages to compare.
        
        lda #0                ;Set up LSB's of memory pointers.
        sta buffer
        sta buffer2

        sta STATUS            ;Initialize STATUS.

        ldy #0


2$      lda (buffer),y
        cmp (buffer2),y
        beq 1$

        lda #$ff              ;Not equal!  Load STATUS with nonzero.
        sta STATUS
        bne 99$               ;  (branch always)

1$      iny
        bne 2$                ;More in this page?

        inc buffer+1
        inc buffer2+1
        dex                   ;# of pages counter.
        bne 2$
                
99$     pla                   ;Restore old memory configuration.
        sta $ff00

        rts

;**********************************************************

SENDCMD       ;Sends the command in CMDLINE to the logical file
              ;indicated by LF.  Length of the command should be in CMDLEN.

        ldx LF
        jsr  chkout           ; channel output (pointed to by .X)
        ldx  #0
        ldy  cmdlen           ; send cmd 
1$      lda  cmdline,x
        jsr  bsout
        inx
        dey
        bne  1$

        jsr  clrchn           ; send buffered char & eoi
        rts

;***********************************************************

SETU0   lda #85               ;'U'
        sta CMDLINE
        lda #48               ;'0'
        sta CMDLINE+1
        rts


CLKLO                 ; set clock low
        pha
        lda  d2pra              
        ora  #clkout
        sta  d2pra
        pla
        rts



CLKHI                 ; set clock high
        lda  d2pra
        and  #$ff-clkout
        sta  d2pra
        rts

CLK_CHNG              ;  change the state of the clock line output.
        lda D2PRA
        eor #clkout
        sta D2PRA
        rts

WAIT                  ;  wait for the shift register to be full or empty.
1$      lda #8
        bit D1ICR
        beq 1$
        rts


        .end
