;Read from controller memory writem equ 0A1h ;Write to controller memory ;Define stepping rate equates ;---------------------------- ; dmfste equ 3*341/10 ;SA851 stepping rate constant dmfset equ 15*341/10 ;SA851 settling rate constant ;Define Internal status byte fields ;---------------------------------- ; dms$t0 equ 01000000b ;Track 0 status mask (1 = on trk 0) dms$dd equ 00100000b ;Double density mask (1 = double) dms$wr equ 00010000b ;Double sided track wrap (1 = wrap) dms$ds equ 00001000b ;Double sided status mask (1 = double) dms$hs equ 00000100b ;Hard sectored status mask (1 = hard) dms$ss equ 00000011b ;Sector size code mask ... ;... 0 = 128, 1 = 256, 2 = 512, 3 = 1024 ;Define North Star status byte fields ;------------------------------------ ; dmn$dä eqõ 10000000â ;Doublå densitù mask dmn$ds equ 01000000b ;Double sided mask dmn$2x equ 00100000b ;CP/M version 2.x mask dmn$ok equ 00010000b ;Validation mask dmn$40 equ 00001000b ;40/80 track mask dmn$dt equ 00000100b ;Double track density mask dmn$xx equ 00000011b ;RFU mask ;Common Subroutines ;------------------ ; Return a pointer to the current drives drive parameter entry ;------------------------------------------------------------- ; dmdpar: lhld dmdriv ;Get the current drive number mvi h,0 ;Drive number is a byte dad h ;Ten bytes per parameter table entry mov d,h mov e,l dad h dad h dad d lxi d,dparam ;Parameter table address dad d ret page if maxdm ne 0 ;Start 8" drive's unique code section ;==================================================================== ;Devicå Specificatioî Tablå foò DJDMA controlleò witè ¸" drives ;============================================================== ; dmdst: db maxdm ;Number of logical drives dw dmwarm ;Warm boot dw dmtran ;Sector translation dw dmldr1 ;Select drive 1 dw dmldr2 ;Select drive 2 dw dmhome ;Home drive dw dmseek ;Seek to specified track dw dmsec ;Set sector dw dmdma ;Set DMA address dw dmread ;Read a sector dw dmwrit ;Write a sector dw nobad ;No bad sector map if dmorder ne 1 ;no warm boot possible ;DJDMA 8" warm boot dummy ;------------------------ ; 1) If 8" DJDMA is not drive A (i.e. dmorder not equal 1) then ; it is not possible to warm boot from 8". So routine not needed. ; dmwarm: ret ;return if called else ;DJDMÁ 8¢ warí booô loader ;------------------------- ; 1) Thió loadeò loadó froí thå starô oæ thå CCÐ (tracë ° sectoò 5© ; tï thå enä oæ thå BDOÓ (tracë ± sector 3)® Onlù 76¸ (3/4k© byteó ; oæ tracë ± sectoò ³ ió reaä iî since thå warí booô routinå ió ; noô alloweä tï loaä anù thå CBIOÓ code. ; 2) Sectoò ³ ió reaä intï thå disë buffeò anä copieä intï itó propeò ; restinç place. ; dmcod8 equ 22*128 ;Amount of code on track 0 to load dmwarm: call dmsel2 ;Select drive 0 dmwbad: lxi h,dmwchn ;Warm boot command channel lxi d,dmwoff call dmcmd ;Execute the channel jnz dmwbad ;Retry lda dmwst0 ;Get track read status lhld dmwst1 ;Track ones status in L ora l cpi 40h jnz dmwbad ;Loop on 'terrible' errors like no disk lxi b,300h ;Move .75 Kbytes of sector 3 lxi d,buffer ;Sector 3 is in our buffer lxi h,ccp+1300h ; and this is where we want it to go call movbyt xra a ret dmwchn: db dmsdma ;Set track 0 DMA address dw ccp-512 ;First track DMA address - boot loader db 0 db rdtrck ;Read track command db 0 ;Track 0 db 0 ;Side 0 db 0 ;Drive 0 dw dmwmap ;Sector load/status map db 0 dmwst0: db 0 ;Track read status db dmsdma dw ccp+dmcod8 ;DMA address for track 1 db 0 db rdtrck db 1 ;Track 1 db 0 ;Side 0 db 0 ;Drive 0 dw dmwmap+26 ;Load map right after track 0 map db 0 dmwst1: db 0 ;Track read status db dmsdma dw buffer ;Sector 3 gets loaded in system buffer db 0 db dmrsec db 1 ;Track 1 db 3 ;Side 0, sector 3 db 0 ;Drive 0 db 0 ;Read status db dmhalt ;Controller halt command db 0 dmwoff equ $-dmwchn-1 ;Halt offset for the command channel dmwmap: dw -1, -1, 0, 0, 0, 0, 0 ;Do not load the boot loader dw 0, 0, 0, 0, 0, 0 dw 0, -1, -1, -1 ;First 2 sectors on track 2 endif ;end of 8" DJDMA warm boot ;DJDMA 8" sector translation ;--------------------------- ; dmtran: inx b ;Ajust sectors to start at 1 lda dmpsta ;Test for double sided drives ani dms$ds jz dmtrn0 ;Skip if single sided lda dmcspt ;Get SPT/2 sub c ;Test for side one sectors jnc dmtrn0 ;Skip sector adjustment if on side zero cma ;'Knock off' first sides sectors inr a mov c,a mvi b,80h ;Set side one flag dmtrn0: mov l,c ;Make an index to the SECTRAN table mvi h,0 dad d mov l,m ;Load the translated sector mov h,b ;Set the side bit ret ;DJDMÁ 8¢ drivå selecô 1 ;----------------------- ; 1) Determinå thå sectoò sizå anä thå numbeò oæ sideó oî thå drive® ; 2) Returî correcô DPH. ; dmldr1: call dmsel2 ;Do logical select call dminit ;Test for a controller jc zret ;Skip if no controller present call dmstat ;Accm:= Djdma_returned_Drive_Status jc zret ;Skip on status check error push psw ani dms$t0 ;Check for track 0 jz dmldr0 ;Skip if not on track 0 (status valid) pop psw ;Clean stack lxi h,1 ;read sector 1 ... shld truesec inx h ;... of track 2 shld cpmtrk ;because track 1 always single density xra a sta rdwr ;force read to get valid drive status call fill ;flush buffer and read jc zret ;exit with error if error call dmdpar ;Get the drive parameter address inx h mvi m,0 ;Decalibrate the drive call dmparm call dmstat ;Accm:= Djdma_returned_Drive_Status jc zret ;If (error eq true) goto error_return push psw dmldr0: pop psw ;Get drive status sta dmpsta ;Set the physical status mode call dmsptr ;Save status in status table mov m,a ani dms$ss ;Mask in sector size bits rlc ;Make a word index push psw ;Used to select a DPB mov e,a mvi d,0 lxi h,xlts ;Table of XLT table pointers dad d push h ;Save pointer to proper XLT call dmgdph ;Get a pointer to the drives DPH pop d ;Copy XLT pointer from table to DPH lxi b,2 call movbyt lxi d,8 ;Offset to DPB pointer dad d push h lda dmpsta ;Test for a double sided drive ani dms$ds lxi d,dpb128s ;Base for single sided DPB's jz dmsok call dmfstp ;Set controller to fast steping mode lxi d,dpb128d ;Base of double sided DPB's dmsok: xchg poð ä ;Restorå DPH pointeò to DPB pop psw ;Offset to correct DPB (sector size) rlc ;Times 4 rlc ; 8 rlc ; 16 bytes per DPB mov c,a ;Offset to the correct DPB mvi b,0 dad b xchg ;Load the DPB pointer in the DPH mov m,e inx h mov m,d lxi h,15 ;Offset to the sector size code dad d mov c,m dmgdph: lda dmdriv ;Get the DPH pointer lxi d,dphdm0 call retdph ret ;DJDMÁ 8¢ drivå selecô 2 ;----------------------- ; 1) Figurå numbeò oæ sectoró_peò_trac믲 foò SECTRAN. ; ; dmldr2: call dmsel2 ;Perform logical drive select call dmgdph ;Load the DPH pointer lxi d,10 ;Offset to the DPB pointer dad d mov a,m ;Load the DPB pointer inx h mov h,m mov l,a mov a,m ;Load the number of CP/M sectors/track rrc ;Divide by two sta dmcspt ;Save CPM SPT ret ;Set the drive's step rate to 3ms ;-------------------------------- ; 1) Thå currenô drivå ió doublå sided® Thuó ió iô safå tï seô thå ; steppinç ratå tï ³ mó witè 1µ mó settling. ; dmfstp: call dmdpar ;Get the parameter table pointer inx h ;Bump to the drive initialized flag mvi m,0 ;Force reparamitization of this drive inx h ;Offset to the Stepping rate constant mvi m,(low dmfste) ;Fast stepping rate constant inx h mvi m,(high dmfste) lxi d,5 ;Skip over the reserved fields dad d mvi m,(low dmfset) ;Fast settling rate constant inx h mvi m,(high dmfset) call dmparm ;Set drive parameters for the SA850 ret ;DJDMA 8" driver variables ;--- ° ; sidå 1). ; mfseek: xra a ;Clear double sided select flag sta mfsid1 lxi h,dmpsta ;Get the drive status mov a,m ani dms$hs ;Test for hard sectored drives jz dmsoft ;Skip if soft sectored mov a,m ;Test for double sided drives ani dms$ds jz dmseek ;Skip if single sided mov a,m ;Test for track wrap mode ani dms$wr jz dmseek ;Skip if not wrapping mov a,c ;Test for tracks 35-69 cpi 35 jc dmseek ;Skip if less than track 35 mvi a,69 ;Adjust tracks 35 -> 69 to 34 -> 0 sub c mov c,a mvi a,080h ;Set side one flag sta mfsid1 jmp dmseek dmsoft: mov a,m ;get drive status again ani dms$ds ;check for double sided (cy = 0) jz dmseek ;skip if not double sided mov a,c ;get track number rar ;divide by 2 for Morrow soft sectored mov c,a jnc dmseek ;skip if on side 1 mvi a,80h sta mfsid1 ;else indicate side 2 jmp dmseek ;DJDMA 5.25" set sector ;---------------------- ; mfssec: lda dmpsta ;if (drive .eq. soft_sectored) ani dms$hs ; goto sector save routine jz dmsec ;else dcr c ; adjust for first sect = zero jmp dmsec ;DJDMA 5.25" read/write sector ;----------------------------- ; mfread: call mfset ;Set up side flag jmp dmread mfwrit: call mfset ;Set up side flag jmp dmwrit mfset: lda mfsid1 ;Get the side flag lxi h,dmsctr ;Merge with the sector number ora m mov m,a ret ;DJDMA 5.25" driver variables ;---------------------------- ; ;Mini-Floppy Configuration/DPB_Lookup table ; 1) This table is used by the mini-floppy first time select routine ; (mfsldr1) and is used to: ; a) validate the drive configuration byte. ; b) fill in the parameters that can't be determined by doing ; sense drive status (like sensing double sided drives). ; c) returning a pointer to the proper DPB for the media. ; 2) There are four fields per entry. ; Field_1: Drive configuration byte. ; Field_2: Additional drive parameters that can't be determined ; by doing a sense drive status (i.e. double_sided and ; track_wrap). ; Field_3: Pointer to the appropriate DPB ; mfs: db 10h ;North Star CP/M 1.4 db 0 ;Single density, 35 tracks, 1-sided dw dpbmf0 ;1K groups db 90h ;North Star CP/M 1.4 db 0 ;Double density, 35 tracks, 1-sided dw dpbmf1 ;1K groups db 0b0h ;North Star CP/M 2.x db 0 ;Double density, 35 tracks, 1-sided dw dpbmf2 ;2K groups db 0f0h ;North Star CP/M 2.x db (dms$ds or dms$wr) ;Double density, 35 tracks, 2-sided dw dpbmf3 ;2K groups db 0a0h ;North Star CP/M 2.x (fake 40 track) db 0 ;Double density, 35 tracks, 1-sided dw dpbmf2 ;2K groups db 0d0h ;North Star CP/M 2.x (fake 40 track) db (dms$ds or dms$wr) ;Double density, 35 tracks, 2-sided dw dpbmf3 ;2K groups db 0a1h ;Morrow Designs CP/M 2.x Soft sectored db 0 ;Double density, 40 tracks, 1-sided dw dpbmf4 db 0a9h ;Morrow Designs CP/M 2.x Soft sectored db dms$ds ;Double density, 40 tracks, 2-sided dw dpbmf5 db 0 ;End of configuration table ; Hard sectored single sided sector translation table ; mfxlts: db 1, 2 db 3, 4 db 5, 6 db 7, 8 db 9, 10 db 11, 12 db 13, 14 db 15, 16 db 17, 18 db 19, 20 ; Hard sectored double sided sector translation table ; mfxltd: db 1, 2, 3, 4 db 21, 22, 23, 24 db 5, 6, 7, 8 db 25, 26, 27, 28 db 9, 10, 11, 12 db 29, 30, 31, 32 db 13, 14, 15, 16 db 33, 34, 35, 36 db 17, 18, 19, 20 db 37, 38, 39, 40 ; Soft sectored single sided translation table ; mfxlt1: db 1, 2, 3, 4, 5, 6, 7, 8 db 25, 26, 27, 28, 29, 30, 31, 32 db 9, 10, 11, 12, 13, 14, 15, 16 db 33, 34, 35, 36, 37, 38, 39, 40 db 17, 18, 19, 20, 21, 22, 23, 24 mfsid1: db 0 ;On side one flag ;disk parameter headers ;---------------------- ; dphmf0: dw 0 ;translation table address dw 0 dw 0 dw 0 dw dirbuf ;directory buffer dw dpbmf0 ;pointer to disk parameter block dw csvmf0 ;scratch pad area for checking changed disks