; I/O Drivers for CMI-19. ; Last changed 6-15-84 by Don Tarbell. ; Hard disk drive equates. cyl equ 306 ; number of cylinders. heads equ 6 ; number of heads. precomp equ 128 ; cyl to start write precomp. lowcurr equ 128 ; low current not used. stepdly equ 2 ; step delay (0-12.7 microsec.) steprcl equ 60 ; recalibrate step delay. headdly equ 0 ; settle delay (0-25.5 microsec.) sectsiz equ 3 ; code for 512 byte sectors. badsiz equ 32 ; # of bad sector entries. hrdspt equ 17 ; physical sectors/track. hcspt equ hrdspt*hstblk ; cpm sectors/track. cpmspc equ hcspt*heads ; cpm sectors/cylinder. ; Morrow Controller Commands. dmaread equ 0 ; read sector. dmawrit equ 1 ; write sector. dmarhed equ 2 ; find a sector. dmawhed equ 3 ; write headers (format track). dmalcon equ 4 ; load disk parameters. dmassta equ 5 ; sense disk drive status. dmanop equ 6 ; null controller operation. reset equ 54h ; reset controller. attn equ 55h ; send a controller attention. chan equ 50h ; default channel address. stepout equ 10h ; step direction out. stepin equ 0 ; step direction in. band1 equ 40h ; no precomp, high current. band2 equ 0c0h ; precomp, high current. band3 equ 80h ; precomp, low current. track0 equ 1 ; track zero status. wflt equ 2 ; write fault from drive. dready equ 4 ; drive ready. sekcmp equ 8 ; seek complete. ; Log in Morrow Hard disk interface drive. ; mapper: mov Byte Ptr hrddsk,cl ; set disk no. for map op. call mwhome ;do a restore. mov cx,0 ; track zero. call mwseek ; seek to zero. mov al,dmaread ; setup for read. mov byte ptr dmaop,al mov dx,(offset hstbuf) ; get host buffer addr. call fndact ; figure physical addr. mov word ptr dmadma,dx ; physical addr a00-a15. mov byte ptr extdma,al ; physical addr a16-a19. mov al,0 mov byte ptr mwsectr,al ; sector 0 for badmap. mov al,2 ; head 2. mov byte ptr mwhead,al call rwsect ; go read the sector. or al,al ; test status of read. jnz overflo mov bx,word ptr badptr ; pick up bad map pointer. mov si, (offset hstbuf) ; start at beginning of buffer. bad1: mov al,[si] ; pick up an entry from buffer. or al,al jz bade ; all done. mov al,[bx] ; pick up entry from bad map table. inc al jz overflo ; bad map overflow. mov al,byte ptr hrddsk ; put drive in table. mov [bx],al inc bx mov cx,8 xchg bx,si ;ldir ; move rest of info into table. ldir: mov al,[bx] ; get a byte. mov [si],al ; put a byte. inc bx ; bump pointers. inc si dec cx ; decrement byte count. or cx,cx ; zero yet? jnz ldir ; loop back if not. xchg bx,si jmps bad1 bade: mov word ptr badptr,bx ;restore new bad map pointer. ret overflo: mov al,byte ptr drvltr ; get absolute drive. add al,'A' ; make ascii. mov byte ptr mapmessagedrive,al mov bx,(offset mapmessage) call prtmsg pop dx ; pop return address. pop bx ; pop dph pointer. mov bx,0 ; indicate select error. push bx push dx ; restore return address. ret ; fndact - Find actual (physical) address of an operand. ; Enter with offset in dx. ; Return with al=a16-19, dx=a00-a15 of physical address. fndact: mov ax,cs ; get base of segment. mov cl,4 ; shift count. rol ax,cl ; shift segment left 4. mov cl,al ; save shifted out top 4 bits. and cl,0fh ; mask for top 4 bits only. and ax,0fff0h add dx,ax ; add shifted segment to offset. mov al,0 ; clear. adc al,cl ; add top 4 & carry. ret ; al=a16-a19, dx=a00-a15. l_1 equ $ dseg org offset l_1 mapmessage rs 0 db cr,lf,'Badmap read error or overflow on ' mapmessagedrive rs 0 db 0,':',0 badptr dw (offset badmap) ;pointer to next bad map entry. l_2 equ $ cseg org offset l_2 ; Common Morrow hard disk read/write routine. findalt: mov hrddsk,cl ; save hard disk no. mov al,cl mov bx,(offset badmap) ;get badmap address. all: mov dx,word ptr badptr ;get bad map pointer. or al,al ;clear carry. xchg bx,dx sub bx,dx jz alt2 ;if the end. xchg bx,dx ; swap back. push bx ; save pointer. mov al,cl ;get drive #. cmp al,[bx] ;check it. jnz altmis ;nope. inc bx ;bump to track. mov al,byte ptr hsttrk ;get lsb track. cmp al,[bx] ;check it. jnz altmis ;nope. inc bx ;bumpt to msb. mov al,byte ptr hsttrk+1 ;get msb track. cmp al,[bx] ;check it. jnz altmis inc bx mov al,[bx] ;get map sector. sbb al,1 ;make real sector number. mov ch,al ;put in b. mov al,byte ptr hstsec ;get sector. cmp al,ch ;check it. jnz altmis inc bx ;alternate found. inc bx ;bump to alternate. mov cl,[bx] ;get lsb alternate track. inc bx mov ch,[bx] ;get msb alternate track. push bx ;save hl. call mwseek ;do the seek. pop bx ;restore hl. inc bx mov al,byte ptr mwop ;get the operation. mov byte ptr dmaop,al ;tell the controller. mov al,[bx] ;get the alternate sector. sbb al,1 ;make real sector number. pop bx ;make stack right. jmps altfnd ;calculate head and do it. altmis: pop bx ;restore hl mov dx,9 ;offset to next badmap entry. add bx,dx jmp all ;look some more. ; jump here if no alternate found. alt2: mov cx,word ptr hsttrk call mwseek ;do the seek. mov al,byte ptr mwop ;get the operation. mov byte ptr dmaop,al ;tell the controller. mov al,byte ptr hstsec ;get the requested sector. ; jump here if an alternate is found. altfnd: mov cl,al ;put in c. mov dh,0 ;clear head counter. seclp: sub al,hrdspt ;subtract out a heads worth. jb secfnd ;jump if found. inc dh ;else bump to next head. mov cl,al ;update sector count. jmps seclp ;and do it again. secfnd: mov al,dh ;get head. mov byte ptr mwhead,al ;save it. mov al,cl ;get sector. mov byte ptr mwsectr,al ;save it also. rwsect: mov al,rtcnt ;get number of retries. mov byte ptr ercnt,al retry: call mwrdwr ;go to it. mov al,0 jnae l_3 ret ;back to mp/m. l_3: mov al,byte ptr ercnt ;get retry count. dec al mov byte ptr ercnt,al ;update count. jnz retry inc al ;set error code. mov erflag,al ; set error flag. ret ;back to mp/m. ; ; these are the low level drivers for the morrow controller. ; reset the controller and do a home on hrddsk. ; mwhome: call mwreset ;reset controller. mov bx,(offset dmarg1) ;load arguments. mov byte ptr [bx],steprcl ;load step delay (slow). inc bx mov byte ptr [bx],headdly ;head settle delay. call mwissue ;do load constants again. call mwptr ;get pointer to current cyl no. mov byte ptr [bx],0 ;setup fake at cyl 0. inc bx mov byte ptr [bx],0 mov cx,2 ;seek in 2 cylinders. call mwseek call mwptr ;get pointer again. mov byte ptr [bx],0ffh ;fake at cyl 255 for max head travel. inc bx mov byte ptr [bx],0ffh mov cx,0 ;seek to cylinder 0. call mwseek ;recal slowly. jmps mwreset ;back to fast stepping mode. ; seek hrddsk to the track in bc. mwseek: call mwptr ;get track pointer. mov dl,[bx] ;get old track number. inc bx mov dh,[bx] dec bx mov byte ptr [bx],cl ;store new track number. inc bx mov byte ptr [bx],ch mov bl,cl ;build cylinder word. mov bh,ch mov word ptr dmarg0,bx ;set command channel cyl no. mov al,dh inc al mov bx,0ffffh jnz mwskip0 mov cl,stepout jmps mwskip mwskip0: mov bh,ch ;(hl)=new track, (de)=old trk. mov bl,cl call mwhlmde mov cl,stepout mov al,bh and al,80h ;check hit bit for - direction. jnz mwsout ;set in. mov cl,0 jmps mwskip mwsout: call mwnegh1 mwskip: mov word ptr dmastep,bx mov al,byte ptr hrddsk or al,cl mov byte ptr dmasel0,al mov al,dmanop ;no-operation command for channel. call mwprep ;step to proper track. mov bx,0 ;clear step counter. mov word ptr dmastep,bx ret ;return back to mp/m. ; ; reset the controller and setup the default parameters. ; mwreset: out reset,al ;send reset pulse to controller. mov dx,(offset dmasel0) ;get command channel address. call fndact ;convert to physical address. push ds ;save data segment register. push cx ;save cx. need to get 0. mov cx,0 ;put zero into DS register. mov ds,cx mov word ptr .chan,dx ;chan addr bits a00-a15. mov byte ptr .chan+2,al ;chan addr bits a16-a19. pop cx ;restore cx, ds. pop ds mov word ptr dmalnk,dx ;put link at end of channel. mov byte ptr dmalnk+2,al mov bx,(offset dmarg1) ;load arguments. mov byte ptr [bx],stepdly ;load step delay. inc bx mov byte ptr [bx],headdly ;head settle delay. inc bx mov byte ptr [bx],sectsiz ;sector size code. inc bx mov byte ptr [bx],dmalcon ;load constants command. jmps mwissue ;do load constants. ; ; do the opration specified by a register. ; mwprep: mov byte ptr dmaop,al ;save command channel op code. ; do the operation specified by dmaop. mwrdwr: mov cl,band1 mov bx,word ptr dmarg0 mov dx,precomp call mwhlcde jb mwpreps mov cl,band2 mov dx,lowcurr call mwhlcde jb mwpreps mov cl,band3 ;cylinder > low_current. mwpreps: mov al,byte ptr mwhead ;load head address. mov byte ptr dmarg2,al not al ;negative logic for controller. and al,7 ;3 bits of head select. rol al,1 ;shove over to bits 2-4. rol al,1 or al,cl ;add on low current and precomp. mov cl,al mov al,byte ptr hrddsk ;load drive address. or al,cl ;slap in drive bits. mov byte ptr dmasel1,al ;save in cmd channel head sel. mov al,byte ptr mwsectr ;load sector address. mov byte ptr dmarg3,al ; start the controller running and wait for completion. mwissue: mov bx,(offset dmastat) ;status byte. mov byte ptr [bx],0 out attn,al ;start controller. mov dx,0 ; outer loop counter. mwilp1: mov cx,1000 ; inner loop counter. mwilp2: mov al,[bx] ;get status. cmp al,0ffh ;test for successful operation. jz mwiret ; hop if successful completion. or al,al ; is it not 0 and not ff? jnz mwierr ; hop out if so. loop mwilp2 ; dec cx, loop if not zero. dec dx ; dec dx, loop if not zero. jnz mwilp1 mwierr: stc ; set carry for error indicator. mwiret: ret ;return no error (carry reset). ; return with hl pointing to the track word for hrddsk. mwptr: mov al,byte ptr hrddsk ;get track address. rol al,1 mov dl,al mov dh,0 mov bx,(offset mwtab) lahf ;offset into track table. add bx,dx rcr si,1 sahf rcl si,1 ret mwnegh1: mov al,bh not al mov bh,al mov al,bl not al mov bl,al lahf inc bx sahf ret mwhlmde: xchg bx,dx call mwnegh1 xchg bx,dx lahf add bx,dx rcr si,1 sahf rcl si,1 ret mwhlcde: mov al,bh cmp al,dh jz l_6 ret l_6: mov al,bl cmp al,dl ret l_7 equ $ ; bios stack area. tmpsp rw 1 rw 40 ; 20 levels. tmp_tos rw 0 ; top of stack. ; Morrow 5-inch Winchester Controller Scratch Area. mwtab rs 0 ; collectionof track addresses. dw 0ffffh ; initialize to dw 0ffffh ; (way out on the end of disk.) dw 0ffffh dw 0ffffh mwop db 0 mwhead db 0 ; currently selected head. mwsectr rs 0 db 0 ; currently selected sector. dmachan equ (offset $) ; command channel area. dmasel0 db 0 ; drive select. dmastep dw 0 ; relative step counter. dmasel1 db 0 ; head select. dmadma dw 0 ; dma address. extdma db 0 ; extended address. dmarg0 db 0 ; first argument. dmarg1 db 0 ; second argument. dmarg2 db 0 ; third argument. dmarg3 db 0 ; fourth argument. dmaop db 0 ; operation code. dmastat db 0 ; controller status byte. dmalnk dw 0 ; link adr to next cmd ch. db 0 ; extended address of link. badmap rs badsiz*9 ; bad sector map. db 0ffh ; end marker. ; these flags control the hard disk drivers. hrddsk db 0 ; hard disk drive number (0-3). mvdat db 0 ; move data flag. cerr db 0 ; offset strobe mask. chkmsk db 0 ; offset head number. chghd db 0 ; head change flag. mapptr dw 0 ; map buffer index. mapbuf db 80h ; must be 80h for first access. rs 40h ; space just in case. ; these tables allow bdos to index the drive attrib info tables. ; hard disk unit - 0. dph8 dw 0000h,0000h ; translate table. dw 0000h,0000h ; scratch area. dw (offset dirbuf),(offset dpbh) ; dir buff, parm block. dw (offset hcsv0),(offset halv0) ; check and alloc. ; hard disk unit - 1. if nhard gt 1 ; if 2 or more drives. dph9 dw 0000h,0000h ; translate table. dw 0000h,0000h ; scratch area. dw (offset dirbuf),(offset dpbh) ; dir buff, parm block. dw (offset hcsv1),(offset halv1) ; check and alloc. endif ; hard disk unit - 2. if nhard gt 2 dph10 dw 0000h,0000h ; translate table. dw 0000h,0000h ; scratch area. dw (offset dirbuf),(offset dpbh) ; dir buff, parm block. dw (offset hcsv2),(offset halv2) ; check and alloc. endif ; hard disk unit - 3. if nhard gt 3 dph11 dw 0000h,0000h ; translate table. dw 0000h,0000h ; scratch area. dw (offset dirbuf),(offset dpbh) ; dir buff, parm block. dw (offset hcsv3),(offset halv3) ; check and alloc. endif ; these tables define the drive physical attributes. ; define a 16-megabyte hard disk in 1 continuous space. dpbh dw cpmspc ; sec/cyl. db 0005 ; block shift. db 0031 ; block mask. db 0001 ; extent mask. dw 3900 ; disk size-1. dw 2047 ; directory max. db 0ffh ; 16 bits for alloc. db 0ffh dw 0 ; check size. dw 0001 ; offset. ; hard disk vectors. halv0 rs 489 ; alloc for drive 0. hcsv0 rs 0 ; check storage. if nhard gt 1 ; if 2 or more drives. halv1 rs 489 ; alloc for drive 1. hcsv1 rs 0 ; check storage. endif if nhard gt 2 ; start condition (nhard>2_true). halv2 rs 489 ; define allocation storage. hcsv2 rs 0 ; check storage. endif ; end condition (nhard>2_true). if nhard gt 3 ; start condition (nhard>3_true). halv3 rs 489 ; define allocation storage. hcsv3 rs 0 ; check storage. endif ; end condition (nhard>3_true).