title 'Loader module for CP/M 3.0 Jonos ltd. 5 1/4" 1.0meg' ; ;ver 1.0 ;last update 6/29/83 ;Copyright 1983 Jonos LTD. ;1835A Dawns Way ;Fullerton Calif. 92631 ;(714)-999-6661 ; ;by C.Norman Campbell ; true equ -1 ;set value true false equ not true ;set value false ; ; cseg ;GENCPM puts cseg in common memory ; ; ; maclib modebaud ;define mode bits maclib ports ; maclib z80 ; maclib cpm3 ; ; variables is system data page ; ; ; ; extrnal names for BIOS entry points ; public ?boot,?wboot,?const,?conin,?cono,?list,?auxo,?auxi public ?home,?sldsk,?sttrk,?stsec,?stdma,?read,?write public ?lists,?sctrn public ?conos,?auxis,?auxos,?dvtbl,?devin,?drtbl public ?mltio,?flush,?mov,?tim,?bnksl,?stbnk,?xmov ; ; BIOS jump vectors ; ?boot: jmp boot ;initial entry on cold start ?wboot: jmp 0 ;not used ; ?const: jmp 0 ;not used ?conin: jmp 0 ;not used ?cono: jmp conout ;send console output character ?list: jmp 0 ;not used ?auxo: jmp 0 ;not used ?auxi: jmp 0 ;not used ; ?home: jmp home ;set disk to logiacal home ?sldsk: jmp seldsk ;select disk drive, return disk parms. ?sttrk: jmp settrk ;set disk track ?stsec: jmp setsec ;set disk sector ?stdma: jmp setdma ;set disk I/O memory address ?read: jmp read ;read physical block(s) ?write: jmp 0 ;not used ; ?lists: jmp 0 ;not used ?sctrn: jmp sectrn ;translate logical to phyical sector ; ?conos: jmp conost ;console output status ?auxis: jmp 0 ;not used ?auxos: jmp 0 ;not used ?dvtbl: jmp devtbl ;return addres of def table ?devin: jmp 0 ;change baud rate of device ; ?drtbl: jmp getdrv ;return address of disk drive table ?mltio: jmp multio ;set multiple record count for I/O ?flush: jmp 0 ;not used ; ?mov: jmp move ;move block of memory ?tim: jmp 0 ;not used ?bnksl: jmp 0 ;not used ?stbnk: jmp 0 ;not used ?xmov: jmp 0 ;not used ; jmp 0 ;reserved for future expansion jmp 0 ;reserved for future expansion jmp 0 ;reserved for future expansion ; ; BOOT ; ; boot: xra a ;only need to set up sta @rdrv ;floppy disk controller for call fd$init$0 ;cpm load ret ;done ; ; devtbl return address of character device table ; devtbl: lxi h,@ctbl ;get address ret ;return with it ; ; getdrv return address of drive table ; getdrv: lxi h,@dtbl ;get address ret ;return with it ; ; character device output ; conout: call conost ;get status ora a ;set flags jz conout crt$out: mov a,c ;get character out crt$0$d ;output it ret ; ; character device output status ; conost: in crt$0$s ;input status ani 01h ;mask txrdy bit rz ;return not ready mvi a,0ffh ;set status ready ret ; ; ; character device table ; @ctbl: db 'INTCRT' ;device 0, internal CRT db mb$in$out+mb$serial db baud$none db 0 ;table terminator ; ; block move routine ; move: xchg ;pass source to and dest to ldir ;use z80 block move xchg ;next address in same regs ret ;we are all done here ; ;disk I/O interface ; ; seldsk select disk drive ; drive code in . Invoke login procedure for drive if this ; is frist select. Return address of disk parameter header in . ; seldsk: mov a,c ;get drive # sta @adrv ;save it mov l,c ;make index from drive code mvi h,0 ;zero h dad h ; lxi b,@dtbl ;get dispatch table pointer dad b ; mov a,m ;point to disk descripter inx h ; mov h,m ; mov l,a ; ora h ;if no entry in table, no disk rz ; mov a,e ;examine login bit ani 1 ; jnz not$frist$select; push h ;put pointer in stack and xchg ; lxi h,-2 ;get reative drive dad d ; mov a,m ; sta @rdrv ; lxi h,-6 ;find login addr dad d ; mov a,m ;get address of login routine inx h ; mov h,m ; mov l,a ; call ipchl ;call login pop h ;recover DPH pointer not$frist$select: ret ;done ; ipchl: pchl ; ; ; ; home home selected drive ; home: lxi b,0 ;same as set track 0 ; ; settrk set track. save track address from in @trk ; for futher operations ; settrk: mov l,c ; mov h,b ; shld @trk ; ret ;done ; ; setsec set sector. save sector number from in ; @sect for further operations. ; setsec: mov l,c ; mov h,b ; shld @sect ; ret ; ; ; setdma set disk dma address ; Saves DMA address from in @DMA and sets @DBNK to @CBNK ; so that futher disk operations take place in current bank ; setdma: mov l,c ; mov h,b ; shld @dma ; ret ; ; ; ; sectrn Sector translate. Indexes skew table in with ; sector in . Returns physical sector in . If no ; skew table then returns physical=logical. ; sectrn: mov l,c ; mov h,b ; mov a,d ; ora e ; rz ; xchg ; dad b ; mov l,m ; mvi h,0 ; ret ; ; ; read Read physical record from currently selected drive. ; Find address of proper read routine from extened disk parameter ; header (XDPH) ; read: lhld @adrv ;get drive code and double it mvi h,0 ; dad h ; lxi d,@dtbl ;make address of table entry dad d ; mov a,m ;fetch table entry inx h ; mov h,m ; mov l,a ; push h ;save address of table lxi d,-8 ;point to read routine address dad d ; mov a,m ;get address of routine inx h ; mov h,m ; mov l,a ; pop d ;recover address of table dcx d ;point to relative drive dcx d ; ldax d ;get relative drive code and post it sta @rdrv ; inx d ;point to DPH again inx d ; pchl ;leap to driver ; ; multio Set multiple sector count. Save pass count in @cnt ; multio: sta @cnt ; ret ;done ; ; @dtbl: dtbl fd516 ; dw 0 ;write would go here dw fd$read ;read for 5 1/4" drive dw fd$login ;login for 5 1/4" drive dw fd$init0 ;initialization for drive 0 db 0,0 ;relative drive 0 fd516 dw 0000h ;no table db 0,0,0,0,0,0,0,0,0 ;bdos scrach db 0 ;media flag dw dpbsd ;Disk Parameter Block dw csv0 ;check sum vector dw alv0 ;allocation vector dw dirbcb ; dw dtabcb ; dw 0ffffh ; db 0 ; dirbcb db 0ffh ;drv, set to ff to start dw 0000h ;rec# db 00h ;rec# db 00h ;wflg db 00h ;chratch for bdos dw 0000h ;track # dw 0000h ;sector dw dirbuf ;dir buffer dtabcb db 0ffh ;drv, set to ff to start dw 0000h ;rec# db 00h ;rec# db 00h ;wflg db 00h ;chratch for bdos dw 0000h ;track # dw 0000h ;sector dw dtabuf ;dir buffer ; ; ; ; dpbsd dpb 1024,4,160,2048,128,4 ;for 5 1/4 1.6 meg drives ; ; ; Disk I/O routines for 5 1/2" disk drive ; fd$init0: call spec5 ;set up controller call home15 ;home disk xra a ;zero a sta sec$cnt ;multio sector count ret ; ; fd$login: ret ;this routine is called to determine ;density. Sony drive are all the same ;so no need for this ; ; fd$read: ;perform read operation mvi a,40h ;set read bit for DMAC sta type ;store dma count mvi a,0c6h ;load read command mfm mode sta temp ; ; common5: lxi h,0000h ;zero hl shld dma$offset ;zero dma offset lda @cnt ;get multio count dcr a ;see if one sector operation jz one$sector ; ;must be multio lda sec$cnt ;get sector count ora a ;zero ? jz do$multio ;do the multi sector i/o dcr a ;-1 sta sec$cnt ;save jnz dec$cnt ; mvi a,01 ; sta @cnt ; dec$cnt: xra a ;set no errors ret ;return to bdos do$multio: lda @cnt ;get sector count dcr a ;-1 sta sec$cnt ; call seekcl5 ;seek frist track to read/write lda @cnt ;get # sectors to transfer mov b,a ;put in b for clac. lda @sect ;get starting sector # mov c,a ;find max # of sectors this track mvi a,04 ; sub c ; mov c,a ;put in c mov a,b ;find # of sectors sub c ;to transfer this track jm less$max ;jump if less sector that maxs jz less$max ;max and cnt the same, do it ; loop to transfer rest to sectors next$track: sta sec$left ;store # of sector to read call ex$command ;transfer this track ora a ;see if error jnz error$multio ;jump if error lda @trk ;get track number inr a ;next track (bdos will not overrun track) sta @trk ;store for transfer call seekcl5 ;seek track xra a ;zero a reg sta @sect ;start with sector 0 for new track lda sec$left ;get # of sector left to transfer mov b,a ;put in b sui 04 ;find # of sector to transfer this track jm less$max ;jump if less that one track jz less$max ;jump if = one track mvi c,04 ;transfer one track jmp next$track ;loop till all read ; error$multio: mov b,a ;store error status (normaly 01h) mvi a,01h ;reset count sta @cnt ;store it mov a,b ;get error status back ret ;return to bdos with error status in ; ; sector to trans. less max that can be this track less$max: mov c,b ;get number of sector to trans to jmp ex$command ;do it ; only one sector transfer one$sector: sta sec$cnt ;mullio sector count to zero call seekcl5 ;seek track mvi c,01h ;must be one sector ; ; =number of sectors to read on one track ; ex$command: lhld @dma ;get dma address xchg ;to de lhld dma$offset ;get dma address offset dad d ;add offset shld @dma ;store new address lxi h,0000h ;zero lxi d,1024 ;get length one sector loop$length: dad d ;add one setor dcr c ;-1 on count jnz loop$length ;loop till done shld dma$offset ; dcx h ;-1 lda type ;get type of command mov d,a ;put in d mvi e,00h ;zero e dad d ;add to length shld dmaset ;set dma count and type lxi h,comtb ;point to command table lda temp ;get type of command mov m,a ;put in command table call waitio5 ;go do command ret ;return with error status ; ;enter here from read or write to perform the actual i/o ;for 3" drive ; the disk number in '@rdrv' (0,1) ; the track number in '@trk' (0-77) ; the sector number in '@sect' (0-15) ; the dma address in '@dma' (0-65535) waitio5: inx h ;point to next location in memory lda @trk ;get track # ani 01h ;see if side #1 lda @rdrv ;get drive # jz side0 ;jump if side #0 ori 04h ;set side #1 side0: mov m,a ;store in command table inx h ;next command word storage lda @trk ;get track # ora a ;clear carry flag rar ;set track # 0-77 mov m,a ;store in table inx h ;next mvi b,00h ;select head 0 jnc nots1 ;jump if side 0 inr b ;set for head 2 nots1: mov m,b ;store head # inx h ;point to sector lda @sect ;get sector # mov m,a ;store in command table inx h ;next mvi m,03h ;set n=3 for 1024 bytes inx h ;next mvi m,04h ;8 secotrs per track inx h ;next mvi m,80h ;gap =53 inx h ;next mvi m,0ffh ;dtl mvi a,7 ;store retry count sta retry ;store call erloop5 ;do i/o lda seeker ;get seek error status ora a ;set flags rz ;return if done call spec5 ;set up controller call home15 ;home disk if was seek error call seekcl5 ;seek track to read lxi h,comtb ;point to command table lda temp ;get command mov m,a ;store command (read or write) jmp waitio5 ;try 10 more times ; ;start of i/o routine used by 5 1/4" and (8" drives) ; erloop5: ;loop to here if to try again lhld dmaset ;get dma count mov a,l ;get lsb out dma0tc5 ;output terminal count mov a,h ;get msb out dma0tc5 ;output terminal count lhld @dma ;get dma address mov a,l ;get lsb out dma0ad5 ;output to dma contoller mov a,h ;get msb out dma0ad5 ;output to dma controller mvi a,41h ;enable dma controller out dmacm5 ;output lxi h,comtb ;point to command table mvi c,9 ;load byte count for command write call wfdcc3 ;write command call polli3 ;poll interrupt status till done call result3 ;read result lda rbuf ;get status byte #0 ani 0d8h ;mask bits jnz rty3 ;retry if error lda rbuf+1 ;get status byte #1 ani 7fh ;mask status bytes jz dtest3 ;return no errors rty3: lda retry ;get retry count dcr a ;-1 sta retry ;store new retry count jnz erloop5 ;loop # trys lda seeker ;see if second time ora a ;set flags jnz sectry ;set error and retrun mvi a,0ffh ;set flag sta seeker ; lda comtb ;get coomand sta temp ;store in temp ret ; sectry: xra a ;zero a register sta seeker ;reset seek error stat hard$error: mvi a,01h ;get error status sta er$flag ;update error flag ret ;return ; ;if command was write delay for tunnel erase ; dtest3: xra a ;zero a reg sta seeker ;reset error flag sta erflag ; mov b,a ;zero b for error status lda comtb ;load frist byte command table ani 0Fh ;mask bits 0-3 cpi 05h ;see if write command mov a,b ;get error status rnz ;return if not write mvi a,9eh ;get delay count delay3: dcr a ;bump count jnz delay3 ; mov a,b ;get error status (allways 0) ret ; ; FDC set up routines ; ; ; spec5: ;set head unload time, head load mvi a,1001b out intsp5 ;time, step rate lxi h,spctb3 ;load pointer to command table spec51: mvi c,03h ;load byte count call wfdcc3 ;write command to controller ret ;return ; ; disk prams for Mitsubishi 5 1/4" drives ; spctb3: ;specify prams. table db 03h ;command db 0efh ;step rate 03ms, head unload 240ms db 0ch ;head load time 50ms,dma mode ; ; ; home15: ;home disk drive in @rdrv lxi h,comtb+1 ;load pointer command table lda @rdrv ;get disk to home mov m,a ;put in table dcx h ;point to next buffer location mvi m,07h ;load recalibrate command mvi c,2 ;load byte count for command write call wfdcc3 ;write command call polli3 ;poll interrupt status call sic3a ;call sense interrupt command ret ;return when have good home ; ; seekcl5: ;seek the track in track loc. lda @trk ;get trak to seek ora a ;see if track 0 jz home15 ;home if track 0 rar ;shift for track # lxi h,comtb+2 ;point to command table mov m,a ;store track to seek dcx h ;point next location lda @rdrv ;get disk # mov m,a ;store command in table dcx h ;point next location mvi m,0fh ;load seek command mvi c,3 ;set byte count for command write call wfdcc3 ;write command call polli3 ;wait till done call sic3a ;sense interrupt status command ret ; ; sic3a: lxi h,sictb3 ;load pointer command table mvi c,1 ;load byte count call wfdcc3 ;write command to FDC lxi h,rbuf ;load pointer result storage mvi c,2 ;load byte count for result read call rest13 ;read result in to buufer ret ; sictb3: ;sense interrupt command table db 08h ;command ; ; result3: ;read result phase FDC lxi h,rbuf ;load pointer Result BUFfer mvi c,7 ;load byte count for read/write call rest13 ;read result ret ;return rest13: in fdcsr5 ;input FDC status reg. ral ;test bit 7 jnc rest13 ;loop till ready in fdcd5 ;input result read data mov m,a ;put in buffer inx h ;bump pointer dcr c ;dec byte count rz ;return if done jmp rest13 ;loop till all bytes read ; ; ; ; polli3: ;poll interrupt pin FDC in intsp5 ;input status ral ;test bit 7 jnc polli3 ;loop till interrupt pin true ret ;return when true ; wfdcc3: ;write command to FDC wfdcc: in fdcsr5 ;input status ral ;test bit 7 jnc wfdcc ;loop till ready mov a,m ;get command byte out fdcd5 ;output to FDC inx h ;bump command pointer dcr c ;dec byte counter rz ;return when done jmp wfdcc ;loop till all bytes output ; ; ; scratch ram area for disk driver use ; retry: ds 1 ;retry count rbuf: ds 7 ;result buffer seeker: ds 1 ;seek error try flag temp: ds 1 ;temp storage dmaset: ds 2 ;dma terminal count erflag: ds 1 ;error reporting sec$cnt: ds 1 ;multio sector count type: ds 1 ;type of command secleft: ds 1 ;sector left to transfer dma$offset: ds 2 ;dma offset multio comtb: ds 9 ;command table storage ; ; ; ; disk communication data items ; @adrv ds 1 ;currently selected disk drive @rdrv ds 1 ;controller relative disk drive @trk ds 2 ;current track number @sect ds 2 ;current sector number @dma ds 2 ;current DMA address @cnt db 01 ;record count for multisector transfer ; csv0 ds 32 alv0 ds 80 ; dirbuf ds 1024 dtabuf ds 1024 ; ; end