High-Density FDC for YASBEC by Harold F. Bower Paul Chidley's excellent YASBEC (Yet Another Single-Board Eight- bit Computer) has proven to be remarkably versatile, and suffers few weaknesses. The most desirable feature was addressed by Jim Thale in 1994 when he produced the YASMIO expansion that added a "High-Density" floppy diskette controller (which can also handle 8" drives) as well as additional serial and parallel ports. Having worked closely with Jim to build the prototypes as well as write the drivers for the Banked and Portable (B/P) Bios, it was natural to draw on this experience when I built a YASBEC-based laptop a year ago. The circuit modifications in this article might also be easily adaptable to other computers. Since I could not afford the space (or power) for a YASMIO in the laptop, a circuit modification to the YASBEC was the course of action. Borrowing on the circuitry from the YASMIO, I used the National Semiconductor DP8473 as the core since it does nearly everything required in one chip. While the part has been discon- tinued by National, it is still available from Digi-Key as of this writing. In addition to this chip, only a 24 MHz Monolithic oscillator, a few resistors, capacitors, a piece of perfboard and some pins are required for the entire modification. As a further benefit, several parts may be removed from the YASBEC since the 8473 includes the drivers on-board! One of the main constraints going in to this project was to make minimal trace cuts and other modifications to the basic YASBEC. Since the fundamental goal is to replace the Western Digital 1772 controller (U14), any signals appearing on that chip are assumed to be available by plugging into the socket when the chip is removed. This furnishes us with power, 8 data lines, Address lines A0-A2, and Chip select for addresses 68-6FH. Also avail- able are several lines needed for the Floppy cable connector. Missing from the needed signals are Read and Write (active low), and a Reset signal of the proper polarity. These three signals are, however, available from a socket adjacent to the 1772 which was designed for a 8231A Math Coprocessor (U13). In addition, more power and ground pins are available to provide better noise performance. Six additional signals are still needed, but they can be handled by a short length of ribbon cable and a home-made plug made from in-line machined-pin socket strips. With the sockets for U13 and U14 available, we create a footprint for the modification. The prototype, as well as a duplicate to prove the design for this article are based on a piece of "pad- per-hole" perfboard measuring 1.5" x 3.0". Connections between this board and the YASBEC sockets are via pins which plug into the sockets and into pad holes on the perfboard. Since the two sockets are not exact multiples of 0.1" apart, some mis-alignment exists, but not to an excessive degree. Before you begin this project, be sure you have any needed files on a bootable hard disk. With "Murphy" alive and well, you should prepare a second hard drive as well, since you will not be able to boot from floppy diskettes from the time you begin this project until you have the modification working and modify the Boot ROM to recognize the new circuitry. For the bold of heart, charge on... The first step is to remove all unnecessary parts from the YAS- BEC. Remove the 8231A (U13) and FD1772 (U14) from their sockets. Carefully unsolder and remove the 8 MHz Monolithic oscillator (U24), the 74HC74 surface-mount IC from the bottom of the board (U23), and the two surface-mount drivers; 74AC04 (U22) and 74AC00 (U18) from the top of the board next to the 34-pin DIP header. Care in removal of these latter two chips is essential since you will need to solder wires to many of the pads for these ICs. Next, solder short "U"-shaped pieces of wire-wrap wire across some of the pads where U22 formerly resided to connect signals from the DIP header directly to pins on the U14 socket. Five such jumpers are required to connect pins 1-2 (MOTOR_ON), 3-4 (STEP), 5-6 (WRITE_GATE), 10-11 (WRITE_DATA) and 12-13 (DIR_SEL). On the bottom of the board, solder a short jumper wire between pin 26 of U14 to Pin 2 of the 34-pin DIP floppy cable connector. This lead will be used to command floppy drives to switch between "High-Density" and normal MFM by latching a "1" or "0" in bit 6 of the 74HC273 at U20. This is the only bit of that chip used in the modified design, since the other six bits which were needed by the original 1772 are no longer needed. Note that wiring a TTL/CMOS level signal such as this directly to the floppy cable violates the normal open-collector/open-drain drive, but works in practice if the cable lengths are short, and you are careful not to short the pin or tie it directly to +5 volts. Set the YASBEC aside for the time being. We will return to it later to wire a small cable to pick up six more signals to/from the floppy con- nector. Gather all parts needed to construct the small adapter board. Component selection is relatively non-critical except for those used in the analog data filters. Contrary to the filter design used in the YASMIO which accommodated rates through 1000 kbps, this circuit includes only the 250 and 500 kbps capability. I have had best results using either a mylar or Silver Mica capaci- tor for the .001 microfarad unit, and mylar for the .027 and .047 microfarad items. Careful selection of these capacitors and the two 560 ohm resistors will provide the most reliable data recov- ery. Finally, wire the adapter according to the schematic. The six leads shown on the schematic extended slightly to the right are the leads which will be wired to the extender cable and should be terminated on the adapter in six pin female header. Perhaps the easiest way to begin is to place the male pins in the respective sockets on the YASBEC, then place the perfboard on the pins in the desired position. Tack-solder a few pins in each row to retain the positioning and carefully pry the board with pin strips out of the YASBEC sockets. Next, position the 52-pin PLCC socket for the DP8473 and solder the unused pins to hold the socket in place. Finally, wire the remaining components using wire-wrap wire for connections. When the board is fully wired, return to the YASBEC. Five of the six external connections will be made to the pads remaining after removal of U18 and U22, but one (DSKCHG) must be made from the bottom of the board. This may be made by drilling a small hole near pin 32 on the floppy connector. Hold the YASBEC up to a bright light and locate a free spot with no trace on either side of the PCB. Mark the spot and drill with a 1/16" drill or small- er. Feed a small stranded wire through the hole and solder it to the resistor lead which is wired to a trace running only to pin 34 of the Floppy Drive connector. In the original circuit, this was the /READY signal and was simply pulled high. The new cir- cuit uses it for the /DSKCHG signal which is typically unused by the software, but available. Next connect small flexible strand- ed wires to the following pads for removed ICs: U22 Pin 8 (SIDE), U18 Pins 3, 6, 11, and 8 (/SELECT0-/SELECT3). A piece of flexi- ble ribbon cable may be used if much care is used to prevent stress from pulling the pad traces from the PCB. After the wires are installed, install the adapter board by plugging it into the sockets, and route the wires to the header on the adapter. Insert a 6-pin male strip into the header, and solder the wires to the respective pins. This method allows the board to be removed if necessary rather than fixing it into position by soldering it in place. Now comes the hard part..the software! If you heeded the intro- ductory warnings about preparing a bootable hard drive, you should be able to still use the computer by booting from the hard disk, but the floppy disks will be useless until a modified Bios is prepared. Anyone proceeding this far should have the knowl- edge to perform this, so we will concentrate on the requirements for booting from Floppy Disks, or the code that must be burned into ROM. Rather than specifically addressing the YASBEC ROM, we will generically cover code fragments suitable for integrating in any form. It might have been simpler to extend the DENS signal from the 8473 directly to pin 2, but that would have required all dis- kettes to conform explicitly to the IBM-PC conventions for Hi/Lo density and speed. Maintaining this signal under your control by latching it with the 'LS273 provides the option of handling older drives which may not be so "standardized". The software frag- ments listed here do correspond to 3.5" and 5.25" drives strapped just as they came from a clone. The primary routine is the one which attempts to identify the drive and media type. As listed, it can take many seconds to sort out the correct format due to the many combinations. If you restrict the choice of drive to a particular type, then you can eliminate the other alternatives and significantly reduce the time needed to identify the drive/format. Assuming you have a bootable machine (recall the hard drive warning?), you might want to modify a BIOS based on these frag- ments and test the hardware adapter, then integrate the fragments into the boot ROM. In this way, you can become familiar with the nuances of the circuit and its capabilities. A replacement Floppy Module for B/P Bios is available to B/P Bios owners for the asking (E-Mail HalBower@worldnet.att.net). NOTE: 5 Dec 2001 - The replacement is in the 2001 GPL Release of the YASBEC B/P Bios code available at: http://home.att.net/~halbower ---------------------------------------------------------------- ; Boot ROM Fragments for National DP8473 grafted onto YASBEC. ; Harold F. Bower, 14 March 1998 FDCTRL EQU 40H ; Floppy Drive Control Register ; only B5 used for Density signal to Cable pin 2 FDCBAS EQU 68H ; DP8473 Base Address (Same as 1772) DCR EQU FDCBAS+2 ; Drive Control Register MSR EQU FDCBAS+4 ; Main Status Register DR EQU FDCBAS+5 ; Data Register DRR EQU FDCBAS+7 ; Data Rate Register/Disk Changed Bit in B7 ; Data needed for DP8473 FDC Controller boot code dmaAd0: DEFS 2 dmaAd1: DEFS 2 HdFlg: DEFS 1 ; "HD" Byte for FDCTRL and DRR Comnd: DEFS 1 ; DP8473 Command Block HDR: DEFS 1 ; - Head (B2)/Drive(B1,0) Byte TRK: DEFS 1 ; - Track HD: DEFS 1 ; - Head (B0) SECT: DEFS 1 ; - Sector NBYTS: DEFS 1 ; - Number of Bytes (0/FF) EOT: DEFS 1 ; - Ending Track # GPL: DEFS 1 ; - Gap3 Length DTL: DEFS 1 ; - Data Length Flag ST0: DEFS 1 ; DP8473 Status Block - Status Byte 0 ST1: DEFS 1 ; - Status Byte 1 ST2: DEFS 1 ; - Status Byte 2 RC: DEFS 1 ; - Cylinder # RH: DEFS 1 ; - Head # RR: DEFS 1 ; - Sector # RN: DEFS 1 ; - Sector Size (3..0) secTbl: DEFS 2 ; Addr of Sector Table reTrys: DEFS 1 ; Number of overall Retries on Hi-level boot count: DEFS 1 ; Number of 100 mS ticks for Timeout nSides: DEFS 1 ; Number of Sides (0/1) on diskette fdcOk: DEFS 1 ; Flag to show that DP8473 detected (0=No) secOff: DEFS 1 ; Sector Offset Number from Decode Tries ; Code fragment to reset controller via software. ; This snippet can also be made into a subroutine and used to ; de-select the controller and turn motors off. (Add RETurn to end) XOR A ; Motors off, Reset OUT (DCR),A LD B,(IX+0) LD B,(IX+0) ; (delay) LD A,00000100B ; Clear Reset OUT (DCR),A ;..... ; Deselect Floppys and reset Controller ; Include early in Boot ROM Initialization sequence. DESELCT: XOR A ; Motors Off, Reset mode OUT (DCR),A EX (SP),HL EX (SP),HL ; (delay) LD A,00000100B ; re-activate Controller OUT (DCR),A RET ;..... ; Check for Presence of Floppy Controller ; Exit: A = 0, Zero Flag Set (Z) if NO Controller detected ; A <> 0, Zero Clear (NZ) if Controller found. ; NOTE: This relies on a timer routine in mS increments. CKFDC: CALL FPurg ; Clear the Controller, Make Ready LD A,04H ; Sense Drive Status OUT (DR),A LD A,20 CALL DLYmS ; pause 20 mS IN A,(MSR) CP 90H ; Ready for next byte? JR NZ,NoFDC ; ..Exit No FDC if Not XOR A OUT (DR),A ; Say Drive 0, Hd 0 LD A,20 CALL DLYmS ; delay IN A,(MSR) CP 0D0H ; Ready with Result? JR NZ,NoFDC ; ..quit No FDC if Not IN A,(DR) ; Else Clear ST3 Status CALL WRdy LD A,03H ; Specify Drive Parameters OUT (DR),A CALL WRdy LD A,[16-6]*16+15 ; 6/12 mS Step Rate, 240/480 mS Unload Time OUT (DR),A CALL WRdy LD A,34*2 ; 34/68 mS Head Load Time OR 01H ; No DMA (LSB=1) OUT (DR),A DEFB 03EH ; ..fall thru w/"LD A,0AFH" setting NZ NoFDC: XOR A ; Else LD (fdcOk),A ; say No FDC present RET ;..... ; Attempt Boot from Floppy Drive FBOOT: XOR A LD HL,9000H ; Clear Boot Sctr Flag byte LD (HL),A CALL HDens ; Start by Setting to 3.5" High-Density EI ; (insure Ints Active) LD A,0F4H ; All motors On OUT (DCR),A CALL DLY10M ; (wait 1 Sec) LD A,3 LD (reTrys),A FBoot0: CALL CkKey ; Abort if Key Pressed CALL Home ; Start by Homing the Heads JR NZ,NoFDC ; ..abort if Bad CALL RdID ; Read ID and Set Values JR Z,FBoot1 ; ..jump if Ok LD HL,reTrys DEC (HL) ; Trys Exhausted? JR NZ,FBoot0 ; .try again if Not RET ; ..else Quit FBoot1: LD A,3 ; Try 3 times LD (reTrys),A FBoot2: LD HL,9000H ; Set Location for Boot Sector LD (dmaAd0),HL LD A,(secOff) INC A ; Get First Sector LD (SECT),A ; to Comnd Blk XOR A LD (TRK),A ; Track = 0 CALL ReadF ; Attempt a Read JR Z,FBoot3 ; ..jump if Ok LD HL,reTrys DEC (HL) ; Trys Exhausted? JR NZ,FBoot2 ; .jump if Not RET ; ..else Quit FBoot3: CALL CkKey ; Check Keypress, go to Monitor if press LD A,(9000H) ; Get First byte of Boot Sector CP 21H ; Is it LD HL,nnnn? JP Z,9000H ; ..jump to Boot Sector if So CP 3EH ; Is it LD A,nn? JP Z,9000H ; ..jump to Boot Sector if So JR NoFDC ;..... ; Home the Heads to Track 0 Home: LD B,3 XOR A LD (HDR),A ; Set Drive 0, Head 0 Home0: PUSH BC LD BC,2*256+07H ; Recalibrate Command CALL FDCmd ; Execute CALL FDCDn ; Check for Status CALL FSnsI ; Sense Interrupt to Check Results POP BC AND 00010000B ; Errors? RET Z ; ..return if Not DJNZ Home0 ; Else loop if more tries OR A ; then Set NZ RET ;..... ; Read Sector ID and Set values if Interpretable. ; Enter: All Motors ON ; FDC (via HdFlg) set to High-Density 3.5" parameters RdID: PUSH BC ; Save regs PUSH HL XOR A ; Drive A:, Head 0 LD (HDR),A ; Initially Set to 500 kbps, 3.5" Format (1.76 MB HD) LD BC,2*256+4AH ; Attempt MFM ID Read CALL FDCmd CALL RdIDSt ; Monitor Status w/timeout JR Z,RdID0 ; ..jump if ID Record Read Ok ; Try 250 kbps, 3.5" Format (800 kB Ampro DSQD) LD A,02H ; Load settings CALL StDens ; Set LD BC,2*256+4AH CALL FDCmd ; Attempt Another MFM Sector ID Read CALL RdIDSt ; Monitor Status w/timeout JR Z,RdID0 ; ..jump if ID Record Read Ok ; Try PC HD 300 kbps 5.25" Formats ; (400/800 kB Ampro DSDD/DSQD) LD A,01H ; Load settings CALL StDens ; Set LD BC,2*256+4AH CALL FDCmd ; Attempt Another MFM Sector ID Read CALL RdIDSt ; Monitor Status w/timeout JR Z,RdID0 ; ..jump if ID Record Read Ok ; Else try 250 kbps, 5.25" Formats ; (400/800 kB Ampro DSDD/DSQD) LD A,22H ; Load settings CALL StDens ; Set CALL DLY10M ; pause 1 Sec for Motor to Settle LD BC,2*256+4AH ; Read MFM ID CALL FDCmd CALL RdIDSt ; Monitor Status w/timeout JR NZ,RdIDX ; ..quit if Not good Read RdID0: XOR A ; Good ID Read, Preset Command Record for Boot LD (HDR),A ; Head 0, Unit 0 LD (HD),A ; Head 0 DEC A LD (DTL),A ; Length=FF LD A,13 LD (GPL),A ; Gap3 = 13 LD A,(RN) LD (NBYTS),A ; Set Sector Size LD HL,SKEW40 CP 2 ; 512-byte Sctrs? JR NZ,RdID1 ; ..jump if Not LD A,(HdFlg) ; Ensure we are Not at 500 kbps AND 03H JR Z,RdIDX ; ..Error Exit if 512-byte sctrs in HD mode RdID4: LD A,(RR) ; Else validate Sector # for DSDD/DSQD CP 16+1 ; Valid Sector # for our formats? LD A,16 ; (assume Ok) JR NC,RdIDQ ; ..jump if Ok RdIDX: POP HL ; Restore Regs POP BC OR 0FFH ; Set Error Flag RET RdID1: CP 3 ; 1024-byte Sctrs? JR NZ,RdIDX ; ..Error if Not LD HL,SKEW80 LD A,(HdFlg) AND 03H ; Anything other than 500 kbps (HD)? JR NZ,RdID4 ; ..jump if Yes to validate Ampro DSQD ; Else sort out 3.5/5.25" High-Density Formats LD HL,SKEWH3 LD A,(RR) CP 64+1 ; Valid B/P 3.5" HD Format (Sector offset=64)? LD A,64 ; (preset Yes) JR NC,RdIDQ ; ..jump if YES to Set LD HL,SKEWH5 LD A,(RR) ; Fetch Sector # Again CP 48+1 ; Valid B/P 5.25" HD (Sector offset=48)? LD A,48 ; (preset Yes) JR C,RdIDX ; ..Error if Not RdIDQ: LD (nSides),A ; Indicate Non-0 for 2-sided LD (secTbl),HL LD (secOff),A POP HL ; Restore Regs POP BC XOR A ; Set Ok Flag RET ; Monitor Status of Read ID Progress, Abort if Over one second elapses RdIDSt: EI ; Interrupts must be active for Timer LD HL,ST0 ; Read Status to buffer LD A,10 LD (count),A ; Timeout in 1 Sec if Not Successful RdIDS0: LD A,(count) OR A ; Timed Out? JR Z,RdIDEr ; ..jump if So setting Error IN A,(MSR) BIT 7,A ; Interrupt? JR Z,RdIDS0 ; ..loop if Not BIT 5,A ; In Execution Phase? JR NZ,RdIDS0 ; ..jump if So BIT 4,A ; End of Status/Rslt? JR Z,RdIDSX ; ..Exit if So BIT 6,A ; Another Byte Ready? JR Z,RdIDSX ; ..Exit if Not INI ; Else Read a Byte from (C) to (HL) JR RdIDS0 ; and check for next RdIDEr: CALL FPurg ; Purge any Status Bytes LD A,0B7H LD (ST1),A ; Set Error Status RdIDSX: LD A,(ST1) ; Get Status AND 35H ; Set Zero if Ok, Non-0 if Error RET ; and return ;..... ; Read a Sector from the Floppy ; Enter: HL -> Buffer ; Exit : HL -> Byte after last one read ReadF: PUSH BC LD BC,9*256+46H ; MFM Read Command LD A,(SECT) LD (EOT),A ; read just 1 Sector CALL FDCmd ; Send Command (disabling Ints) ReadF0: CALL WRdy BIT 5,A ; Done? JR Z,ReadF1 ; ..jump to Result if So INI ; Else Read a Byte from (C) to (HL) JR ReadF0 ; and check for next ReadF1: PUSH HL ; Save next address CALL FDCDn ; fetch Results (reenabling Ints) LD A,(ST1) POP HL ; restore next address AND 34H ; Set Error bits POP BC RET ;..... ; Execute Command in C, Length of Command in B ;; Enter: HL -> Data Buffer (if any) FDCmd: PUSH HL LD HL,Comnd LD (HL),C ; Save Command LD C,DR ; address Data Register DI ; (no Ints here) FDCm0: CALL WRdy OUTI JR NZ,FDCm0 ; Send all command string POP HL ; Restore Entry Ptr RET ; and back to Caller ;..... ; Check for Results of Command. FDCDn: EI ; Allow Ints Now LD HL,ST0 ; Read Results here FDRe0: CALL WRdy BIT 4,A ; End of Status/Result? RET Z ; ..quit if So BIT 6,A ; Another byte ready? RET Z ; ..quit if Not INI ; Read Byte of Status JR FDRe0 ; ..back for More ;..... ; Check for Seek/Home Complete status by Executing Sense Interrupt Comnd ; Return Carry Set, Non-0 if Timeout FSnsI: PUSH HL ; Save Regs FSnsI0: CALL WRdy ; Wait til Ready LD A,08H OUT (DR),A ; Issue Sense Interrupt CALL WRdy IN A,(DR) ; Get Status0 LD L,A ; (cache) CP 80H ; Invalid Comnd? JR Z,FSnsI0 ; ..try again if So CALL WRdy IN A,(DR) ; Else get Track LD A,L BIT 5,A ; ST0 Seek Complete? JR Z,FSnsI0 ; ..loop if Not POP HL ; restore Regs EI RET ; back to Caller ;..... ; Purge any waiting status bytes until Controller Ready for Command FPurg: LD B,10 ; Set Clear Retry Count FPurg0: IN A,(MSR) ; Fetch FDC Status AND 0F0H ; (strip any Drive bits) CP 80H ; Ready? RET Z ; ..return if So CP 0D0H ; Read Data Present? JR NZ,FPurg1 ; ..jump if Not IN A,(DR) ; Else Clear Status by Reading Data Reg EX (SP),IX EX (SP),IX ; delay DJNZ FPurg0 ; .loop for More RET ; ..Quit in disgust if we get here FPurg1: LD A,08H OUT (DR),A ; Force Interrupt to break chain LD A,20 CALL DLYmS ; let it work JR FPurg0 ; ..and Check again ;..... ; Wait for IO Ready status WRdy: EX (SP),IX ; (little delay) EX (SP),IX WRdy0: IN A,(MSR) ; Read Main Status Reg BIT 7,A ; Interrupt Present? RET NZ ; return if So JR WRdy0 ; ..Else try again ;..... ; Set Flags for High-Density Floppys HDens: XOR A ; Set B5/B1/B0 for High-Dens 3.5" StDens: HDens0: LD (HdFlg),A ; Save Flag OUT (DRR),A ; Activate B1/0 in Data Rate Reg AND 20H ; OUT (FDCTRL),A ; and B5 in Control Reg RET ; ;..... ; Table of Diskette Sector Numbers SKEW40: DB 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0FFH SKEW80: DB 1, 2, 3, 4, 5, 0FFH SKEWH3: DB 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0FFH ; 3.5" HD (1.76 MB) SKEWH5: DB 1, 2, 3, 4, 5, 6, 7, 8, 9, 0FFH ; 5.25" HD (1.44 MB) ;..... ;<<---- Entry Point from Boot Sector Loader ---->> ; Step to Hext Floppy Track or Switch to Head 1 for Double-Sided Disks NXTTRK: LD A,(nSides) OR A ; Double-Sided? JR NZ,NxtTr0 ; ..jump if So ; -- Add Step for SS Disks here -- RET NxtTr0: LD A,(HDR) ; Get Head/Drive Byte XOR 00000100B ; reverse Head Bit LD (HDR),A ; save LD A,(HD) ; Get Head Byte XOR 00000001B ; reverse LD (HD),A ; save RET ;..... ;<<---- Entry Point from Boot Sector Loader ---->> ; Read a Complete Track from the Selected Floppy Disk RdTrkF: LD HL,(secTbl) RdTrk0: LD A,3 LD (reTrys),A ; Set Retry Count LD A,(secOff) ADD A,(HL) ; Add Sctr Offset to Next Sctr Num RET C ; ..exit if Track Done INC HL ; Else Pt to Next Sctr LD (SECT),A ; store Sctr # in Comnd Blk PUSH HL RdTrk1: LD HL,(dmaAd0) ; Get Addr to Load to CALL ReadF ; Attempt Sector Read LD (dmaAd0),HL ; save Returned Addr JR Z,RdTrk2 ; ..jump if Good Read LD HL,reTrys DEC (HL) ; Else More Tries remaining? LD HL,(dmaAd1) ; (repair Xfer addr) LD (dmaAd0),HL JR NZ,RdTrk1 ; ..jump if So LD SP,9000H ; Else reset Stack ; JP BOOTH ; ..else try to Boot SCSI RdTrk2: LD HL,(dmaAd0) LD (dmaAd1),HL ; Else Set Next Trk Addr POP HL JR RdTrk0 ; ..and continue til done ;..... ; Other routines needed to support this code: DLYmS: RET ; Delay the number of milliSeconds in A DLY10M: RET ; Delay One Second CkKey: RET ; Check for Key Press, Go to Monitor if Press