1571-8.TXT rev 1a 96-11-06
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     THIS DOCUMENT IS COPYRIGHT (C) 1988, 1996 BY HERNE DATA
     SYSTEMS LTD.  THE MATERIAL CONTAINED HEREIN MAY BE FREELY
     USED FOR PERSONAL INFORMATION ONLY.  IF YOU REPRODUCE IT,
     THIS COPYRIGHT NOTICE MUST NOT BE REMOVED.  THIS MATERIAL
     MAY NOT BE EXPLOITED FOR COMMERCIAL PURPOSES.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

Herne Data Systems Ltd., 
PO Box 250, Tiverton, ON N0G 2T0 CANADA.  
Voice/fax 519-366-2732, 
e-mail herne@herne.com, 
internet: http://www.herne.com

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
 
                      Burst Write Protocol 
 
 
The 1571 disk drive Burst Command Instruction Set (BCIS) contains
a single command for writing data to a disk.  The burst WRITE
SECTOR command is somewhat analogous to the standard Commodore
DOS "Sector-Write" ("ub:" or "u2:") command.  Unfortunately,
there is no "FAST SAVE" command (corresponding to the burst mode
"FAST LOAD" command) which would allow you to write an entire
file in burst mode.  Similar to most other burst mode commands,
the write command will work with either MFM or GCR disks.  The
burst write is also faster than normal KERNAL controlled writing
to the 1571, although the difference in speed is not as great as
the difference in reading speeds.  The average speed for a burst
write using 256 byte sectors is about 500 bytes per second.  The
corresponding figure in normal 1571 mode is about 400 bytes per
second and in 1541 mode it is about 300 bytes per second.  In
1571 and burst modes, the write speeds are a factor of 3 to 5
slower than the corresponding read speeds.  The main reason for
this is because all sector write operations (including burst
mode) are followed by a sector read to verify that the sector was
written correctly.  In order to do this, the drive must wait
until the just written sector is positioned under the head again. 
This requires one full disk revolution, or about 0.2 seconds at
300 RPM, of overhead or dead time for each sector written.  
 
Unlike DOS's Sector-Write, burst write can be used to write
multiple sectors in succession (up to one track worth). 
 
This Chapter gives a step by step procedure for writing data to
disks in burst mode.  There are six basic steps to follow for a
burst mode write operation.  These are: 
 
(a)  log in the disk and send the burst write command
     string; 
 
(b)  set the serial port to fast output mode; 
 
(c)  send the data; 
 
(d)  set the serial port to fast input mode; 
 
(e)  read the burst status byte (repeat steps (b) to (e) for
     a  multi sector write); 
 
(f)  restore default I/O. 
 

Burst Write Setup

Similar to the burst mode read described in 1571-7.TXT, the
easiest way to log in the disk is to use the burst mode INQUIRE
DISK command by sending the command string: 
 
        "U0"+CHR$(4) 
 
This command will normally return a burst status byte which
indicates the condition on the drive controller.  If you are
interested in its value, the status byte can read using the
technique outlined in 1571-7.TXT.  If you are not interested in
the status byte (i.e. you are sure of the type of disk in the
drive) you can ignore the status byte by sending the burst WRITE
command string immediately following the INQUIRE DISK command. 
For a write operation, it may be a good idea to read the status
byte to check that you do have the correct disk in the drive. 
This is more important than for a read operation, because if you
do not have the correct disk, you can seriously damage the data
on the disk that you do have if you are not careful.   

