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