title djdma/format.mac (rev 3.3 - 30_Mar_83) .z80 channl equ 50h ;Start channel address index equ 10h ;Delta index status bit wproct equ 40h ;Write protected status bit dready equ 80h ;Drive ready status bit home equ 0a0h ;Internal Table home-disk routine address seek equ 0a3h ; seek-track sdrive equ 0a6h ; set-drive hsync equ 0a9h ; header-sync diskd equ 4001h ;Disk data port status equ 4003h ;Status port contrl equ 4007h ;Control port crlfs equ 0d0ah ;Carraige return / line feed sequence acr equ 0dh ;A carraige return character alf equ 0ah ;A line feed character aesc equ 1bh ;An escape character adel equ 7fh ;A delete character retries equ 3 ;Disk retries before giving up on verify bdos equ 5 ;Bdos entry address wcon equ 2 ;Write console function direct equ 6 ;Direct console I/O page 63 start: ld sp,ecode+30h ;Initialize the stack pointer ld hl,"0 " ;Initialize track number to 0 ld (ftrack+1),hl ld hl,qfmess ;Ask about type of format call getc jp z,ibmst ;Formatting IBM cp 1 jp z,nstart ;Formatting North Star jp 0 ;Return to CP/M ibmst: ld hl,1030h ;Initalize command addresss ld (dotcmd+1),hl ld hl,sdadvt ld (atcmd+1),hl ld hl,slcmd+1 ;Set 8 inch drive as 0-3 ld (hl),0 dec hl ld c,4 call lcmd ld hl,drmess ;Get drive number call getcc ld (single+1),a ;Store the drive number in code ld (drive),a ; and save in a safe place ld a,26 ;26 Sectors per track for single ld (nspt),a ld hl,26*128 ;Load number of bytes per track ld (trksiz),hl ld a,0e5h ;We format with e5's ld (verval),a ld hl,dnmess ;Get density call getcc ld (densty),a ;Save for later use jp z,side ;Skip sector size if single density ld hl,slmess ;Select sector length message call getcc ld d,0 ;Form offset into sector table ld e,a ld hl,tsize ;Get track size add hl,de ld h,(hl) ;Get high byte of size ld l,0 ld (trksiz),hl ;Save track size inc a ;Adjust for sector length code ld (dlcode-ddfmt+double),a ;Store in format code ld hl,sptabl add hl,de ld a,(hl) ;Fetch number of sectors ld (dlast-ddfmt+double),a ;Store in format code dec a ld (nspt),a ; and in the verify section ld a,20h ;Sector length code is 80,100, or 0 dcnst: add a,a dec e ;Decrement the sector type jp p,dcnst ;Test for cycle done ld (dsize-ddfmt+double),a ;Store 1/4 length in format code side: ld a,(drive) ;Get drive # add a,"0" ;Make ASCII decimal ld (wdriv8),a ;Save in wait message ld hl,wdmes8 ;Wait for a disk call putm ld hl,wdmess call getcc retryf: ld hl,sscmd+1 ;Test various drive parameters ld a,(drive) ;Load drive # to sense ld (hl),a dec hl ld c,7 ;Offset to status call lcmd ld hl,nrmess ;Not ready message cp 82h ;Test for not ready jp z,nready ;Skip if not ready ld a,(sscmd+4) ;fetch status port value ld b,a ;Save for a while ld hl,wpmess ;Write protected message and 40h ;Mask in write protected bit jp nz,nready ;Skip if write protected ld a,b ;Restore full status port value and 4 ;Mask in 'sides' bit rrca ;Shift to bit 0 rrca ld (ddsbit-ddfmt+double),a ;Store in format code double density ld (sdsbit-sdfmt+single),a ;Store in format code single density rrca ;Zap around to bit 7 ld (nside),a ;And save side flag ld hl,ftmess ;Formatting ... message call putm ld a,1 ;Load track counter ld (ctrack),a ld hl,lsdcmd ;Load single density code command ld c,9 ;Offset to halt status call lcmd ;Load the code ld hl,dotcmd ;Format track 0 command ld c,5 ;Offset to status call lcmd ;Execute the command jp z,proced ;Zero => no error ld hl,nrmess ;Drive not ready message cp 82h ;Drive not ready error code jp z,nready ;Test for drive not ready ld hl,wpmess ;Well... the write tab fell off... nready: call getcc ;Send the message jp z,start ;Zero => start the program over jp retryf ;Go back and do the command over proced: ld hl,sdrdy ;Adjusted execution address of format ld a,(densty) or a ;Test for double density jp z,contue ;Make no adjustments for single density ld hl,lddcmd ;Load double density format command ld c,9 ;Offset to halt status call lcmd ;Load the code into controller ld hl,ddadvt ;Advance track execute address ld (atcmd+1),hl ;Update the command execute address ld hl,1030h ;Format execute address contue: ld (dotcmd+1),hl ;Update track format execute address ld hl,atcmd ;Advance track command ld c,5 ;Offset to status call lcmd ;Load the command and execute cp 77 ;Last track value (77 decimal) jp nz,fmtrck ;Zero => formatting done ld a,77 ;77 tracks on an 8 inch drive ld (ntrack),a jp verify ;Verify disk fmtrck: ld hl,ftrack ;Pointer to track # call ptrack ;Print and update track number ld hl,dotcmd ;Format a track command ld c,5 ;Offset to status call lcmd ;Load and execute the command jp z,contue+3 ;Loop back for more tracks ld hl,femess ;Drive has become not ready call putm jp start ;Stop the formatting page ; ; The following routine set up and execute the North Star formatter ; nstart: ld hl,1030h ld (nscmex+1),hl ld a,20h ld (data-nsfmt+nsform),a ld (cpdata-nsfmt+nsform),a ld (verval),a xor a ld (track-nsfmt+nsform),a ld a,10 ;Load number of sectors per track ld (nspt),a ld hl,10*512 ;Load number of bytes per track ld (trksiz),hl ld hl,slcmd+1 ;Set 5 1/4 inch drive as 0-3 ld (hl),4 dec hl ld c,4 call lcmd ld hl,drmess ;Get drive number call getcc ld (nsform+1),a ld (drive),a ld hl,ntmess ;Get number of tracks call getcc ld d,0 ld e,a ld hl,nstrak add hl,de ld a,(hl) ld (strack-nsfmt+nsform),a ld (ntrack),a push de ld hl,dnmess ;Get density call getcc pop de ld b,051h jp z,nstore push af rrca add a,e ld e,a pop af ld b,0d1h nstore: ld (den1-nsfmt+nsform),a ld a,b ld (den2-nsfmt+nsform),a push de ld hl,simess ;Get number of sides call getcc pop de ld (dflag-nsfmt+nsform),a rrca ld (nside),a ;Set up side flag rlca jp z,nsdatc rlca rlca add a,e ld e,a nsdatc: push de ld hl,nsmess ;Ask about North Star vs CP/M format call getcc pop de jp z,nsload ld a,e and 80h ld a,10h jp z,nstord ld hl,nstype-80h add hl,de ld a,(hl) nstord: ld (cpdata-nsfmt+nsform),a ld a,0e5h ld (data-nsfmt+nsform),a ld (verval),a nsload: ld a,(drive) ;Get drive # add a,"0" ;Make ASCII decimal ld (wdriv5),a ;Save in wait message ld hl,wdmes5 ;Wait for a disk call putm ld hl,wdmess call getcc nsrtry: ld hl,nscmlm ld c,9 call lcmd ld hl,nscmex ld c,5 call lcmd jp z,nsproc ld hl,nrmess cp 82h jp z,$+6 ld hl,wpmess ;Tell about fault call getcc jp z,start jp nsrtry nsproc: ld hl,ftmess ;Formatting ... message call putm xor a ;Initialize track counter ld (ctrack),a ld hl,entry ld (nscmex+1),hl nscont: ld hl,ftrack ;Print track # call ptrack ld hl,nscmat ld c,5 call lcmd ld b,a ld a,(strack-nsfmt+nsform) cp b jp z,verify ;Go verify disk ld hl,nscmex ld c,5 call lcmd jp z,nscont ld hl,femess ;Drive not ready call putm jp start page ; ; Verify the disk ; verify: ld hl,vtmess ;Send verifying ... message call putm ld hl,sacmd ;Set the DMA address ld c,5 ;Halt status offset call lcmd xor a ;Initialize track counters ld (ctrack),a ld (rtcmd+1),a ld a,(drive) ;Initialize the drive number ld (rtcmd+3),a vertrk: ld hl,vtrack ;Print track # call ptrack ld a,(nside) ld (rtcmd+2),a ;Load sides flag ld a,retries ;Initialize retry counters ld (retrys),a ;Soft error counter ld (retryh),a ;Hard error counter versid: ld hl,rtcmd ;Verify a side ld c,9 ;Status offset call lcmd ;Read a track jp nz,verfat ;Fatal drive error ld hl,sectab ;Lets check out sectors ld a,(nspt) ;Load number of sectors to check ld c,a ld a,40h ;'Ok' code verspt: cp (hl) jp nz,vererr ;Sector does not verify inc hl dec c jp nz,verspt ld hl,rtcmd+2 ;Side ok, check for other side ld a,(hl) ;Get side flag ld (hl),0 ;Clear flag just in case ... or a ;Test flag jp nz,versid ;Verify other side dec hl ;Bump to track count inc (hl) ;Bump track number ld a,(ntrack) ;Test for end of disk cp (hl) jp nz,vertrk ;Verify next track ld hl,vdmess ;Verify done call putm jp start ;Restart verfat: ld hl,retryh ;Bump hard retry count dec (hl) jp nz,versid ld hl,vemess ;Verify error jp errpr vererr: ld hl,retrys ;Bump hard retry count dec (hl) jp nz,versid ld hl,vsmess ;Verify error errpr: call putm ;Tell user about it jp start ; and quit ; ; Execute controller command. ; hl -> Start of command sequence ; c -> Offset pointer to status byte of sequence ; a <- Status return (z flag set if = 40h) ; ; The command sequence must end with a halt. If any status ; is returned from the regular part of the command then this ; status must immediatly precede the halt. The value in the ; c register added to hl should produce a pointer to the ; halt status. ; lcmd: ld a,26h ;Branch channel command ld (channl),a ld (channl+1),hl ;Channel address xor a ld (channl+3),a ;Extended address ld b,0 add hl,bc ;Offset to status byte ld (hl),a ;Clear halt status out (0efh),a ;Start controller waitc: or (hl) ;Wait for halt complete jp z,waitc dec hl ;Back up to command status dec hl ld a,(hl) ;Load status cp 40h ;Comper to Ok status ret ; ; Print a track #, do fancy backspacing, ect. ; ptrack: ld (ptrk),hl ;Save ASCII pointer ld a,(ctrack) ;Load current track push af ld hl,(ptrk) ;Place to deposite track # call decim3 ;Figure track # pop af inc a ;Bump to next track ld (ctrack),a ld bc,300h ;b = fore count, b = back count ld hl,(ptrk) ;Pointer to current track # ld de,otrack ;Pointer to old track # ex de,hl ;Set pointers the way we want them ptrkcp: ld a,(de) ;Get a digit cp (hl) ;Compare against old number jp nz,ptrkdn ;Skip if done inc c ;Bump offset inc de ; current pointer inc hl ; old pointer dec b ; counter jp nz,ptrkcp ;Compare next digit ret ;Numbers were the same ptrkdn: push hl ;Save pointer to first dirty digit ptrklp: ld (hl),a ;Copy dirty string over inc de ld a,(de) inc hl dec b jp nz,ptrklp ld hl,bsmess ;Back space add hl,bc ;Offset neccesary amount call putm pop hl ;Retreive string pointer call putm ;And print ld c,6 ld e,0ffh call 5 ret ; ; Put 'a' in (hl) in ASCII decimal form with leading spaces ; decim3: ld c,"0" ;Initialize 'leader' flag ld d,100 ;Hundreds call decfig ld d,10 ;Tens call decfig decim1: ld c,0 ;Force leading 0 ld d,1 ;Ones jp decfig decfig: ld e,"0"-1 declop: inc e sub d jp nc,declop add a,d push af ld a,e cp c ;Handle leading space (sometimes) jp nz,decok ld e," " ;Load space jp decokk decok: ld c," " decokk: ld (hl),e ;Save digit inc hl ;Bump to next position pop af ret ; ; Print a null terminated text to the terminal ; putm: ld a,(hl) ;Get current byte of message or a ;Test for end of message ret z ;Return at end of message push hl ;Save the character pointer call putc ;Output the character pop hl ;Recover the character pointer inc hl ;Advance the character pointer jp putm ;Go get the next character ; ; Print a character to the terminal ; putc: push af push bc push de push hl ld e,a ld c,wcon call bdos pop hl pop de pop bc pop af ret ; ; Call getc. Parse ESC and DEL codes. If these codes ; were typed then return to start. ; getcc: call getc ;Get code jp m,start ;Restart if ESC or DEL ret ;Return regular status ; ; This routine prints a prompt and then accepts an input character. ; This input character is compared to a 'reply list'. If the ; character is found then an associated 'reply string' is echoed ; and a value associated with that character is returned. ; ; The routine is called with a pointer to a string in hl and ; returns a value in (a) and (zero). The format for the string ; follows: ; ; db "initial prompt string" ; db 0 ;Null terminator ; db 2 ;Number of 'reply values' ; db "a", "A", acr ;A list of characters to be ; ; with the coresponding reply ; ; 'value.' ; db 83h ;The reply value. Parity must ; ; be set. ; db "Reply echo string for a, A, or acr." ; db 0 ;Null terminator ; db "d", "D" ;A list of characters to be ; ; with the coresponding reply ; ; 'value.' ; db 85h ;The reply value. Parity must ; ; be set. ; db "Reply echo string for d or D." ; db 0 ;Null terminator ; ; This structure will return a 3 if an 'a', 'A', or acr is typed ; and a 5 if a 'd' or 'D' is typed. The routine prints a CRLF ; before the initial prompt string and a CRLF after the reply ; string. If an ESC or DEL is typed then a code of 80h will be ; returned and the minus flag will be set. ; getc: push hl ld hl,crlf ;Print an initial CRLF call putm pop hl call putm ;Print prompt inc hl ;Bump to number of valid replies ld c,(hl) ld a,c ld (valid),a ;Save reply count ld (string),hl ;Save string pointer gtchk: push bc ;Save reply count push hl ;Save string pointer gtwait: ld c,direct ;Direct console I/O ld e,255 ;We want input! call bdos or a ;Test for no character typed jp z,gtwait ;Wait for a character pop hl pop bc cp 3 ;Check for control C jp z,0 ; exit to CP/M cp aesc ;Escape and delete get special coverage jp z,gtspec cp adel jp z,gtspec ld b,a ;Save user reply gtscan: inc hl ;Bump to reply string ld a,(hl) ;Load reply character or a ;Test for end of reply string jp m,gtflsh ;Not in this reply list, flush string cp b ;Compare to user reply jp nz,gtscan ;No match, continue scan gtdone: inc hl ;Look for reply value ld a,(hl) or a jp p,gtdone push af ;Save value inc hl ;Bump to response message call putm ld hl,crlf ;Print a trailing CRLF call putm pop af ;Restore reply value and 7fh ;Clear parity bit ret gtflsh: inc hl ;Look for and of message (null) ld a,(hl) or a jp nz,gtflsh dec c ;Bump reply count jp nz,gtscan ;Continue scan ld a,(valid) ;Reinitialize reply count ld c,a ld hl,(string) ;Reinitialize string pointer jp gtchk ;User guessed wrong, let us try again gtspec: ld a,80h ;Special flag or a ;Zap flags ret page slcmd: db 02eh ;Set/get logical drive settings db 0 ;Logical to set db 0 ;Logical drives returned db 25h db 0 lddcmd: db 0a1h ;Write controller memory command dw double ;Main memory address pointer db 0 dw single-double ;Byte count dw 1030h ;Controller memory address pointer db 25h ;Controller halt command db 0 ;Halt command status byte lsdcmd: db 0a1h ;Write controller memory for single dw single db 0 dw nsform-single dw 1030h db 25h db 0 dotcmd: db 0a2h ;Execute controller routine command dw 1030h ;Format a track address db 0 ;Execute command status db 25h ;Halt command db 0 ;Status byte atcmd: db 0a2h dw sdadvt ;Advance the track value address db 0 db 25h db 0 sscmd: db 022h ;Sense drive status db 0 ;Drive # db 0 ;Drive characteristic byte db 0 ;Sector size byte db 0 ;Status port byte db 0 ;Completion status db 25h db 0 sacmd: db 023h ;Set DMA address dw buffer db 0 db 25h db 0 rtcmd: db 029h ;Read track command db 0 ;Track # db 0 ;Side # db 0 ;Drive # dw sectab ;Sactor table db 0 db 0 ;Status db 25h db 0 nscmlm: db 0a1h ;Load controller memory dw nsform db 0 dw ecode-nsform dw 1030h db 25h db 0 nscmex: db 0a2h ;Execute controller memory dw 1030h db 0 db 25h db 0 nscmat: db 0a2h ;Advance track command (internal) dw advtrk db 0 db 25h db 0 nstrak: db 35 ;Track count table db 40 db 80 nstype: db 90h db 0a0h db 0c0h db 0 db 0f0h db 0d0h db 0e0h tsize: db 26*256/100h ;Number of pages per track db 15*512/100h db 8*1024/100h sptabl: db 27 ;26 sectors per track (256 bytes) db 16 ;15 sectors per track (512 bytes) db 9 ;8 sectors per track (1024 bytes) page qfmess: dw crlfs db "DJDMA Format Program (Rev 3.3 - 30_Mar_83)", acr, alf db " Type ESC or DEL to restart selections", acr, alf db " The option listed first is the default", acr, alf dw crlfs db "Select: Carriage_Return - Exit to CP/M",acr,alf db " I - 8"" disk (IBM 3740 compatable)",acr,alf db " N - 5.25"" disk (CP/M-North_Star compatable)",acr,alf dw crlfs db "Select size of media (Carriage_Return, I, or N): " db 0 db 3 db "i", "I", 80h db "IBM 3740 format" db 0 db "n", "N", 81h db "CP/M - North_Star format" db 0 db alf, acr, 82h db "Returning to CP/M" db 0 drmess: db "Select a drive ( 0, 1, 2, or 3 ): " db 0 db 4 db "0", acr, 80h db "Preparing to format drive 0" db 0 db "1", 81h db "Preparing to format drive 1" db 0 db "2", 82h db "Preparing to format drive 2" db 0 db "3", 83h db "Preparing to format drive 3" db 0 dnmess: db "Select: D - double density", acr, alf db " S - single density", acr, alf db " " db 0 db 2 db "d", "D", acr, 81h db " Double density selected." db 0 db "s", "S", 80h db " Single density selected." db 0 ntmess: db "Select the number of tracks ( 0=35, 1=40, 2=80 ): " db 0 db 3 db "0", acr, 80h db "35 track drive" db 0 db "1", 81h db "40 track drive" db 0 db "2", 82h db "80 track drive" db 0 slmess: db "Select the sector length ( 2=1024, 1=512, 0=256 ): " db 0 db 3 db "0", 80h db "256 byte sectors" db 0 db "1", 81h db "512 byte sectors" db 0 db "2", acr, 82h db "1024 byte sectors" db 0 nsmess: db "Select: C - CP/M compatibility or",acr, alf db " N - North star compatibility", acr, alf db " " db 0 db 2 db "n", "N", 80h db " North Star format." db 0 db "c", "C", acr, 81h db " CP/M format." db 0 simess: db "Select: S - single sided or", acr, alf db " D - double sided media.", acr, alf db " " db 0 db 2 db "s", "S", acr, 80h db " Single sided media selected." db 0 db "d", "D", 81h db " Double sided media selected." db 0 nrmess: db "Drive not ready - (R)estart program, or (C)ycle: " db 0 db 2 db "r", "R", 80h db "Restarting program" db 0 db "c", "C", acr, 81h db "Cycling" db 0 femess: dw crlfs db "Drive has become 'not ready' during formatting" db 0 wpmess: db "Write protected - (R)estart program, or (C)ycle: " db 0 db 2 db "r", "R", 80h db "Restarting program" db 0 db "c", "C", acr, 81h db "Cycling" db 0 wdmes5: dw crlfs, crlfs db "Insert a write enabled diskette in 5 1/4 inch drive " wdriv5: db "0." db 0 wdmes8: dw crlfs, crlfs db "Insert a write enabled diskette in 8 inch drive " wdriv8: db "0." db 0 wdmess: db "Close the drive door and then press " db 0 db 1 db alf, acr, 80h db 0 ftmess: dw crlfs db "Formatting track:" ftrack: db " 0" ;ASCII track number db 0 vtmess: dw crlfs db "Verifying track: " vtrack: db " 0" db 0 bsmess: db 8, 8, 8 ;Back terminal 3 spaces db 0 otrack: db " 0" ;Old ASCII track number db 0 vdmess: dw crlfs, crlfs db "Verify done." dw crlfs db 0 vemess: dw crlfs, crlfs db "Fatal verify error, probable bad diskette." dw crlfs db 0 vsmess: dw crlfs, crlfs db "Sector verify error" dw crlfs db 0 crlf: dw crlfs db 0 page drive: db 0 ;# of drive being formatted densty: db 0 ;Density flag for current drive nspt: db 0 ;Number of sectors per track trksiz: dw 0 ;Size of a track (bytes) verval: db 0 ;Byte to verify with nside: db 0 ;Number of sides flag ntrack: db 0 ;Number of tracks on current drive ctrack: db 0 ;Current track number ptrk: dw 0 ;Pointer to ASCII track # retryh: db 0 ;Retry counter, hard retrys: db 0 ;Retry counter, soft valid: db 0 ;Temp save for number of valid replies string: dw 0 ;Temp pointer to parse trees sectab: db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ;Sector status table db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 page ; ; The following routines are the actual formatting routines. ; These routines are loaded into controller RAM at 1030h ; and executed as needed. Currently there are 3 routines: ; ; IBM 8 inch single density. ; IBM 8 inch double density. ; North Star 5 1/4 inch multi desity. ; ; ; IBM 8 inch single density formatter routine ; double equ $ .phase 1030h ddfmt: ld hl,status bit 7,(hl) ;Check that the drive is ready nrexit: ld a,82h ;Drive not ready error code ret z ;Error exit bit 6,(hl) ;Test for write protected ld a,90h ;Write protected error code ret nz ;Error exit ld (ix+0bh),0 ;Reset index counter ld a,(dtrck) ;Get the new track value cp (iy+1) ;Compare with current track push af ;Save the track call nz,seek ;Move the head(s) if needed ld hl,diskd ;Pointer to disk shift register ld de,contrl ;Pointer to control port pop af ;Recover the tack cp 2bh ;Compare with track 43 ld a,4 ;No write precompensation jr c,loadpc ;Carry => track is less than 43 ld a,14h ;Write precompensation bit set loadpc: ld (precmp),a ;Setup the write precompensation byte sbc a,a ;Push carry bit throughout accumulator or 0feh ;Low current bit now set and (iy+2) ;Merge with drive pattern or 2 ;Select side 0 ld (iy+2),a ;Restore drive pattern or 0ch ;Turn off step command ld (4005h),a ;Update the drive register ld b,50h ;Preamble length ddlbl1: ld a,(status) and index ;Look for index pulse jr nz,ddlbl1 ;Wait for no index pulse present ddlbl2: ld a,(status) and index jr z,ddlbl2 ;Wait for leading edge of new indes pulse ld a,90h ;Control byte - normal write/no crc ld (de),a ;Initialize control port ld a,0 precmp equ $-1 ;Write precompensation & controller start ld (4006h),a ;Start the controller ddlbl3: ld (hl),4eh djnz ddlbl3 ;Write the preamble ld b,0ch ;Zero preamble length ddlbl4: ld (hl),0 djnz ddlbl4 ;Write the zero preamble ld a,80h ;Control byte for 16 bit write ld (de),a ;Change mode ld (hl),52h ;First half of c2 ld (hl),24h ;Second half of c2 ld (hl),52h ;Another c2 ld (hl),24h ld (hl),52h ;The third c2 ld a,90h ;Control byte 8 bit write ld (de),a ;Change mode ld (hl),24h ;Finish the sync bytes ld (hl),0fch ;Index mark ld b,32h ;Postamble length ddlbl5: ld (hl),4eh djnz ddlbl5 ;Write the postamble dmloop: ld b,0ch ;Zero preamble length ddlbl6: ld (hl),0 djnz ddlbl6 ;Write the preamble ld a,81h ;16 bit write mode w/crc ld (de),a ;Change mode ld (hl),44h ;First half of a1 ld (hl),89h ;Second half of a1 ld (hl),44h ;Second a1 ld (hl),89h ld (hl),44h ;Third a1 ld a,91h ;8 bit write mode w/crc ld (de),a ;Change mode ld (hl),89h ;Finish sync bytes ld (hl),0feh ;Sector header id byte ld (hl),0 ;Write the track number dtrck equ $-1 ld (hl),0 ;Write the side dside equ $-1 ld (hl),1 ;Write the sector number dsect equ $-1 ld (hl),1 ;Sector length code dlcode equ $-1 ld a,0a1h ;Mode to write crc bytes ld (de),a ;Change mode ld (hl),a ld (hl),a ;Write the crc bytes ld a,90h ;Reset crc generator ld (de),a ;Change mode ld b,16h ;4e postamble length ddlbl7: ld (hl),4eh djnz ddlbl7 ;Write the postamble ld b,0ch ;Data field preamble ddlbl8: ld (hl),0 djnz ddlbl8 ;Write the preamble ld a,81h ;16 bit write w/crc ld (de),a ;Change mode ld (hl),44h ;First half of a1 ld (hl),89h ;Second half of a1 ld (hl),44h ;Second a1 ld (hl),89h ld (hl),44h ;Third a1 ld a,91h ;8 bit write w/crc ld (de),a ;Change mode ld (hl),89h ;Finish the 3 sync bytes ld (hl),0fbh ;Data header id byte ld b,40h ;Sector length divided by four dsize equ $-1 ddlbl9: ld (hl),0e5h ;Empty sector data byte ld (hl),0e5h ld (hl),0e5h ld (hl),0e5h ;Write four fill bytes djnz ddlbl9 ;Test for data field write done ld a,0a1h ;Crc control byte ld (de),a ;Change mode ld (hl),a ;Write the crc bytes ld (hl),a ld a,90h ;Turn off the crc generator ld (de),a ;Change mode ld a,(dsect) ;Get the sector number inc a cp 1bh ;Test for last sector +1 dlast equ $-1 ld (hl),4eh ;First byte of postamble jr nz,$+4 ;Zero => all sectors written ld a,1 ld (dsect),a ;Update the sector number ld b,35h ;Postamble length less one ddlbla: ld (hl),4eh djnz ddlbla ;Write the postamble jr nz,dmloop ld (hl),4eh ;First fill byte ld b,0 ;Double sided bit test ddsbit equ $-1 ld a,(dside) xor b ;Conditionally switch the side byte ld (dside),a ;Update the side byte ld (hl),4eh ;Second fill byte ld b,4fh ;Preamble length less one ex Af,Af' ;Save the double sided status dlblb: ld (hl),4eh ;Write a fill byte ld a,(status) and index ;Wait for the index pulse jr z,dlblb ex Af,Af' ;Recover the double sided status jr z,ddlblc ;Zero => track write is done ld a,(iy+2) ;Drive pattern or 0ch ;Turn off the step command and 0fdh ;Change read/write heads ld (4005h),a ;Update the command register ld (hl),4eh ;First preamble byte jp ddlbl3 ;Format the other side ddlblc: ld (hl),4eh ;Trailing fill byte ld (hl),4eh ;Trailing fill byte ld (hl),4eh ;Trailing fill byte xor a ld (de),a ;Turn off the write gate ld a,6 ld (4006h),a ;Turn off the controller ld a,40h ;Status code ret ddadvt: ld a,(dtrck) ;Get the current track value inc a ;Increment ld (dtrck),a ;Restore the new value ret ;Return with current track value .dephase page ; ; IBM 8 inch double density formatter routine ; single equ $ .phase 1030h sdfmt: ld a,0 ;Second byte filled with proper drive number call sdrive ;Select the new drive ret nz ;Return if wrong value ld a,(iy+2) ;Get the drive pattern or 0fh ;Side 0 and no step command ld (4005h),a ;Update drive control register ld hl,0 ;Delay for the head load sdwait: dec hl ld a,h or l jr nz,sdwait ld (ix+0bh),a ;Reset the index counter sdtrk0: call home ;Calibrate the head(s) bit 5,(hl) ;Test for track zero jr z,snrext sdrdy: ld hl,status bit 7,(hl) ;Test for the drive ready snrext: ld a,82h ;Drive not ready code ret z ;Error exit bit 6,(hl) ;Write protect bit ld a,90h ;Write protect error code ret nz ld (ix+0bh),0 ;Reset the index counter ld a,(strck) ;Get the new track cp (iy+1) ;Compare with current track call nz,seek ;Do track seek if necessary ld hl,diskd ;Controller data register ld de,contrl ;Control register ld b,28h ;Preamble length sdlbl1: ld a,(status) and index jr nz,sdlbl1 ;Wait for no index pulse sdlbl2: ld a,(status) and index jr z,sdlbl2 ;Wait for leading edge of new index pulse ld a,90h ;Clear the crc register & turn on write gate ld (de),a ;Change modes ld a,44h ;Single density & start bit ld (4006h),a ;Start the controller sdlbl3: ld (hl),0ffh djnz sdlbl3 ;Write the preamble ld a,80h ;16 bit write mode ld (de),a ;Change modes ld b,0ch ;Zero preamble length sdlbl4: ld (hl),0aah ;Half a zero cell djnz sdlbl4 ;Write the zero preamble ld (hl),0f7h ;First half of fc ld a,90h ;8 bit write mode ld (de),a ;Change modes ld (hl),7ah ;Second half of fc ld b,1ah ;Postamble length sdlbl5: ld (hl),0ffh djnz sdlbl5 ;Write the postamble smloop: ld a,80h ;16 bit write mode ld (de),a ;Change modes ld b,0ch ;Sector header preamble length sdlbl6: ld (hl),0aah ;Half a zero cell djnz sdlbl6 ;Write the preamble ld a,81h ;Enable crc & 16 bit write ld (de),a ;Change modes ld (hl),0f5h ;First half of fe ld a,91h ;Enable crc & 8 bit write ld (de),a ;Change modes ld (hl),7eh ;Second half of fe ld (hl),0 ;Write the track strck equ $-1 lD (hl),0 ;Write the side byte sside equ $-1 ld (hl),1 ;Write the sector number ssect equ $-1 ld (hl),0 ;Write the sector length code ld a,0a1h ld (de),a ;Change modes ld (hl),a ld (hl),a ;Write the crc bytes ld a,90h ;Reset the crc ld (de),a ;Change modes ld b,0bh ;Sector header postamble length sdlbl7: ld (hl),0ffh djnz sdlbl7 ;Write the postamble ld a,80h ;16 bit write mode ld (de),a ;Change modes ld b,0ch ;Data field preamble length sdlbl8: ld (hl),0aah ;Half a zero cell djnz sdlbl8 ;Write the preamble ld a,81h ;Enable crc & 16 bit write ld (de),a ;Change modes ld (hl),0f5h ;First half of fb ld a,91h ;8 bit write ld (de),a ;Change modes ld (hl),6fh ;Second half of fb ld b,80h ;Sector data field length sdlbl9: ld (hl),0e5h djnz sdlbl9 ;Write the data field ld a,0a1h ld (de),a ;Change modes ld (hl),a ld (hl),a ;Write the crc bytes ld a,90h ;Reset the crc ld (de),a ;Change modes ld a,(ssect) ;Get the current sector inc a ;Advance cp 1bh ;Compare with 27 ld (hl),0ffh ;First postamble byte jr nz,$+4 ;Zero => all sectors written ld a,1 ld (ssect),a ;Update the sector ld b,1ah ;Postamble length less one sdlbla: ld (hl),0ffh djnz sdlbla ;Write the postamble jr nz,smloop ;Test for more sectors to format ld (hl),0ffh ;First fill byte ld b,0 ;Side bit sdsbit equ $-1 ld a,(sside) ;Get the current side xor b ;Conditionally switch side bits ld (sside),a ;Update the side byte ld (hl),0ffh ;Write second fill byte ld b,19h ;Preamble length less one ex Af,Af' ;Save the double sided status sdlblb: ld (hl),0ffh ;Write a fill byte ld a,(status) and index jr z,sdlblb ;Wait for the index hole ex Af,Af' ;Recover the double sided status jr z,sdlblc ;Zero => single sided ld a,(iy+2) ;Get the drive pattern or 0ch ;Turn off the step command and 0fdh ;Turn on head one ld (4005h),a ;Update drive control register ld (hl),0ffh ;Write first preamble byte jp sdlbl3 ;Go format the other side sdlblc: ld (hl),0ffh ;Trailing byte xor a ld (de),a ;Turn off write gate ld a,6 ld (4006h),a ;Turn off the controller ld a,40h ;Status code ret sdadvt: ld a,(strck) ;Get the current track inc a ;Advance track value ld (strck),a ;Update the track value ret ;Return with track value .dephase page ; ; North Star multi desity formatter routine ; nsform equ $ .phase 1030h nsfmt: ld a,0 call sdrive ret nz ld (ix+0bh),0 ld a,(iy+2) or 0eh ld (4004h),a call hsync nsexit: ld a,82h ret z track0: call home bit 5,(hl) jr z,nsexit entry: ld (ix+0bh),0 ld a,(track) cp (iy+1) call nz,seek ld a,(4003h) and 40h ld a,90h ret nz ld (ix+0ah),80h wsect0: call hsync jr z,nsexit xor a cp (ix+0ah) jr nz,wsect0 ld a,90h ld (contrl),a ld hl,diskd ld c,0 ld (ix+9),c ld b,11h ld a,0 den1 equ $-1 rra ld a,64h jr nc,cstart ld a,18h strack equ $-1 rra add a,5 cp (iy+1) sbc a,a and 10h or 24h ld b,20h cstart: ld (4006h),a zerow: ld (hl),0 ex (sp),hl ex (sp),hl djnz zerow ld a,(den1) or a jr z,lasts ld (hl),0fbh ex (sp),hl ex (sp),hl lasts: ld (hl),0fbh ld b,5ch ld e,20h data equ $-1 ld d,20h cpdata equ $-1 xor a d1loop: ex (sp),hl ex (sp),hl ld (hl),e xor e rlca djnz d1loop ld b,51h den2 equ $-1 ex (sp),hl ex (sp),hl ld (hl),d xor d rlca ex Af,Af' ld a,e ld (cpdata),a ex Af,Af' ex (sp),hl ex (sp),hl ld (hl),e xor e rlca d2loop: ex (sp),hl ex (sp),hl ld (hl),e xor e rlca ex (sp),hl ex (sp),hl ld (hl),e xor e rlca djnz d2loop ex (sp),hl ex (sp),hl ld (hl),a ld a,(den1) or a ld b,11h jr z,$+4 ld b,20h iloop: ex (sp),hl ex (sp),hl ld (hl),e ld a,(status) and index jr z,iloop inc c ld a,0ah cp c jr nz,zerow ld c,0 ld a,0 ld (contrl),a ;Turn off the controller (& write gate) push bc ;Delay 1 m.s. ld b,200d dssllp: ld a,a djnz dssllp pop bc ld a,(nsdsid) xor 0 dflag equ $-1 ld (nsdsid),a jr z,ftdone ld a,(iy+2) or 0eh and 0fdh ld (4004h),a jp entry ftdone: ld (contrl),a ;Turn off write gate ld a,40h ret advtrk: ld a,(track) ;Get the current track inc a ;Advance track value ld (track),a ;Update the track value ret ;Return with track value track: 0 nsdsid: 0 .dephase ecode equ $ ;End of code marker, stack follows ds 30h ;Room for the stack buffer equ $ ;Track read buffer end