The command string for a burst write is: 
 
     "U0"+CHR$(xx)+CHR$(track#)+CHR$(sector#)+CHR$(# of sectors) 
         +CHR$(next track) 
 
where xx can have the following values: 
Dec  Hex 
2    2    for a write to a GCR disk (either side) or MFM
          disk (side 0),   stop writing if error detected; 
 
18   12   same as above but for MFM disk side 1; 
 
66   42   same as value 2 but ignore errors; 
 
82   52   same as value 18 but ignore errors. 
 
The "track#" and "sector#"  are used to specify where you want to
begin reading on the disk.  As with the burst sector read
command, the maximum number of sectors which can be written is
equivalent to one track.  The actual number depends on the disk
format (for MFM disks) or the track number (for GCR disks).  If
you try to write more than one track worth of sectors, you will
overwrite sectors on the same track until the number of sectors
specified by the "# of sectors" parameter have been written. 
This could hopelessly corrupt your disk, so be careful when
specifying the number of sectors to write.   The next sector to
be written for multi sector writes depends on the value of the
burst mode SET SECTOR INTERLEAVE command.  For example, if an
interleave of 3 was specified, and the first sector written was
#1, then the next sector to write in a multi sector transfer
would be #4.
 
The "next track" parameter is useful if you are writing several
tracks in succession.  Normally before a write or read operation,
the disk head will return to its "park" position before going to
the specified track and sector.  If you specify the next track
option, the head will go to this next track directly without
going to park first.  This saves both time, and wear and tear on
your drive by preventing the head from bouncing around like a
yoyo.  Both the INQUIRE DISK and WRITE command string can be sent
via either a BASIC PRINT# statement or a machine language CHROUT
routine after an appropriate OPEN statement.   


Writng Data
 
The next step is to change the fast serial port direction from
the default "input" mode (data flow from the 1571 to the C-128)
to "output" mode (data flow from the C-128 to the 1571) and set
up the initial clock state.  This is done with a short machine
language routine using the new C-128 KERNAL SPIN/SPOUT routine
(Serial Port INput/Serial Port OUTput).  To set the mode to
output (SPOUT), the routine is called with the carry flag set: 
        SEI                 ; (DISABLE INTERUPTS) 
        SEC 
        JSR $FF47           ; (KERNAL SPIN/SPOUT ROUTINE) 
 
        LDA #$40 
        STA CLOCK 
 
 
The last two instructions start the test for the system clock
state on a high value.  The label "CLOCK" refers to any usable
RAM location (such as zero page $FA to $FF) which is used in
subsequent steps as a temporary storage location for testing the
state of the system clock. 
 
Once the system has been initialized, the data can be sent. 
Similar to the read protocol, data are sent to the 1571 based on
a simple toggle handshake using the Acknowledge and Ready for
Data (ARFD) line.  The procedure is as follows: 
 
         LDY #$00         ;   (RESET BUFFER DATA INDEX) 
 WAIT1   LDA $DD00        ;   (READ ARFD CLOCK STATE) 
         CMP $DD00        ;   (DEBOUNCE) 
         BNE WAIT1 
 
         EOR CLOCK 
         AND #$40          ;   (CHECK STATE OF ARFD CLOCK) 
         BEQ WAIT1 
 
         LDA ($FA),Y        ;  (GET DATA BYTE FROM RAM BUFFER) 
         STA $DC0C          ;  (SEND DATA) 
 
         LDA CLOCK 
         EOR #$40            ; (TOGGLE STATE OF "CLOCK" REGISTER)

         STA CLOCK 
 
  WAIT2  LDA #$08 
         BIT $DC0D            ; (WAIT UNTIL BYTE SENT) 
         BEQ WAIT2 
         INY 
         BNE WAIT1             ; (START OVER FOR NEXT BYTE) 
 
 
The above routine assumes a 256 byte sector of data is to be
transferred (remember MFM sectors can be 128, 256, 512 or 1024
bytes while GCR sectors written with this command are always 256
bytes).  Indexing routines for other sector sizes are given in
Table 11-1.   
 
The first instruction resets the data buffer index.  It is
assumed that the data buffer address is stored in zero page
locations $FA and $FB in standard low byte, high byte format. 
The next six instructions form a wait loop until the serial port
clock pulse is in the correct phase.   
 
The next two instructions retreive the data byte from memory and
send it to the 1571 via the CIA data registers.   
 
Because the size of the data buffer in BANK 15 (the default BANK
for I/O operations) is limited, the "LDA ($FA),Y" instruction can
be replaced with: 
 
         LDX #$3F        ; GO TO BANK 0
         STX $FF00 
 
         LDA ($FA),Y     ; GET DATA
 
         LDX #$00        ; BACK TO BANK 15
         STX $FF00 
 
This allows you to use most of BANK 0 free RAM as a data buffer. 
The next group of three instructions toggles the state of the
clock comparison register.   
 
The three instructions beginning with the "WAIT2" label form a
loop until the interupt control register (ICR) of CIA#1 signals
that the transmission of the data byte is complete.  The final
two instructions increment the buffer pointer and repeat the
process for the next byte until a complete sector has been sent. 


Write Status
 
The fourth step in the write process is used to check that the
data have been successfully written to the 1571.  The 1571
returns a status byte after each sector has been written.  To
read this byte, the fast serial port must first be set to the
read (SPIN) direction followed by a sending ready signal to the
1571.  This is done with: 
 
         CLC            ; (CLEAR CARRY FLAG) 
         JSR $FF47      ; (SET SPIN/SPOUT TO SPIN) 
         BIT $DC0D      ; (RESET CIA ICR) 
 
         LDA $DD00 
         ORA #$10       ; (SET ARFD CLOCK LOW) 
         STA $DD00 
 
 
The status byte can then be read with a standard burst mode read:

 
         LDA #$08 
  WAIT3  BIT $DCOD       ; (WAIT FOR BYTE INTERUPT) 
         BEQ WAIT3 
 
         LDA $DC0C       ; (READ STATUS) 
         STA $FA         ; (STORE IT SOMEWHERE IF YOU WANT) 
 
         LDA $DD00 
         AND #$EF         ; (SET ARFD CLOCK TO HI) 
         STA $DD00 
 
If more sectors are to be written, the whole process starts over
again from step 2 (set serial port to SPOUT) until the specified
number of sectors have been written.   
 

Closing Up

Once all sectors have been written, the final step is to restore
default input/output (I/O) channels: 
 
          CLI 
          JSR $FFCC           ; (KERNAL CLRCHN ROUTINE) 
 
 
If no longer required, the command channel can also be CLOSEd at
this point. 
 
That, my friends, is all there is to writing in burst mode. 

 
 
 
  
TABLE 11-1: SUMMARY OF ASSEMBLY LANGUAGE BURST MODE WRITE
ROUTINES 
 
 
General write-a-burst-byte routine 
 (used by all subroutines below) 
 
 
  WRITE  LDA $DD00 
         CMP $DD00 ;DEBOUNCE ARFD CLOCK 
         BNE WRITE 
         EOR $0D00 ; TEMP STORAGE FOR CLOCK STATE
         AND #$40 
         BEQ WRITE  
         LDX #$3F  ;SWITCH TO BANK 0 
         STX $FF00  
         LDA ($FA),Y ;GET DATA 
         LDX #$00  ;BACK TO BANK 15 
         STX $FF00  
         STA $DC0C ;SEND DATA 
         LDA $0D00 ; TOGGLE TEMP CLOCK
         EOR #$40 
         STA $0D00 
         LDA #$08 
   WAIT  BIT $DC0D ; WAIT TILL BYTE SENT 
         BEQ WAIT 
         RTS 
 
 
 
 ; READ STATUS BYTE ROUTINE 
 
  READST  CLC 
          JSR $FF47  ;SET SPOUT 
          BIT $DC0D  ;RESET ICR 
          LDA $DD00 
          ORA #$10   ;SET ARFD INPUT 
          STA $DD00 
          LDA #$08 
   WAITR  BIT $DC0D 
          BEQ WAITR  ;WAIT FOR BYTE 
          LDA $DC0C  ;GET STATUS 
          STA $0D01  ;STASH IT 
          LDA $DD00 
          AND #$EF   ;RESET AFRD 
          STA $DD00 
          RTS 
                                                                  
              
NOTE:     before using any of the following routines,
          you must load zero page locations $FA and $FB
          with the low and high bytes of the start of
          your data buffer and call the appropriate
          burst mode command. Location $0D00 in the
          RS-232 buffer is used as a temporary storage 
          register for testing the clock phase. $0D01
          is used to store the status byte if desired.
     
   
; WRITE N 128 BYTE SECTORS:  
         LDX #NUMBER_OF_SECTORS_TO_WRITE  
         STX $FC 
         LDX #$00 
         STX $FD ;# SECTORS WRITTEN 
         LDA #$40  
         STA $0D00; TEMP STORAGE 
         SEI  
 
  NEXTS  LDY #$00  ; RESET INDEX
         SEC  
         JSR $FF47; SET SPOUT  
  NEXTB  JSR WRITE 
         INY  
         CPY #$80; END OF SECTOR  
         BNE NEXTB 
         JSR READST; READ STATUS  
         LDX $FD   
         INX  
         CPX $FC   ; LAST SECTOR?  
         BEQ END 
         STX $FD  
         TYA   
         CLC 
         ADC $FA  ; INCR PNTR 128 BYTES 
         STA $FA 
         BCC NEXTS ; READ NEXT SECTOR  
         INC $FB 
         JMP NEXTS  
 
     END  CLI    
          JSR $FFCC ; CLRCHN 
          RTS  
 
 
; WRITE N 256 BYTE SECTORS: 
                                                                  
          LDX #NUMBER_OF_SECTORS_TO_WRITE 
           STX $FC 
           LDX #$00 
           STX $FD ;# SECTORS WRITTEN 
           LDA #$40 
           STA $0D00; TEMP STORAGE 
           SEI 
 
    NEXTS  LDY #$00 
           SEC 
           JSR $FF47; SET SPOUT 
    NEXTB  JSR WRITE 
           INY 
           CPY #$00; END OF SECTOR 
           BNE NEXTB 
           JSR READST; READ STATUS 
           LDX $FD 
           INX 
           CPX $FC   ; LAST SECTOR? 
           BEQ END 
           STX $FD 
           INC $FB 
           JMP NEXTS ;READ NEXT SECTOR 
 
      END  CLI  
           JSR $FFCC 
           RTS 
    
    
; WRITE N 512 OR 1024 BYTE SECTORS:  
 
           LDX #NUMBER_OF_SECTORS_TO_WRITE 
           STX $FC 
           LDX #$00 
           STX $FD ;# SECTORS WRITTEN 
           LDA #$40 
           STA $0D00; TEMP STORAGE 
           LDX #SECTOR_SIZE/256 
           STX $FE  ; SAVE IT TWICE
           STX $FF 
           SEI 
 
    NEXTS  LDY #$00 
           SEC 
           JSR $FF47; SET SPOUT 
    NEXTB  JSR WRITE 
           INY 
           CPY #$00; END OF PAGE? 
           BNE NEXTB 
           LDX $FE 
           DEX 
           STX $FE 
           INC $FB 
           CPX #$00 ;END OF SECTOR? 
           BNE NEXTB 
           JSR READST; READ STATUS 
           LDX $FF 
           STX $FE 
           LDX $FD 
           INX 
           STX $FD 
           CPX $FC   ; LAST SECTOR? 
           BNE NEXTS 
 
      END  CLI 
           JSR $FFCC 
           RTS 
 
 
