IMD 1.17: 29/05/2011 12:31:07 disk drivers disk turbodos v SOURCE DSKA3033 ACDMA5F ACDMA5R ACDSKTBL ACHARDISK ACR HARDISK2ACR HARDTBLSACHDCBOOT AC5MAX105 ACMAX140 ACMAX65 ACMC1302 ACMC1303 ACMC1304 ACMS3425 MACPARK AC Q2010 AC!Q2020 AC"Q2030 AC#Q2040 AC$README SK%S6LOAD AC&'SA1002 AC(SA1004 AC)SA604 AC *ST412 MAC+ST419 AC,ST425 AC-ST506 AC.TM501 AC/TM502 AC0TM503 AC1TRK0BDOSAC^234567TRK0BIOSAC89:;<=>?TRK0BIOSAC@ABCDEFGTRK0BIOSACHTRK0BOOTQU ITRK0BOOTAC JTULIN213ACKTULIN226ACLTULIN240ACMS6BNK AC NOS6DSK ACPQRSTUVWS6DSK AC XYS6DSK ELS6DST58FACKZ[\]^S6NIT AC_`S6RTC ACaS6SIO ACbcdefghiS6SIO AC jS6SOM ACkCONDR AClmDREQUATEIBnoEQUATE IB6pqrsFORMATH ACtuvwxyz{FORMATH AC |LSTCTS AC }LSTETX AC~LSTPAR ACLSTXON ACVECINT ACMCDSS ACvSLVRES ACSSBNK ACSSBOOT AC$SSCKTDR AC$SSLOAD AC SSLSTPARACSSNIT ACSSRTC ACSSSIO2 ACSSSIO2 AC SSSIO4 ACSSSIO4 AC{SSSOM ACtitle Hard disk specification table subttl Advanced Digital 7/3/84 name ('A3033') ; Module name (6 chars only) tracks equ 645 ; physical tracks heads equ 5 ; physical heads steprt equ 6 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 1024 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 16 ; sectors per track (head) secsiz equ 512 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro dseg ; locate in data segment A3033@:: ; Global entry point for patching (6 chrs only) setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*heads/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*heads*(tracks-trkoff) ; total blocks endif db ((dirsiz*8)/blksiz)*4 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end title Hard disk specification table subttl Advanced Digital 7/3/84 name ('DMA5F') ; Module name (6 chars only) tracks equ 306 ; physical tracks heads equ 4 ; physical heads steprt equ 15 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 1024 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 2 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 32 ; sectors per track (head) secsiz equ 256 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro dseg ; locate in data segment DMA5F@:: ; Global entry point for patching (6 chrs only) setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db ((dirsiz*8)/blksiz)*4 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end title Hard disk specification table subttl Advanced Digital 7/3/84 name ('DMA5R') ; Module name (6 chars only) tracks equ 306 ; physical tracks heads equ 2 ; physical heads steprt equ 15 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 1024 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 32 ; sectors per track (head) secsiz equ 256 ; sector size 512 or 256 fixed equ 0 ; set to 1 for fixed media else 0 for removable ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro dseg ; locate in data segment DMA5R@:: ; Global entry point for patching (6 chrs only) setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db ((dirsiz*8)/blksiz)*4 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end title Hard disk specification table subttl Advanced Digital 7/3/84 name ('NAME') ; Module name (6 chars only) tracks equ 512 ; physical tracks heads equ 8 ; physical heads steprt equ 0 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 1024 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 16 ; sectors per track (head) secsiz equ 512 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable dseg ; locate in data segment NAME@:: ; Global entry point for patching (6 chrs only) ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db ((dirsiz*8)/blksiz)*4 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end  title TURBODOS OPERATING SYSTEM - HDC1001 HARD DISK DRIVER subttl Written by Kevin Aguilar for Advanced Digital 6/23/84 ; Version: 2; Changed code to correctly sense ECC 9/18/84 K.A. ; Version: 3; Retrdy modified to test for ready ; before restoring drive 9/20/84 K.A. .z80 ; z80 code implemented name ('HRDISK') ; module id include DREQUATE.LIB ; o/s symbolic equates ;*** port equates for hdc1001 *** hdcbase equ 0e0h ; base of hdc1001 hdcdata equ hdcbase ; data port wpc equ hdcbase+1 ; write precomp port secnt equ hdcbase+2 ; sector count secno equ hdcbase+3 ; sector number cyllo equ hdcbase+4 ; cylinder low cylhi equ hdcbase+5 ; cylinder high sdh equ hdcbase+6 ; size/drive/head comnd equ hdcbase+7 ; command register hdcerr equ wpc ; error port status equ comnd ; status register ;*** command equates for hdc1001 *** crest equ 10h ; restore command cread equ 20h ; read command cwrite equ 30h ; write command cform equ 50h ; format track cseek equ 70h ; seek command ;*** status and error bits secbit equ 6 ; sector size ecc equ 7 ; ecc bit flag bsy equ 7 ; hard disk busy bit seek equ 4 ; seek complete bit errs equ 1 ; hard disk errors mask rdy equ 64 ; hard disk ready mask dseg ; data stuff dmxsph: ; mutual exclusion semaphore dw 1 ; semaphore count ..dmxh: dw ..dmxh ; semaphore p/d head dw ..dmxh hdcsph: ; hdc semaphore dw 0 ; semaphore count ..hdch: dw ..hdch ; semaphore p/d head dw ..hdch stksav: dw 0 ; stack save dmaptr: dw 0 ; temporary dma pointer storage errors: db 0 ; error save area sector: db 0 ; temporary sector storage seccnt: db 0 ; temporary sector count storage phyinfo:db 0 ; physical info hdoffst:db 0 ; head offset for current drive phydrv: db 0 ; current physical drive sechd: db 0 ; sectors per head nitflgs:db -1,-1,-1,-1 ; drive initialization flags cseg ; code stuff dskdr@::ld hl,dmxsph ; get mutual exclusion semaphore call wait## ; dispatch if necessary call ..dd ; call disk driver push af ; save return code ld hl,dmxsph ; get mutual exclusion semaphore call signal## ; signal process as ready pop af ; restore return code ret ; done ..dd: ld (stksav),sp ; save the stack ld a,(ix+pdrfcn) ; get pd req function number or a ; pd req function number=0? jp z,read ; if so, continue dec a ; pd req function number=1? jp z,write ; if so, continue dec a ; pd req function number=2? jp z,retdst ; if so, continue dec a ; pd req function number=3? jp z,retrdy ; if so, continue dec a ; pd req function number=4? jp z,format ; if so, continue ret ; else, done read: call setup ; select disk and initialize pointers ..reads:call trnslt ; translat sector to heads ld a,cread ; send read command out (comnd),a ; send command to controller call wthdc ; wait until done ld bc,hdcdata ; set up port address ld hl,(dmaptr) ; get dma address inir ; get data bit 0,(ix+secsiz) ; 512 byte sectors jr nz,..rd256 ; skip if not inir ; else get more data ..rd256:ld (dmaptr),hl ; save dma address call update ; update pointers jr nz,..reads ; get next sector jp finish ; finish up write: call setup ; initialize pointers ..wrts: call trnslt ; translat sector to heads ld a,cwrite ; send write command out (comnd),a ld bc,hdcdata ; set up port address ld hl,(dmaptr) ; get dma address otir ; send data bit 0,(ix+secsiz) ; 512 byte sectors jr nz,..wr256 ; skip if not otir ; else get more data ..wr256:ld (dmaptr),hl ; save dma address call wthdc ; wait until done call update ; update pointers jr nz,..wrts ; get next sector verify: call setup ; select disk and initialize pointers ..vfys: call trnslt ; translat sector to heads ld a,cread ; send read command out (comnd),a ; tell the controller call wthdc ; wait until done in a,(status) ; get status and 5 ; check the corrected bit and error bit call nz,beep ; jump if bad verify call update ; update pointers jr nz,..vfys ; get next sector finish: ld a,(errors) ; get accumulated errors or a ; set flags jr z,exit ; exit fatal: xor -1 ; preset to ff exit: call off ; turn off drive ld sp,(stksav) ; get the stack back ret ; exit to TuRboDoS format: call retrdy ; initialize drive call setup ; select disk and setup pointers call trnslt ; translat sector to head # ld hl,(dmaptr) ; set hl to dma address ld a,(seccnt) ; get sector count out (secnt),a ; send to hdc xor a ; zero a out (secno),a ; reset the sector to 0 ld a,cform ; issue format command out (comnd),a ld bc,hdcdata ; load bc with port addr & count ld a,(phyinfo) ; get phyinfo bit secbit,a ; 512 byte sectors jr z,..fmt256 ; skip if so set 7,b ; else set b = 80h for 256 byte sectors ..fmt256:xor a ; zero a ..loop: out (c),a ; send bad block byte outi ; send interleave byte  jr nz,..loop ; continue till sector full call wthdc ; wait for format jp finish ; finish up setup: call select ; select the disk jp z,fatal ; exit if drive not ready ld l,(ix+pdrdma) ; get dma address ld h,(ix+pdrdma+1) ld (dmaptr),hl ; save into local storage ld l,(ix+pdrtrk) ; get and send track number ld h,(ix+pdrtrk+1) ld a,l out (cyllo),a ld a,h out (cylhi),a ld a,(ix+pdrsc) ; get sector count ld (seccnt),a ld a,(ix+pdrsec) ; get sector number ld (sector),a ; save the sector xor a ; clear a ld (errors),a ; clear all errors ret ; done update: ld hl,sector ; get the current sector inc (hl) ; sector + 1 ld hl,seccnt ; get the sector count dec (hl) ; count - 1 ret select: call dstadr ; set the current physical info ld a,(phydrv) ; get to physical drive and 3 ; mask out physical drive sla a ; shift into proper place for command sla a sla a ld b,a ; save it ld a,(phyinfo) ; get information about drive and 1 shl ecc ; mask ecc bit or b ; merge in ecc ld b,a ; save results ld a,(phyinfo) ; get info bit secbit,a ; test sector size jr nz,..sel ; skip if 256 set 5,b ; set for 512 sectors ..sel: ld a,b ; restore values out (sdh),a ; select the physical drive out (sdh),a ; force it to select call rate ; set the step rate rdysts: in a,(status) ; get the status and rdy ; mask the ready ret ; exit; 0=not ready trnslt: ld a,(sechd) ; get sectors per head ld b,a ; save it in b ld c,0 ; c=head number ld a,(sector) ; get logical sector ..nxthd:cp b ; is sector larger than sector per track jr c,..done ; done if <= to sectrk inc c ; increment head number sub b ; subtract sector from sec per tracks jr ..nxthd ; try again ..done: out (secno),a ; set the physical sector ld a,(hdoffst) ; get the head offset and 0fh ; only up to 16 heads add a,c ; add in offset to heads ld b,a ; save new head value bit 3,a ; is head > 7 ld a,-1 ; preload less than value jr z,..les ; if < 7 skip xor a ; else load > value ..les: out (wpc),a ; send extra head select to controller res 3,b ; reset bit 3 of head bits ..tr512:in a,(sdh) ; get sdh with drive selected and 0f8h ; zero out the head bits or b ; merge in bits out (sdh),a ; send to controller ret retrdy: call select ; select the proper drive call rdysts ; get ready status ret z ; exit if not ready ld a,(phydrv) ; find out if drive initialized yet and 3 ; mask for 4 drives ld c,a ; save in c ld b,0 ; make drive no. 16 bits ld hl,nitflgs ; point to nit flags add hl,bc ld a,(hl) ; get flag for this drive or a ; is it set jr z,..ret ; skip if nit done before ld (hl),0 ; else clear flag call restor ; initialize drive ..ret: call off ; turn off drive ld a,-1 ; preset error code ret ; and leave retdst: in a,(status) ; get status inc a ; test for board presense jp z,exit ; exit if board not present call select ; select the disk push af ; no exit until turbo has a dst packet call dstadr ; get the dst table for this drive ld (ix+pdrdst),l ; save for return ld (ix+pdrdst+1),h pop af ; restore the status ret dstadr: ld a,(ix+pdrdrv) ; get requested drive sla a ; multiply *2 sla a ; multiply *4 sla a ; multiply *8 sla a ; multiply *16 ld hl,hdtbla## ; get base address of dst tables ld e,a ; make offset 16 bit ld d,0 add hl,de ; and put together push hl ; save hdcdst base ld de,11 ; point to physical information tables add hl,de ; add in offset ld de,phyinfo ; point to table ld bc,4 ldir pop hl ; restore base address ret restor: ld a,crest+3 ; restore slow out (comnd),a ; tell controller call wthdc ; wait until done rate: ld a,(phyinfo) ; get step rate and 0fh ; mask off junk or cseek ; set step rate out (comnd),a ; and fall through to wait until done wthdc: ld a,(phyinfo) ; get sector size bit secbit,a ; test for dma call nz,dmafix ; call the delay if 256 sectors ld de,hdcpoll ; get poll routine address call lnkpol## ; create poll routinue call hdcpr ; execute poll routine ld hl,hdcsph ; get semaphore call wait## ; dispatch if necessary in a,(status) ; get status and errs ; mask ld hl,errors ; point to errors or m ; combine errors ld (hl),a ; save errors ret ; done hdcpoll:dw 0 ; poll routine linkage dw 0 hdcpr: in a,(status) ; get drive status bit bsy,a ; controller busy? ret nz ; if so, done bit seek,a ; seeks complete? ret z ; if so, done ld hl,hdcpoll ; else, get poll routine address call unlink## ; unlink poll routine ld hl,hdcsph ; get semaphore jp signal## ; signal process as ready dmafix: ld b,28 ; wait 200 us ..dma: ex (sp),hl ; delay ex (sp),hl ; delay djnz ..dma ; tight loop ret ; can you think of a better way? beep: call dms## ; send character to local console db 7,7+80h ; beeeep! ret off: push af ; don't effect status in a,(sdh) ; get old setting or 18h out (sdh),a ; force selection out (sdh),a ; again pop af ; restore status ret ; done end ll wait## ; dispatch if necessary in a,(status) ; get status and errs ; mask ld hl,errors ; point to errors or m ; combine errors ld (hl),a ; save errors ret ; done hdcpoll:dw 0 ; poll routine linkage dw 0 hdcpr: in a,(status) ; get drive status bit bsy,a ; controller busy? ret nz ; if so, done bit seek,a ; seeks complete? ret z ; if so, done ld hl,hdcpoll ; else, get poll routine address call unlink## ; unlink poll routine ld hl,hdcsph ; get semaphore jp signal## ; signal process as ready dmafix: ld b,28 ; wait 200 us ..dma: ex (sp),hl ; delay ex (sp),hl ; delay djnz ..dma ; tight loop ret ; can you think of a better way? beep: call dms## ; send character to local c title TURBODOS OPERATING SYSTEM - HDC1001 HARD DISK DRIVER subttl Written by Kevin Aguilar for Advanced Digital 6/23/84 ; DRIVER FOR A 2ND HDC BOARD IN TURBODOS USE THIS WHEN MATING SA1004 TYPE ; DRIVES WITH ST506 TYPE OR WHEN YOU NEED MORE THAN 4 DRIVES .z80 ; z80 code implemented name ('HRDISK') ; module id include DREQUATE.LIB ; o/s symbolic equates ;*** port equates for hdc1001 *** hdcbase equ 0d0h ; base of hdc1001 hdcdata equ hdcbase ; data port wpc equ hdcbase+1 ; write precomp port secnt equ hdcbase+2 ; sector count secno equ hdcbase+3 ; sector number cyllo equ hdcbase+4 ; cylinder low cylhi equ hdcbase+5 ; cylinder high sdh equ hdcbase+6 ; size/drive/head comnd equ hdcbase+7 ; command register hdcerr equ wpc ; error port status equ comnd ; status register ;*** command equates for hdc1001 *** crest equ 10h ; restore command cread equ 20h ; read command cwrite equ 30h ; write command cform equ 50h ; format track cseek equ 70h ; seek command ;*** status and error bits secbit equ 6 ; sector size ecc equ 7 ; ecc bit flag bsy equ 7 ; hard disk busy bit seek equ 4 ; seek complete bit errs equ 1 ; hard disk errors mask rdy equ 64 ; hard disk ready mask dseg ; data stuff dmxsph: ; mutual exclusion semaphore dw 1 ; semaphore count ..dmxh: dw ..dmxh ; semaphore p/d head dw ..dmxh hdcsph: ; hdc semaphore dw 0 ; semaphore count ..hdch: dw ..hdch ; semaphore p/d head dw ..hdch stksav: dw 0 ; stack save dmaptr: dw 0 ; temporary dma pointer storage errors: db 0 ; error save area sector: db 0 ; temporary sector storage seccnt: db 0 ; temporary sector count storage scrtch: db 0 ; scratch pad phyinfo:db 0 ; physical info hdoffst:db 0 ; head offset for current drive phydrv: db 0 ; current physical drive sechd: db 0 ; sectors per head nitflgs:db -1,-1,-1,-1 ; drive initialization flags cseg ; code stuff dskdr@::ld hl,dmxsph ; get mutual exclusion semaphore call wait## ; dispatch if necessary call ..dd ; call disk driver push af ; save return code ld hl,dmxsph ; get mutual exclusion semaphore call signal## ; signal process as ready pop af ; restore return code ret ; done ..dd: ld (stksav),sp ; save the stack ld a,(ix+pdrfcn) ; get pd req function number or a ; pd req function number=0? jp z,read ; if so, continue dec a ; pd req function number=1? jp z,write ; if so, continue dec a ; pd req function number=2? jp z,retdst ; if so, continue dec a ; pd req function number=3? jp z,retrdy ; if so, continue dec a ; pd req function number=4? jp z,format ; if so, continue ret ; else, done read: call setup ; select disk and initialize pointers ..reads:call trnslt ; translat sector to heads ld a,cread ; send read command out (comnd),a ; send command to controller call wthdc ; wait until done ld bc,hdcdata ; set up port address ld hl,(dmaptr) ; get dma address inir ; get data bit 0,(ix+secsiz) ; 512 byte sectors jr nz,..rd256 ; skip if not inir ; else get more data ..rd256:ld (dmaptr),hl ; save dma address call update ; update pointers jr nz,..reads ; get next sector jp finish ; finish up write: call setup ; initialize pointers ..wrts: call trnslt ; translat sector to heads ld a,cwrite ; send write command out (comnd),a ld bc,hdcdata ; set up port address ld hl,(dmaptr) ; get dma address otir ; send data bit 0,(ix+secsiz) ; 512 byte sectors jr nz,..wr256 ; skip if not otir ; else get more data ..wr256:ld (dmaptr),hl ; save dma address call wthdc ; wait until done call update ; update pointers jr nz,..wrts ; get next sector verify: call setup ; select disk and initialize pointers ..vfys: call trnslt ; translat sector to heads ld a,cread ; send read command out (comnd),a ; tell the controller call wthdc ; wait until done in a,(status) ; get status and 5  ; check the corrected bit and error bit call nz,beep ; jump if bad verify call update ; update pointers jr nz,..vfys ; get next sector finish: ld a,(errors) ; get accumulated errors or a ; set flags jr z,exit ; exit fatal: xor -1 ; preset to ff exit: call off ; turn off drive ld sp,(stksav) ; get the stack back ret ; exit to TuRboDoS format: call retrdy ; initialize drive call setup ; select disk and setup pointers call trnslt ; translat sector to head # ld hl,(dmaptr) ; set hl to dma address ld a,(seccnt) ; get sector count out (secnt),a ; send to hdc xor a ; zero a out (secno),a ; reset the sector to 0 ld a,cform ; issue format command out (comnd),a ld bc,hdcdata ; load bc with port addr & count ld a,(phyinfo) ; get phyinfo bit secbit,a ; 512 byte sectors jr z,..fmt256 ; skip if so set 7,b ; else set b = 80h for 256 byte sectors ..fmt256:xor a ; zero a ..loop: out (c),a ; send bad block byte outi ; send interleave byte jr nz,..loop ; continue till sector full call wthdc ; wait for format jp finish ; finish up setup: call select ; select the disk jp z,fatal ; exit if drive not ready ld l,(ix+pdrdma) ; get dma address ld h,(ix+pdrdma+1) ld (dmaptr),hl ; save into local storage ld l,(ix+pdrtrk) ; get and send track number ld h,(ix+pdrtrk+1) ld a,l out (cyllo),a ld a,h out (cylhi),a ld a,(ix+pdrsc) ; get sector count ld (seccnt),a ld a,(ix+pdrsec) ; get sector number ld (sector),a ; save the sector xor a ; clear a ld (errors),a ; clear all errors ret ; done update: ld hl,sector ; get the current sector inc (hl) ; sector + 1 ld hl,seccnt ; get the sector count dec (hl) ; count - 1 ret select: call dstadr ; set the current physical info ld hl,scrtch ; point to scratch pad ld a,(phydrv) ; get to physical drive and 3 ; mask out physical drive sla a ; shift into proper place for command sla a sla a ld (hl),a ; save it ld a,(phyinfo) ; get information about drive and 1 shl ecc ; mask out ecc or (hl) ; or in value ld a,(phyinfo) ; get info bit 6,a ; test sector size jr nz,..sel ; skip if 256 set 5,(hl) ; set for 512 sectors ..sel: ld a,(hl) ; restore values out (sdh),a ; select the physical drive out (sdh),a ; force it to select call rate ; set the step rate rdysts: in a,(status) ; get the status and rdy ; mask the ready ret ; exit; 0=not ready trnslt: ld a,(sechd) ; get sectors per head ld b,a ; save it in b ld c,0 ; c=head number ld a,(sector) ; get logical sector ..nxthd:cp b ; is sector larger than sector per track jr c,..done ; done if <= to sectrk inc c ; increment head number sub b ; subtract sector from sec per tracks jr ..nxthd ; try again ..done: out (secno),a ; set the physical sector ld a,(hdoffst) ; get the head offset and 0fh ; only up to 16 heads add a,c ; add in offset to heads ld b,a ; save new head value bit 3,a ; is head > 7 ld a,-1 ; preload less than value jr z,..les ; if < 7 skip xor a ; else load > value ..les: out (wpc),a ; send extra head select to controller res 3,b ; reset bit 3 of head bits ..tr512:in a,(sdh) ; get sdh with drive selected and 0f8h ; zero out the head bits or b ; merge in bits out (sdh),a ; send to controller ret retrdy: call select ; select the proper drive ld a,(phydrv) ; find out if drive initialized yet and 3 ; mask for 4 drives ld c,a ; save in c ld b,0 ; make drive no. 16 bits ld hl,nitflgs ; point to nit flags add hl,bc ld a,(hl) ; get flag for this drive or a ; is it set jr z,..ret ; skip if nit done before ld (hl),0 ; else clear flag call restor ; initialize drive ..ret: call rdysts ; get ready status call off ; turn off drive ret z ; exit if not ready ld a,-1 ; preset error code ret ; and leave retdst: in a,(status) ; get status inc a ; test for board presense jp z,exit ; exit if board not present call select ; select the disk push af ; no exit until turbo has a dst packet call dstadr ; get the dst table for this drive ld (ix+pdrdst),l ; save for return ld (ix+pdrdst+1),h pop af ; restore the status ret dstadr: ld a,(ix+pdrdrv) ; get requested drive sla a ; multiply *2 sla a ; multiply *4 sla a ; multiply *8 sla a ; multiply *16 ld hl,hdtblb## ; get base address of dst tables ld e,a ; make offset 16 bit ld d,0 add hl,de ; and put together push hl ; save hdcdst base ld de,11 ; point to physical information tables add hl,de ; add in offset ld de,phyinfo ; point to table ld bc,4 ldir pop hl ; restore base address ret restor: ld a,crest+3 ; restore slow out (comnd),a ; tell controller call wthdc ; wait until done rate: ld a,(phyinfo) ; get step rate and 0fh ; mask off junk or cseek ; set step rate out (comnd),a ; and fall through to wait until done wthdc: ld a,(phyinfo) ; get sector size bit secbit,a ; test for dma call nz,dmafix ; call the delay if 256 sectors ld de,hdcpoll ; get poll routine address call lnkpol## ; create poll routinue call hdcpr ; execute poll routine ld hl,hdcsph ; get semaphore call wait## ; dispatch if necessary in a,(status) ; get status and errs ; mask ld hl,errors ; point to errors or m ; combine errors ld (hl),a ; save errors ret ; done hdcpoll:dw 0 ; poll routine linkage dw 0 hdcpr: in a,(status) ; get drive status bit bsy,a ; controller busy? ret nz ; if so, done bit seek,a ; seeks complete? ret z ; if so, done ld hl,hdcpoll ; else, get poll routine address call unlink## ; unlink poll routine ld hl,hdcsph ; get semaphore jp signal## ; signal process as ready dmafix: ld b,28 ; wait 200 us ..dma: ex (sp),hl ex (sp),hl ; djnz ..dma ret ; can you think of a better way? beep: call dms## ; send character to local console db 7,7+80h ; beeeep! ret off: push af ; don't effect status in a,(sdh) ; get old setting or 18h out (sdh),a ; force selection out (sdh),a ; again pop af ; restore status ret ; done end d hl,hdcsph ; get semaphore call wait## ; dispatch if necessary in a,(status) ; get status and errs ; mask ld hl,errors ; point to errors or m ; combine errors ld (hl),a ; save errors ret ; done hdcpoll:dw 0 ; poll routine linkage dw 0 hdcpr: in a,(status) ; get drive status bit bsy,a ; controller busy? ret nz ; if so, done bit seek,a ; seeks complete? ret z ; if so, done ld hl,hdcpoll ; else, get poll routine address call unlink## ; unlink poll routine ld hl,hdcsph ; get semaphore jp signal## ; signal process as ready dmafix: ld b,28 ; wait 200 us ..dma: ex (sp),hl ex (sp),hl ; djnz ..dma ret ; can you think of a better way? beep: call dms## ; send character to locatitle hard disk header name ('hdtbls') public hdtbl@ dseg hdtbl@ equ $ ;header for turbo to sync on end or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db ((dirs Title TURBODOS boot loader - HDC1001 HARD DISK DRIVER subttl Written by Kevin Aguilar for Advanced Digital 8/27/84 .z80 ; z80 code implemented name ('boothd') ; module id include DREQUATE.LIB ; o/s symbolic equates ;*** port equates for hdc1001 *** hdcbase equ 0e0h ; base of hdc1001 hdcdata equ hdcbase ; data port wpc equ hdcbase+1 ; write precomp port secnt equ hdcbase+2 ; sector count secno equ hdcbase+3 ; sector number cyllo equ hdcbase+4 ; cylinder low cylhi equ hdcbase+5 ; cylinder high sdh equ hdcbase+6 ; size/drive/head comnd equ hdcbase+7 ; command register hdcerr equ wpc ; error port status equ comnd ; status register cr equ 0dh lf equ 0ah eol equ 80h ;*** command equates for hdc1001 *** crest equ 10h ; restore command cread equ 20h ; read command cwrite equ 30h ; write command cform equ 50h ; format track cseek equ 70h ; seek command ;*** status and error bits secbit equ 6 ; sector size ecc equ 7 ; ecc bit flag bsy equ 7 ; hard disk busy bit seek equ 4 ; seek complete bit errs equ 1 ; hard disk errors mask rdy equ 64 ; hard disk ready mask dseg ; data stuff stksav: dw 0 ; stack save dmaptr: dw 0 ; dma pointer storage sector: db 0 ; sector storage head: db 0 ; head number drive: db 0 ; current logical drive phyinfo:db 0 ; physical info hdoffst:db 0 ; head offset for current drive phydrv: db 0 ; current physical drive sechd: db 0 ; sectors per head cseg ; code stuff nithdc::ret ; none implemented selhdc::ld (drive),a ; save drive number call seldsk ; select the disk ret z ; exit if not ready call restore ; restore and set the step rate ld a,0 ; preset error code ret nz ; exit if errors call dstadr ; get table base in hl xor -1 ; a=ff ret ; done seldsk: call dstadr ; set the current physical info ld a,(phydrv) ; get to physical drive and 3 ; mask out physical drive sla a ; shift into proper place for command sla a sla a ld b,a ; save it ld a,(phyinfo) ; get information about drive and 1 shl ecc ; mask out ecc or b ; or in value ld a,(phyinfo) ; get info bit 6,a ; test sector size jr nz,..sel ; skip if 256 set 5,b ; set for 512 sectors ..sel: ld a,b ; restore values out (sdh),a ; select the physical drive out (sdh),a ; force it to select rdysts: in a,(status) ; get the status and rdy ; mask the ready ret nz ; return if ready call dms## db cr,lf,7 dc 'Drive is not ready' jp fatal rdhdc:: ld a,b ; get track number out (cylhi),a ; set high order ld a,c ; get track number out (cyllo),a ; set low order ld a,e ; get requested sector number ld (sector),a ; set sector number ld (dmaptr),hl ; set dma address call seldsk ; select requested drive call trnslt ; translat sector to heads ld a,cread ; send read command out (comnd),a ; send command to controller call wait ; wait until done jr nz,fatal ; exit if errors ld bc,hdcdata ; set up port address ld hl,(dmaptr) ; get dma address inir ; get data ld a,(phyinfo) ; get info bit 6,a ; test sector size jr nz,..rd256 ; skip if 256 inir ; else get more data ..rd256:ld (dmaptr),hl ; save dma address xor a ; a = 0 jr exit ; good, exit exit: call off ; turn off drive ret ; exit to TuRboDoS fatal: call dms## db cr,lf,7+eol in a,(hdcerr) ; read errors ld b,a bit 7,b jr z,..nxt call dms## dc 'Bad block: ' ..nxt: bit 6,b jr z,..nxt2 call dms## dc 'Uncorrectable: ' ..nxt2: bit 5,b jr z,..nxt3 call dms## dc 'CRC: ' ..nxt3: bit 4,b jr z,..nxt4 call dms## dc 'ID not found: ' ..nxt4: bit 2,b jr z,..nxt5 call dms## dc 'Aborted command: ' ..nxt5: bit 1,b jr z,..nxt6 call dms## dc 'Track 0: ' ..nxt6: bit 0,b jr z,..err call dms## dc 'DAM not found: ' ..err: call dms## dc 'Error/s reading Track: ' in a,(cylhi) ld h,a in a,(cyllo) ld l,a call hldec## call dms## dc ' Sector: ' ld h,0 ld a,(sector) ld l,a call hldec## call dms## dc ' Head: ' ld h,0 ld a,(head) ld l,a call hldec## call dms## db cr,lf db 'Aborting back to the Monitor' db cr,lf+eol call errors## ret trnslt: ld a,(sechd) ; get sectors per head ld b,a ; save it in b ld c,0 ; c=head number ld a,(sector) ; get logical sector ..nxthd:cp b ; is sector larger than sector per track jr c,..done ; done if <= to sectrk inc c ; increment head number sub b ; subtract sector from sec per tracks jr ..nxthd ; try again ..done: out (secno),a ; set the physical sector ld a,(hdoffst) ; get the head offset and 0fh ; only up to 16 heads add a,c ; add in offset to heads ld (head),a ; save head for error message ld b,a ; save new head value bit 3,a ; is head > 7 ld a,-1 ; preload less than value jr z,..les ; if < 7 skip xor a ; else load > value ..les: out (wpc),a ; send extra head select to controller res 3,b ; reset bit 3 of head bits ..tr512:in a,(sdh) ; get sdh with drive selected and 0f8h ; zero out the head bits or b ; merge in bits out (sdh),a ; send to controller ret dstadr: ld a,(drive) ; get requested drive sla a ; multiply *2 sla a ; multiply *4 sla a ; multiply *8 sla a ; multiply *16 ld hl,hdtbla## ; get base address of dst tables ld e,a ; make offset 16 bit ld d,0 add hl,de ; and put together push hl ; save hdcdst base ld de,11 ; point to physical information tables add hl,de ; add in offset ld de,phyinfo ; point to table ld bc,4 ldir pop hl ; restore base address ret restore:ld a,crest+3 ; restore slow out (comnd),a ; tell controller call wait ; wait until done rate: ld a,(phyinfo) ; get step rate and 0fh ; mask off junk or cseek ; set step rate out (comnd),a ; and fall through to wait until done wait: ld a,(phyinfo) ; get sector size bit secbit,a ; test for dma call nz,dmafix ; call the delay if 256 sectors ..bsy: in a,(status) ; get drive status bit bsy,a ; controller busy? jr nz,..bsy ; if so, wait bit seek,a ; seeks complete? jr z,..bsy ; if so, wait in a,(status) ; get status and errs ; mask jp nz,fatal ; exit if errors ret ; done dmafix: ld b,28 ; wait 200 us ..dma: ex (sp),hl ; delay ex (sp),hl ; delay djnz ..dma ; tight loop ret ; can you think of a better way? off: push af ; don't effect status in a,(sdh) ; get old setting or 18h out (sdh),a ; force selection out (sdh),a ; again pop af ; restore status ret ; done end dress ret restore:ld a,crest+3 ; restore slow out (comnd),a ; tell controller call wait ; wait until done rate: ld a,(phyinfo) ; get step rate and 0fh ; mask off junk or cseek ; set step rate out (comnd),a ; and fall through to wait until done wait: ld a,(phyinfo) ; get sector size bit secbit,a ; test for dma call nz,dmafix ; call the delaytitle Hard disk specification table subttl Advanced Digital 7/3/84 name ('MAX105') ; Module name (6 chars only) tracks equ 918 ; physical tracks heads equ 11 ; physical heads steprt equ 0 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 1024 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 16 ; sectors per track (head) secsiz equ 512 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable dseg ; locate in data segment MAX105@:: ; Global entry point for patching (6 chrs only) ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db ((dirsiz*8)/blksiz)*4 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end title Hard disk specification table subttl Advanced Digital 7/3/84 name ('MAX140') ; Module name (6 chars only) tracks equ 918 ; physical tracks heads equ 15 ; physical heads steprt equ 0 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 1024 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 16 ; sectors per track (head) secsiz equ 512 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable dseg ; locate in data segment MAX140@:: ; Global entry point for patching (6 chrs only) ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db ((dirsiz*8)/blksiz)*4 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end title Hard disk specification table subttl Advanced Digital 7/3/84 name ('MAX65') ; Module name (6 chars only) tracks equ 918 ; physical tracks heads equ 7 ; physical heads steprt equ 0 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 1024 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 16 ; sectors per track (head) secsiz equ 512 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable dseg ; locate in data segment MAX65@:: ; Global entry point for patching (6 chrs only) ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if  bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db ((dirsiz*4)/blksiz)*8 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end title Hard disk specification table subttl Advanced Digital 7/3/84 name ('M1302') ; Module name (6 chars only) tracks equ 830 ; physical tracks heads equ 3 ; physical heads steprt equ 0 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 2048 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 17 ; sectors per track (head) secsiz equ 512 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable dseg ; locate in data segment M1302@:: ; Global entry point for patching (6 chrs only) ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if  bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db 16 ; db ((dirsiz*8)/blksiz)*4 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end title Hard disk specification table subttl Advanced Digital 7/3/84 name ('M1303') ; Module name (6 chars only) tracks equ 830 ; physical tracks heads equ 5 ; physical heads steprt equ 0 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 2048 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 17 ; sectors per track (head) secsiz equ 512 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable dseg ; locate in data segment M1303@:: ; Global entry point for patching (6 chrs only) ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if  bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db 16 ; db ((dirsiz*8)/blksiz)*4 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end title Hard disk specification table subttl Advanced Digital 7/3/84 name ('M1304') ; Module name (6 chars only) tracks equ 830 ; physical tracks heads equ 6 ; physical heads steprt equ 0 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 2048 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 17 ; sectors per track (head) secsiz equ 512 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable dseg ; locate in data segment M1304@:: ; Global entry point for patching (6 chrs only) ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if  bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db ((dirsiz*4)/blksiz)*8 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end title Hard disk specification table subttl Advanced Digital 7/3/84 name ('MS3425') ; Module name (6 chars only) tracks equ 612 ; physical tracks heads equ 4 ; physical heads steprt equ 0 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 2048 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 17 ; sectors per track (head) secsiz equ 512 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable dseg ; locate in data segment M3425@:: ; Global entry point for patching (6 chrs only) ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db ((dirsiz*4)/blksiz)*8 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end .z80 title park utility include EQUATE.LIB name ('PARKIT') ;bit equates rdymsk equ 6 ;drive ready bit busy equ 7 ;controller busy bit CSEG start: ld a,(tfcb) ; get default fcb drive or a jp nz,..ok ; jump if drive specified call dms ; display message db cr,lf,lf,bel dc 'No drive specified' jp wboot ;continue ..ok: dec a ; make base 0 ld (pdrdrv),a ; save drive number ld c,43 ; are we in bank 1 ? ld e,-1 call opsyst cp 0 jr z,getdrv ; get drive information call dms db cr,lf,bel dc 'To park the drive you must be attached to the master and on bank 0' jp wboot ; cannot execute from bank 1 getdrv: ld a,2 ld (pdrfcn),a ; get dst info ld de,pdrdp ld c,pdafcn call opsyst ; call turbo ld hl,(trkdsk) ; get max track value ld (pdrtrk),hl ; set max drive ld a,0 ld (pdrfcn),a ld de,pdrdp ld c,pdafcn call opsyst ; effectivly seek to maximum track call dms db cr,lf dc 'Drive is now parked' jp wboot ; done dms: ex (sp),hl ;get message address call msghl ;display message ex (sp),hl ;set up return address ret ;done msghl: push af ;save af ..l: ld a,(hl) ;get message byte inc hl ;increment pointer call conout ;display character or a ;last character? jp p,..l ;if not, continue pop af ;else, restore af ret ;done conout: push bc ;save registers push de push hl push af and 7fh ;strip sign bit from character ld e,a ;output character to e-reg ld c,rcofcn ;c=raw console output function call opsysc ;output character to console pop af ;restore registers pop hl pop de pop bc ret ;done DSEG pdrdp: ;pd request packet pdrfcn: db 0 ;pd request function pdrdrv: db 0 ;pd request drive number pdrtrk: dw 0 ;pd request track number pdrsec: dw 1 ;pd request sector number pdrsc: dw 1 ;pd request sector count pdrtc: dw 1 ;pd request transfer count pdrdma: dw dstpkt ;pd request dma address pdrdst: dw dstp kt ;pd request dst address dstpkt: ;dst area blksiz: db 0 ;block size nmblks: dw 0 ;number of allocation blocks nmbdir: db 0 ;number of directory blocks secsiz: db 0 ;sector size sectrak:dw 0 ;sectors/track trkdsk: dw 50 ;tracks/disk restrk: dw 0 ;reserved tracks end  ;save registers push de push hl push af and 7fh ;strip sign bit from character ld e,a ;output character to e-reg ld c,rcofcn ;c=raw console output function call opsysc ;output character to console pop af ;restore registers pop hl pop de pop bc ret ;done DSEG pdrdp: ;pd request packet pdrfcn: db 0 ;pd request function pdrdrv: db 0 ;pd request drive number pdrtrk: dw 0 ;pd request track number pdrsec: dw 1 ;pd request sector number pdrsc: dw 1 ;pd request sector count pdrtc: dw 1 ;pd request transfer count pdrdma: dw dstpkt ;pd request dma address pdrdst: dw dstptitle Hard disk specification table subttl Advanced Digital 7/3/84 name ('Q2010') ; Module name (6 chars only) tracks equ 512 ; physical tracks heads equ 2 ; physical heads steprt equ 0 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 1024 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 16 ; sectors per track (head) secsiz equ 512 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable dseg ; locate in data segment Q2010@:: ; Global entry point for patching (6 chrs only) ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if  bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db ((dirsiz*8)/blksiz)*4 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end title Hard disk specification table subttl Advanced Digital 7/3/84 name ('Q2020') ; Module name (6 chars only) tracks equ 512 ; physical tracks heads equ 4 ; physical heads steprt equ 0 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 1024 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 16 ; sectors per track (head) secsiz equ 512 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable dseg ; locate in data segment Q2020@:: ; Global entry point for patching (6 chrs only) ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if  bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db ((dirsiz*8)/blksiz)*4 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end title Hard disk specification table subttl Advanced Digital 7/3/84 name ('Q2030') ; Module name (6 chars only) tracks equ 512 ; physical tracks heads equ 6 ; physical heads steprt equ 0 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 1024 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 16 ; sectors per track (head) secsiz equ 512 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable dseg ; locate in data segment Q2030@:: ; Global entry point for patching (6 chrs only) ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if  bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db ((dirsiz*8)/blksiz)*4 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end  title Hard disk specification table subttl Advanced Digital 7/3/84 name ('Q2040') ; Module name (6 chars only) tracks equ 512 ; physical tracks heads equ 8 ; physical heads steprt equ 0 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 1024 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 16 ; sectors per track (head) secsiz equ 512 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable dseg ; locate in data segment Q2040@:: ; Global entry point for patching (6 chrs only) ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if  bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db ((dirsiz*8)/blksiz)*4 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end Th har dis drive supplie wit you Turbodo no ha patchabl har dis tabl wit enoug bell an whistle t kee yo guy happ fo quit awhil. T mak you ow table fo drives jus edi th dsktbl.ma fil o premad dis tabl an g dow th lis an chang i t you preferances. Use these patch points to modify your driver at the time of genning if you like. drivename equ name of drive currently using drivename+0 ; block size drivename+1 ; number of blocks drivename+3 ; directory blocks drivename+4 ; sector size drivename+5 ; sectors per cylinder drivename+7 ; tracks per disk drivename+9 ; track offset drivename+0b ; drive type drivename+0c ; head offset drivename+0d ; physical drive number drivename+0e ; physical sectors per track physical sectors per track end title turbodos track 0 boot loader (advanced digital super six) ; Written by Kevin Aguilar for advanced digital 8/28/84 name ('Main') ; module id public ram ram equ 40h ; ram address for osboot to use cr equ 0dh ; return lf equ 0ah ; line feed eol equ 80h ; end of line tpa equ 100h ; transient program area tbuf equ 80h ; default disk buffer area sioadr equ 00h ; sio port a data register sioacr equ 01h ; sio port a control register siobdr equ 02h ; sio port b data register tssojr equ 15h ; option jumpers and two sided status register extadr equ 15h ; extended address register memcr1 equ 16h ; memory control register #1 memcr2 equ 17h ; memory control register #2 .z80 ; produce z80 code dseg prompt::ds 80,80h ; prompt message load:: dw tpa ; address to load file cseg ; locate in program area begin:: xor a ; clear a out (extadr),a ; set extended address to bank 0 ld hl,prompt ; prompt message call dmshl ; print message jp osboot## ; jump to rest of boot program init:: ld hl,(load) ; get address to load ret ; done select::jp selhdc## ; continue read:: jp rdhdc## ; read hard disk xfer:: xor a ; clear a ld (80h),a ; clear the command table ld hl,(load) ; get address to jump to jp (hl) ; transfer to loader dms:: ex (sp),hl ;get message address call dmshl ;display message ex (sp),hl ;set up return address ret ;done dmshl:: push af ;save af ..next: ld a,(hl) ;get message byte inc hl ;increment pointer call conout ;display character bit 7,a ;last character? jr z,..next ;if not, continue pop af ;else, restore af ret ;done hldec:: push af ;SAVE REGISTERS push bc push de push hl ld b,0 ;CLEAR LEADING ZERO FLAG ld de,10000 ;DISPLAY TEN THOUSANDS DIGIT call ..do ld de,1000 ;DISPLAY THOUSANDS DIGIT call ..do ld de,100 ;DISPLAY HUNDREDS DIGIT call ..do ld de,10 ;DISPLAY TENS DIGIT call ..do inc b ;INCREMENT LEADING ZERO FLAG ld de,1 ;DISPLAY UNITS DIGIT call ..do pop hl ;RESTORE REGISTERS pop de pop bc pop af ret ;DONE ..do: ld c,-1 ;PRESET QUOTENT or a ;CLEAR CARRY FLAG ..dl: inc c ;INCREMENT QUOTENT sbc hl,de ;SUBTRACT DIVISOR jr nc,..dl ;UNTIL UNDERFLOW add hl,de ;RESTORE UNDERFLOW ld a,c ;GET QUOTENT or a ;QUOTENT=0? jr nz,..dd ;IF NOT, DISPLAY DIGIT inc b dec b ;LEADING ZERO FLAG SET? ret z ;IF NOT, DONE ..dd: add a,"0" ;ADD ASCII BIAS call conout ;OUTPUT CHARACTER inc b ;INCREMENT LEADING ZERO FLAG ret ;DONE ; hlhex:: push af ;SAVE AF-REG ld a,h ;GET MSB OF VALUE call ..hexo ;DISPLAY MSB IN HEX ld a,l ;GET LSB OF VALUE call ..hexo ;DISPLAY LSB IN HEX pop af ;RESTORE AF-REG ret ;DONE ..hexo: push af ;SAVE VALUE rrca ;SHIFT MSN TO LSN rrca rrca rrca call ..hexn ;DISPLAY MSN IN HEX pop af ;RESTORE VALUE call ..hexn ;DISPLAY LSN IN HEX ret ;DONE ..hexn: and 0fh ;EXTRACT NIBBLE add a,"0" ;ADD ASCII BIAS cp "9"+1 ;VALID HEX DIGIT? jr c,..hexd ;IF SO, CONTINUE add a,"A"-("9"+1) ;ELSE, ADD LETTER BIAS ..hexd: call conout ;OUTPUT CHARACTER ret ;DONE conout: push af ;save character ..wait: in a,(sioacr) ;get status bit 2,a ;test tbe jr z,..wait ;wait for ready pop af ;get data out (sioadr),a ;print character ret end ERO FLAG SET? ret z ;IF NOT, DONE ..dd: add a,"0" ;ADD ASCII BIAS call conout ;OUTPUT CHARACTER inc b ;INCREMENT LEADING ZERO FLAG ret ;DONE ; hlhex:: push af ;SAVE AF-REG ld a,h ;GET MSB OF VALUE call ..hexo ;DISPLAY MSB IN HEX ld a,l ;GET LSB OF VALUE call ..hexo ;DISPLAY LSB IN HEX pop af ;RESTORE AF-REG ret ;DONE ..hexo: push af ;SAVE VALUE rrca ;SHIFT MSN TO LSN rrca rrca rrca call ..hexn ;DISPLAY MSN IN HEX pop af ;RESTORE VALUE call ..hexn ;DISPLAY LSN IN HEX ret ;DONE ..hexn: and 0fh ;EXTRACT NIBBLE add a,"0" ;ADD ASCII BIAS cp "9"+1 ;VALID HEX DIGIT? jr title Hard disk specification table subttl Advanced Digital 7/3/84 name ('S1002') ; Module name (6 chars only) tracks equ 256 ; physical tracks heads equ 2 ; physical heads steprt equ 0 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 1024 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 16 ; sectors per track (head) secsiz equ 512 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable dseg ; locate in data segment S1002@:: ; Global entry point for patching (6 chrs only) ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if  bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db ((dirsiz*8)/blksiz)*4 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end title Hard disk specification table subttl Advanced Digital 7/3/84 name ('S1004') ; Module name (6 chars only) tracks equ 256 ; physical tracks heads equ 4 ; physical heads steprt equ 0 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 1024 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 16 ; sectors per track (head) secsiz equ 512 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable dseg ; locate in data segment S1004@:: ; Global entry point for patching (6 chrs only) ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if  bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db ((dirsiz*8)/blksiz)*4 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end  name ('SA604') tracks equ 160 ; physical tracks heads equ 4 ; physical heads steprt equ 6 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 1024 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 16 ; sectors per track (head) secsiz equ 512 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro dseg SA604@:: setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size dw ((sectrk*heads)*(tracks-trkoff))/(blksiz/secsiz) ; blocks db ((dirsiz*32)/blksiz) ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end o to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro dseg SA604@:: setparm blksiz ; determine blotitle Hard disk specification table subttl Advanced Digital 7/3/84 name ('ST412') ; Module name (6 chars only) tracks equ 306 ; physical tracks heads equ 4 ; physical heads steprt equ 0 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 2048 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 17 ; sectors per track (head) secsiz equ 512 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable dseg ; locate in data segment ST419@:: ; Global entry point for patching (6 chrs only) ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if  bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db ((dirsiz*4)/blksiz)*8 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end  title Hard disk specification table subttl Advanced Digital 7/3/84 name ('ST419') ; Module name (6 chars only) tracks equ 306 ; physical tracks heads equ 6 ; physical heads steprt equ 0 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 1024 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 16 ; sectors per track (head) secsiz equ 512 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable dseg ; locate in data segment ST419@:: ; Global entry point for patching (6 chrs only) ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if  bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db ((dirsiz*8)/blksiz)*4 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end title Hard disk specification table subttl Advanced Digital 7/3/84 name ('ST425') ; Module name (6 chars only) tracks equ 306 ; physical tracks heads equ 8 ; physical heads steprt equ 0 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 2048 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 17 ; sectors per track (head) secsiz equ 512 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable dseg ; locate in data segment ST425@:: ; Global entry point for patching (6 chrs only) ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if  bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db ((dirsiz*4)/blksiz)*8 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end title Hard disk specification table subttl Advanced Digital 7/3/84 name ('ST506') ; Module name (6 chars only) tracks equ 153 ; physical tracks heads equ 4 ; physical heads steprt equ 6 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 1024 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 16 ; sectors per track (head) secsiz equ 512 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable dseg ; locate in data segment ST506@:: ; Global entry point for patching (6 chrs only) ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if  bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db ((dirsiz*8)/blksiz)*4 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end title Hard disk specification table subttl Advanced Digital 7/3/84 name ('TM501') ; Module name (6 chars only) tracks equ 306 ; physical tracks heads equ 2 ; physical heads steprt equ 0 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 1024 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 16 ; sectors per track (head) secsiz equ 512 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable dseg ; locate in data segment TM501@:: ; Global entry point for patching (6 chrs only) ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if  bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db ((dirsiz*8)/blksiz)*4 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end  title Hard disk specification table subttl Advanced Digital 7/3/84 name ('TM502') ; Module name (6 chars only) tracks equ 306 ; physical tracks heads equ 4 ; physical heads steprt equ 0 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 1024 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 16 ; sectors per track (head) secsiz equ 512 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable dseg ; locate in data segment TM502@:: ; Global entry point for patching (6 chrs only) ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if  bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db ((dirsiz*8)/blksiz)*4 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end title Hard disk specification table subttl Advanced Digital 7/3/84 name ('TM503') ; Module name (6 chars only) tracks equ 306 ; physical tracks heads equ 6 ; physical heads steprt equ 0 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 1024 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 16 ; sectors per track (head) secsiz equ 512 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable dseg ; locate in data segment TM503@:: ; Global entry point for patching (6 chrs only) ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if  bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db ((dirsiz*8)/blksiz)*4 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end  TITLE TURBODOS COLD BOOT LOADER BDOS 1/17/84 doc .z80 ; .PHASE 100H bdossecs equ 44 ;sectors to read on warm boot buffer equ 1400h ; OSLOAD.SYS load area monit equ 0f033h ;return to monitor for error memory equ 16h ;to enable monitor PROM false equ 0 true equ not false devlp equ false ;true for devlopment loader to ask what to load nmbch equ 1 ;number of choices to choose from nmbcpm equ 0 ;number of cp/m choices turbo equ true ;true for turbodos or CP/M 3.0 loader ; loader bios access bios equ 500h conin equ bios+09h conout equ bios+0ch seldsk equ bios+1bh settrk equ bios+1eh setsec equ bios+21h setdma equ bios+24h read equ bios+27h sectran equ bios+30h page start: ld SP,100h ;use default buffer for stack if devlp ques: ld HL,signon ;send which boot mess. call pstrng xor a call conin ;get response push psw ;save input ld C,A ;display it call conout pop psw ;get input back sub '0' ;make number cp nmbch ;make sure valid jr nc,ques ;if not ask again ld (typeld),A ;save type of load ld HL,cpmf ;get address of start of file names ld DE,namlng ;get length of name entry floop: dec a ;add in length jp m,fdone ;skip out if no more to add in add HL,DE ;else add in lingth of entry jr floop ; and go back for more else if turbo ld HL,turbof ;load turbodos loader file name adderss ld A,1 ;force load type ld (typeld),A else ld HL,cpmf ;load cp/m file name xor A ;force load type ld (typeld),A endif endif fdone: ;HL points to beg. of name to load ld DE,filefcb+1 ;destination to move to ld BC,8 ;amount to move ldir ;now move file to load ld C,0 ld E,0 ;make seldsk know this is the first call call seldsk ld A,H or L ld DE,badsel jp z,error ;bad select-HL=0000 ;HL=DPH address ld C,(HL) ;XLT table, low order byte inc HL ld B,(HL) ld A,B or C ;A=0 if no sector translation ld (trans),A ld (XLT),BC ld DE,7 add HL,DE ;(HL)=DIRBUF address - might as well use it ;for our workspace ld C,(HL) inc HL ld B,(HL) ld (dirbuf),BC push HL call setdma ;use the dirbuf for operations pop HL inc HL ;(HL)=DPB address ld E,(HL) inc HL ld D,(HL) page ex DE,HL ;HL=DPB address ld E,(HL) inc HL ld D,(HL) ;(HL)=sectors per track ld (SPT),DE ;highest sector number before next track inc HL ld A,(HL) ;Block shift factor ld (BSH),A inc HL ld A,(HL) ld (BLM),A ;block mask inc A ld (blksec),A ;sectors per block inc HL inc HL inc HL ld A,(HL) ;A=msb of DSM or total block count of drive ld (blkmsb),A inc HL ld E,(HL) inc HL ld D,(HL) inc DE ;make = max dirs. not -1 ld (maxdir),DE ld DE,5 add HL,DE ;(HL)=track offset ld C,(HL) inc HL ld B,(HL) ld (trkoff),BC ld (curtrk),BC call settrk ;directory starts at first non-system track page ; Current status of program: ; The disk on which the system file resides has been selected ; and the head has been stepped to the first directory track ; Note that the directory will always start at sector 1 of ; the first non-system track, and will occupy consecutive ; sectors through the end of the directory. The total number ; of sectors occupied is (maxdir)/4, but they may be on more ; than one track. ; nextsec: ;read next directory sector into the DIRBUF ld HL,(SPT) ld BC,(cursec) sbc HL,BC jr nc,trksame ;haven't gone to next track yet ld BC,(curtrk) inc BC ld (curtrk),BC call settrk ;step disk ld BC,0 ;first sector, new track trksame: push BC ;logical sector ld A,(trans) or A jr z,notran ;do we need to do sector translation? ld DE,(XLT) ;translate table call sectran push HL pop BC notran: call setsec call read or A ld DE,permerr jp nz,error ;physical error pop HL ;sector just read inc HL ld (cursec),HL ; ; The next sector of the directory (4 entries) is now in the DIRBUF ; Now see if we can find the file ; ld HL,(dirbuf) ld DE,32d ld B,4 nextdir: push HL push DE push BC call match ;match directory entry with FCB pop BC pop DE pop HL jr z,found ;file found add HL,DE djnz nextdir ; ; we've search this sector-no match. Was it the last? ; ld HL,(absec) inc HL ld (absec),HL dec HL ;HL=sectors read so far add HL,HL add HL,HL ;sectors x 4 = directory entries ld DE,(maxdir) sbc HL,DE ld DE,nofile jp z,error jr nextsec page ; ; Match: match takes as a parameter HL pointing to a directory ; entry. Match returns the zero flag set if the file matches. ; match: ex DE,HL ;use DE to point to directory ld HL,Filefcb ;first character in filename to search ld BC,0c0dh ;11 characters to match nextch: ld A,(DE) ;next character in directory entry inc DE and 7fh ;mask file attribute bits cpi ret nz ;no match, return djnz nextch ret page ; ; Now we have the correct directory entry, with HL pointing to ; the the start of the FCB ; Next we expand the block allocation data into a table of items: ; ; dw track, dw first sector, dw last sector found: ld DE,15d add HL,DE ;(HL)=records in this extent ld DE,filefcb+15d ;DE=block allocation area in filefcb ld BC,17d ldir ;move to file fcb ld IY,filefcb+16 ;pointer to next block ld IX,boottbl ;pointer to current table entry call getblk ;returns block # in DE newtbl: push DE call mktrk ;returns track in BC, 1st sector in HL ld (IX),C ld (IX+1),B ;store track ld (IX+2),L ;first sector ld (IX+3),H dec HL ;set up for add mrebks1: ld DE,(blksec) add HL,DE ;HL=last sector of block ld DE,(spt) dec DE ;sectors numbered 0-(spt-1) sbc HL,DE jr c,skp jr nz,newtrk ;block overflows to next track skp: add HL,DE ;add sectors per track back in ld (IX+4),L ;save last sector ld (IX+5),H nxtblk: call getblk ;get next block # pop HL ;last block scf ccf sbc HL,DE inc HL ;HL=0 if new block adjacent to last ld A,H or L jr z,moreblks ld BC,6 add IX,BC ;set pointer to next track item jr newtbl newtrk: ld (IX+4),E ;spt-1 last sector on track ld (IX+5),D ld BC,6 add IX,BC ;pointer to next track dec HL ld (IX+4),L ;last sector of this block ld (IX+5),H xor A ld (IX+3),A ;start sector zero ld (IX+2),A ld C,(IX-6) ld B,(IX-5) ;last track inc BC ld (IX),C ld (IX+1),B jr nxtblk page moreblks: push DE ;save new block # ld L,(IX+4) ;last sector so far ld H,(IX+5) jr mrebks1 ;go do rest of overflow check ; getblk returns the block # (IY) in DE and moves IY to the next ; also, exits loop if block # = 0 getblk: ld E,(IY) ld A,(blkmsb) or A jr z,onebyte inc IY ld A,(IY) onebyte: ld D,A inc IY or E ;block # = 0? ret nz pop DE ;lose return in loop jr tbldone ; mktrk gets block # in DE, returns track in BC, 1st sector in HL mktrk: ex DE,HL ld A,(bsh) ld B,A shftblk: add HL,HL djnz shftblk ;HL=absolute sector number ld DE,(spt) scf ccf ld BC,(trkoff) dec BC mortrk: sbc HL,DE inc BC jr nc,mortrk add HL,DE ;restore sector relative in track ret page ; ; table now contains the track/sector map for all the blocks in ; the directory. Now read the table into memory. ; tbldone: ld HL,buffer ;start of CCP-starting DMA ld IY,boottbl-6 ;point to boot table nxttrk: push HL ;current DMA ;read sectors of next track ld DE,6 ;update track pointer add IY,DE ld C,(IY) ld B,(IY+1) ;BC=track ld A,B or C jr z,bootdone ;last track done call settrk ld C,(IY+2) ;get next sector to read ld B,(IY+3) dec BC ;pre decrement it ld (nextsc),BC ;save it nxtsec: pop BC ;DMA push BC call setdma scf ;clear carry flag ccf ld BC,(nextsc) ;get next sector to read inc BC ;update it ld L,(IY+4) ;get last sector ld H,(IY+5) sbc HL,BC ;any more on this track pop HL ;fix stack jr c,nxttrk ;done with last sector ld (nextsc),BC ;save next sector ld DE,128 add HL,DE ;update DMA push HL ld DE,(xlt) call sectran ld C,L ld B,H call setsec call read or A ld DE,permerr jr nz,error ;physical read error jr nxtsec page ; ; the .SYS file is now in memory starting at (buffer) ; bootdone: ld A,(typeld) ;load of cp/m or something else cp nmbcpm jp nc,trboot ;if not cp/m leave ; JP TRBOOT ; we must go through it and remove all the BIOS sectors ; to make it a table of CCP and BDOS sectors only for wboot ; ld IX,boottbl-6 ld HL,0 ;count of sectors in table so far nxtitem: push HL ;save count of sectors so far ld DE,6 add IX,DE ld C,(IX+2) ;get first sector this track ld B,(IX+3) ld L,(IX+4) ;get last sector this track ld H,(IX+5) sbc HL,BC inc HL ;sectors in this track pop DE add HL,DE ;total sectors so far ld A,bdossecs ;number of sectors for wboot cp L jr z,movtbl ;this track ends exactly at the BIOS jr nc,nxtitem ;keep reading table ;this is the item we must cut down ;B=first sector, C=last sector, E=C-B+1 ;A=bdossecs, L=sectors through end of track ld D,A ld A,L sub D ;A=sectors to remove ld E,A ld D,0 ld L,(IX+4) ld H,(IX+5) sbc HL,DE ld (IX+4),L ;must contain at least one sector in track ld (IX+5),H page ; ; table has now been modified for CP/M wboot use ; IX+5 is end of last table entry movtbl: push IX pop HL ld DE,boottbl-6 sbc HL,DE ;HL=length to move ld B,H ld C,L ld HL,boottbl ld DE,buffer+1637h ;boottbl in buffer-after jump table ldir ;move table ;boottbl filled in, now move image to execution ;area ld HL,buffer ld DE,(buffer+1633h) ;ccp start ld C,0 ld A,(filefcb+15) ;128 byte records allocated rrca rr C ;carry=> odd number of records and 7fh ld B,A ldir ;transfer jp buffer+1600h ;coldboot jump page ; ; turbodos loader stuff ; trboot: ld HL,80h ;first need to clear default buffer ld DE,81h xor A ld (HL),A ld BC,30h ldir ; jp buffer ;now go to loader page ;-------------------------------------------- ; ; error message routine ; error: ex DE,HL ;put message address in HL call pstrng ;send message ld HL,errmsg ;send error message call pstrng ld B,11d ;send file name ld HL,filefcb call pstr2 ld A,4fh ;turn prom back on out (memory),A jp monit ;go back to monitor pstrng: ld B,(HL) pstr2: inc HL ;HL=first character, B=count push HL ld C,(HL) push BC xor A call conout pop BC pop HL djnz pstr2 ret ; ;storage ; filefcb: db 0 ;user number db ' ' ;file name filled in at beg. of code db 'SYS' ;extension ds 20,0 ;dummy rest of dir entry BSH: db 0 ;block shift factor = log2(records/block) BLM: db 0 ;block mask = records/block-1 blkmsb: db 0 ;non-zero is >255 blocks on drive ;=msb of DSM in DPB blksec: dw 0 ;sectors per block (BLM+1) dirbuf: dw 0 ;address of DIRBUF trans: db 0 ;0 if no sector translation XLT: dw 0 ;translate table address SPT: dw 0 ;sector per track count maxdir: dw 0 ;number of directory entries on disk trkoff: dw 0 ;track offset curtrk: dw 0 ;current track cursec: dw 0 absec: dw 0 ;absolute sector typeld: db 0 ;load type 0=cp/m, 1=turbodos nextsc: dw 0 ;temp storage for next sector to read ; ;messages ; signon: db badsel-$ db 0dh,0ah,'Which .SYS file to load',0dh,0ah db '0 = ' cpmf: db 'CPM ',0DH,0AH db '1 = ' turbof: db 'OSLOAD ',0DH,0AH db '? ' namlng equ turbof-cpmf ;length of name entry in above table badsel: db 6,'Select' permerr: db 4,'Read' nofile: db 14,'File not found' errmsg: db 14,' error: file ' boottbl: ds 60,0 end 0 ;block mask = records/block-1 blkmsb: db 0 ;non-zero is >255 blocks on drive ;=msb of DSM in DPB blksec: dw 0 ;sectors per block (BLM+1) dirbuf: dw 0 ;address of DIRBUF trans: db 0 ;0 if no sector translation XLT: dw 0 ;translate t TITLE TURBODOS COLD BOOT LOADER BIOS 1/17/84 doc INCLUDE TRK0BOOT.EQU ; parameters .z80 ; .PHASE 500H nmbfpy equ 1 ;number of floppy disk drives SUBTTL SYMBOLIC EQUATES page ; board hardware equates cmd equ 0ch ;fdc command register trk equ cmd+1 ;track register sec equ cmd+2 ;sector register data equ cmd+3 ;data register wait equ 14h ;INTRQ and DRQ synch port (see manual) memry equ 16h ;memory control port ; ; sector deblocking equates ; hstcnt equ 8 ;number of sectors in buffer hstshft equ 3 ;shift factor for # of sectors in buffer if mini ddpspt equ 4 ;double density physical sectors per track if m48tpi tracks equ 39 ;minifloppies else tracks equ 76 ;96tpi drives endif else ddpspt equ 8 ;eight inch tracks equ 76 endif dpblen equ 15 ;length of a DPB ; ; floppy disk hardware parameter offsets ; density equ 0 ;0=single, 1=single side double D, 2= 2S2D seekrt equ 1 ;THIS IS OFFSET INTO TABLE, VALUE IN TABLE CAN BE ;seek rate 0=3ms, 1=6ms, 2=10ms, 3=15ms ;these times double for minifloppies pspt equ 2 ;physical sectors per track (one side) drvtrk equ 3 ;track a floppy is at parmlen equ 4 ;length of the parameter block ; ; miscellaneous equates ; iobyte equ 3 ;used to select various consoles and printers cdisk equ 4 ;default disk user number retries equ 10 ;retry count for disk operations inbfsz equ 32 ;size of input buffer for interrupt input must be power of 2 outbfsz equ 64 ;size of output buffer for interrupt output must be power of 2 SUBTTL Hard disk equates page ;*** HDC1001 Disk equates *** HOFF EQU 1 ; Number of reserved tracks for loader TST MACRO DN ;physical hard disk defined IF HD&DN x defl 1 else x defl 0 endif endm hddsks defl 0 ;number of physical hard disk drives hdldrvs defl 0 ;number of logical hard disk drives hdtst macro tst %hddsks ;test for physical drives iff x exitm endif .lall hddsks defl hddsks+1 .xall endm ;end hdtst hdtst ;calculate number of physical hard disks if hddsks ;set flag for hard disks hard equ true else hard equ false endif .sfcond if hard ;put this stuff in only if needed .lfcond ;*** Port equates for HDC1001 *** HDCBASE EQU 0E0H ; Base of HDC1001 HDCDATA EQU HDCBASE ; Data port WPC EQU HDCBASE+1 ; Write precomp port HDCERR EQU WPC ; Error port SECNT EQU HDCBASE+2 ; Sector count SECNO EQU HDCBASE+3 ; Sector number CYLLO EQU HDCBASE+4 ; Cylinder low CYLHI EQU HDCBASE+5 ; Cylinder high SDH EQU HDCBASE+6 ; Size/Drive/Head COMND EQU HDCBASE+7 ; Command register STATUS EQU COMND ; Status register ;*** Command equates for HDC1001 *** CREST EQU 10H ; Restore command CSEEK EQU 70H ; Seek command CREAD EQU 20H ; Read sector command CWRITE EQU 30H ; Write command CFORM EQU 50H ; Format track inter equ 8 ;hard disk sector interleave factor secs equ 16 ;Physical sectors per track per head hstsiz equ 512 ;size of a hard disk physical sector hdstcnt equ hstsiz/128 ;cp/m sectors per physical sector blksiz equ 4096 ;cp/m block size cpmspt equ hdstcnt*secs ;cp/m sectors per track per head cpmscbk equ blksiz/128 ;cp/m sectors per cp/m block ; dpbg macro dn,secs,bls,blm,ext,dks,dir,al0,al1,cks,off,phys .lall dpb&dn: dw secs ;sec per track db bls ;block shift db blm ;block mask db ext ;extnt mask dw dks ;disk size-1 dw dir ;directory max db al0 ;alloc0 db al1 ;alloc1 dw cks ;check size dw off ;offset db phys ;physical disk drive .xall endm hdscg macro dn,mxcl,mxhd,stprt .lall hdesc&dn: db hdcbase ;base i/o port address db dn ;physical unit no. db inter ;hardware interleave db secs ;sectors per track dw mxcl ;last cylinder db mxhd ;last head db hstsiz/128 ;sector size/128 db stprt ;step rate .xall endm dsktyp macro dn,typ .lall .sfcond if typ eq ST503 hpb&dn macro no dw -1,hdesc&dn als&no defl 004Ch ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,128,5,31,1,607,511,240,0,0,1,%dn hdscg %dn,152,1,3 endm hddr&dn defl 1 endif if typ eq ST506 hpb&dn macro no dw -1,hdesc&dn als&no defl 0098h ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,256,5,31,1,1215,511,240,0,0,1,%dn hdscg %dn,152,3,3 endm hddr&dn defl 1 endif if typ eq TM601S hpb&dn macro no dw -1,hdesc&dn als&no defl 004Ch ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,128,5,31,1,607,511,240,0,0,1,%dn hdsc %dn,152,1,3 endm hddr&dn defl 1 endif if typ eq TM602S hpb&dn macro no dw -1,hdesc&dn als&no defl 0098h ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,256,5,31,1,1215,511,240,0,0,1,%dn hdsc %dn,152,3,3 endm hddr&dn defl 1 endif if typ eq TM603S hpb&dn macro no dw -1,hdesc&dn als&no defl 00E4h ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,384,5,31,1,1823,1023,255,0,0,1,%dn hdscg %dn,152,5,3 endm hddr&dn defl 1 endif if typ eq TM603SE hdpb603E0&dn macro no dw -1,hdesc&dn als&no defl 0100h ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,384,5,31,1,2047,1023,255,0,0,1,%dn hdscg %dn,229,5,3 endm hdpb603E1&dn macro no als&no defl 00FFh ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,384,5,31,1,699,511,240,0,0,172,%dn endm hpb&dn macro no local x x defl no hdpb603E0&dn %x x defl x+1 hdpb603E1&dn %x endm hddr&dn defl 2 endif if typ eq TM501 hpb&dn macro no dw -1,hdesc&dn als&no defl 0099h ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,128,5,31,1,1219,511,240,0,0,1,%dn hdscg %dn,305,1,3 endm hddr&dn defl 1 endif if typ eq TM502 hdpb5020&dn macro no dw -1,hdesc&dn als&no defl 0100h ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,256,5,31,1,2047,1023,255,0,0,1,%dn hdscg %dn,305,3,3 endm hdpb5021&dn macro no als&no defl 0031H ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,256,5,31,1,391,511,240,0,0,257,%dn endm hpb&dn macro no local x x defl no hdpb5020&dn %x x defl x+1 hdpb5021&dn %x endm hddr&dn defl 2 endif if typ eq TM503 hdpb5030&dn macro no dw -1,hdesc&dn als&no defl 0100h ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,384,5,31,1,2047,1023,255,0,0,1,%dn hdscg %dn,305,5,3 endm hdpb5031&dn macro no als&no defl 00CAH ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,384,5,31,1,1611,1023,255,0,0,172,%dn endm hpb&dn macro no local x x defl no hdpb5030&dn %x x defl x+1 hdpb5031&dn %x endm hddr&dn defl 2 endif if typ eq SA602 hpb&dn macro no dw -1,hdesc&dn als&no defl 0050h ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,128,5,31,1,635,511,240,0,0,1,%dn hdscg %dn,159,1,3 endm hddr&dn defl 1 endif if typ eq SA604 hpb&dn macro no dw -1,hdesc&dn als&no defl 009Fh ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,256,5,31,1,1271,511,240,0,0,1,%dn hdsc %dn,159,3,3 endm hddr&dn defl 1 endif if typ eq SA606 hpb&dn macro no dw -1,hdesc&dn als&no defl 00EFh ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,384,5,31,1,1907,1023,255,0,0,1,%dn hdscg %dn,159,5,3 endm hddr&dn defl 1 endif if typ eq SA1002 hpb&dn macro no dw -1,hdesc&dn als&no defl 0080h ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,128,5,31,1,1019,511,240,0,0,1,%dn hdscg %dn,255,1,0 endm hddr&dn defl 1 endif if typ eq SA1004 hpb&dn macro no dw -1,hdesc&dn als&no defl 00FFh ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,256,5,31,1,2039,1023,255,0,0,1,%dn hdscg %dn,255,3,0 endm hddr&dn defl 1 endif if typ eq Q2010 hpb&dn macro no dw -1,hdesc&dn als&no defl 0100h ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,128,5,31,1,2043,1023,255,0,0,1,%dn hdscg %dn,511,1,0 endm hddr&dn defl 1 endif if typ eq Q2020 hdpb20&dn macro no dw -1,hdesc&dn als&no defl 0100h ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,256,5,31,1,2047,1023,255,0,0,1,%dn hdscg %dn,511,3,0 endm hdpb21&dn macro no als&no defl 00FFh ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,256,5,31,1,2039,1023,255,0,0,257,%dn endm hpb&dn macro no local x x defl no hdpb20&dn %x x defl x+1 hdpb21&dn %x endm hddr&dn defl 2 endif if typ eq Q2030 hdpb30&dn macro no dw -1,hdesc&dn als&no defl 0100h ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,384,5,31,1,2047,1023,255,0,0,1,%dn hdscg %dn,511,5,0 endm hdpb31&dn macro no als&no defl 0100h ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,384,5,31,1,2047,1023,255,0,0,172,%dn endm hdpb32&dn macro no als&no defl 00FEh ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,384,5,31,1,2031,1023,255,0,0,343,%dn endm hpb&dn macro no local x x defl no hdpb30&dn %x x defl x+1 hdpb31&dn %x x defl x+1 hdpb32&dn %x endm hddr&dn defl 3 endif if typ eq Q2040 hdpb40&dn macro no dw -1,hdesc&dn als&no defl 0100h ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,512,5,31,1,2047,1023,255,0,0,1,%dn hdscg %dn,511,7,0 endm hdpb41&dn macro no als&no defl 0100h ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,512,5,31,1,2047,1023,255,0,0,129,%dn endm hdpb42&dn macro no als&no defl 0100h ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,512,5,31,1,2047,1023,255,0,0,257,%dn endm hdpb43&dn macro no als&no defl 00FEh ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,512,5,31,1,2031,1023,255,0,0,385,%dn endm hdpb4021&dn macro no als&no defl 00DFh ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,256,5,31,1,1783,1023,255,0,0,257,%dn endm hpb&dn macro no local x x defl no hdpb40&dn %x x defl x+1 hdpb41&dn %x x defl x+1 hdpb42&dn %x x defl x+1 hdpb43&dn %x endm hddr&dn defl 4 endif if typ eq M4010 hpb&dn macro no dw -1,hdesc&dn als&no defl 00F0h ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,128,5,31,1,1915,1023,255,0,0,1,%dn hdscg %dn,479,1,0 endm hddr&dn defl 1 endif if typ eq M4020 hdpb4020&dn macro no dw -1,hdesc&dn als&no defl 0100h ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,256,5,31,1,2047,1023,255,0,0,1,%dn hdscg %dn,480,3,0 endm hdpb4021&dn macro no als&no defl 00DFh ;size of allocation vector css&no defl 0 ;number of checksum elements dpbg %no,256,5,31,1,1783,1023,255,0,0,257,%dn endm hpb&dn macro no local x x defl no hdpb4020&dn %x x defl x+1 hdpb4021&dn %x endm hddr&dn defl 2 endif hdldrvs defl hdldrvs+hddr&dn .lfcond .xall endm x defl 0 rept hddsks dsktyp %x,hd%x ;define hard disk parameters x defl x+1 endm ; ; dskhdr macro dn ; define a single disk header list .lall hdph&dn: dw 0000h,0000h ;translate table dw 0000h,0000h ;scratch area dw dirbuf,dpb&dn ;dir buff,parm block dw 0000h,0000h ;check, alloc vectors .xall endm ; hddisks macro nd ; define nd disks ndisks defl nd ;for later reference dpbase equ $ ;base of disk parameter blocks ; generate the nd elements dsknxt defl nmbfpy rept nd dskhdr %dsknxt dsknxt defl dsknxt+1 endm endm ; lgdrvs defl 0 ; hdpbs macro dn,lgno hpb&dn lgno lgdrvs defl hddr&dn endm ; hddpbs macro times ;define hard disk parameter blocks local x,y x defl 0 y defl nmbfpy rept times hdpbs %x,%y ;define dpb's for this hd drive endm x defl x+1 ;bump counters y defl y+lgdrvs endm ; ddb macro data,comm ; define a db statement db data comm endm ; ddw macro data,comm ; define a dw statement dw data comm endm ; defds macro lab,space lab: ds space,0 endm ; lds macro lb,dn,val size defl val&dn defds lb&dn,%size endm ; ; logdsk defl nmbfpy endif ;hard disk definitions .lfcond fdskhdr macro dn .lall fdph&dn: dw trans,0,0,0 dw dirbuf,fdpbase dw 0000h,0000h .xall endm fdisks macro x defl 0 rept nmbfpy fdskhdr %x x defl x+1 endm endm dwdsk macro drvr,lgdsk dw drvr+lgdsk endm DSKTBL MACRO ;DEFINES DISK ASSIGNMENT TABLE x defl 0 .lall drvtbl equ $+1 .xall if fpyfrst dw fpy rept nmbfpy-1 dwdsk fpy,%x x defl x+1 endm ;rept y defl 0 rept hdldrvs dwdsk hdc,%x iff y ;if first time thru x defl 0 ;reset x for hard disk logical drives starting at 0 y defl y+1 else x defl x+1 endif endm ;rept else ;fpyfrst dw hdc rept hdldrvs-1 dwdsk hdc,%x x defl x+1 endm ;rept y defl 0 rept nmbfpy dwdsk fpy,%x iff y ;if first time thru x defl 0 ;reset x for hard disk logical drives starting at 0 y defl y+1 else x defl x+1 endif endm ;rept endif ddb %x,<;last logical drive> rept 16-nmbfpy-hdldrvs dw 0 endm ;rept endm ;dsktbl SUBTTL BIOS ENTRY AND PUBLIC TABLES page ; ; BIOS jump table start:: ret ;no cold boot dw 0 ret ;no warm boot dw 0 jp pserin jp serin jp serout ret ;no list dw 0 ret ;no punch dw 0 ret ;no reader dw 0 jp home jp seldsk jp settrk jp setsec jp setdma jp read ret ;no write dw 0 ret ;no list status dw 0 jp sectran SUBTTL Console drivers page ; ; Console drivers ; All have entry A=driver number, other parameters per CP/M ; A=0 serial port 0; A=1 serial port 1 pserin:: ;poll serial in-return A=0ff if char ready, else 0 add A,A inc A ;A=command port ld C,A in A,(C) and 1 ret z ;no character waiting ld A,0ffh ret serin:: ld B,A call pserin ld A,B jr z,serin ;loop until character received add A,A ld C,A in A,(C) and 7fh ;mask high order bit ret serout:: ld B,C ;character to output add A,A inc A ld C,A serst:: in A,(C) and 4 jr z,serst dec C out (C),B ret ; miscellaneous character i/o routines pmsg:: ;equivalent to BDOS function 9 (print) ld A,(DE) cp '$' ret z ld C,A inc DE push DE xor A call serout pop DE jr pmsg phex:: ;print A in hex push AF rra rra rra rra call hex1 pop AF hex1:: and 0fh add A,90h daa adc A,40h daa ld C,A xor A jp serout ; ; setdma:: ld (iodma),BC ;shared among all drivers ret ; ; Sectran input:: Logical sector in BC, translate table in DE ; no translation if DE=0 ; ; Returns physical sector in HL ; Note:: only used in single density sectran:: ld A,D or E ld L,C ld H,B ret z ;no sector translation ex DE,HL add HL,BC ld L,(HL) ld H,0 ret SUBTTL Floppy disk driver module page ; ; Floppy disk drive driver module ; .sfcond iff hard ;if not hard disk .lfcond dskparm:: ;disk hardware parameter block ;one block for each drive rept nmbfpy if (mini) ; db 2 ;double sided double density db 1 ;single sided double density else db 0 ;density - 0=single D; 1=1 side, Double D; 2= 2S 2D endif db seekrate ;seek rate - 0=3ms, 1=6ms, 2=10ms, 3=15ms if (mini) db ddpspt else db 26 ;physical sectors per track - 26 in SD, ddpspt in DD endif db 0 ;track drive currently set at endm page ; ; CP/M disk tables fDPHbase:: fdisks ; defind disk parameter headers for floppys page ; ; DPB's for the three formats of disk:: ; ; 8" Single sided, single density ; 5" Single sided, double density ; 5" Double sided, double density ; fdpbase:: sssddpb:: ;single density (1K block) dw 26 ;sectors per track db 3 ;block shift (log2[block size/128]) db 7 ;block mask ([block size/128]-1) db 0 ;extent mask dw 242 ;highest block on disk (numbered from 0) dw 63 ;directory entries-1 db 0c0h ;alloc0 -first two bits for two blocks for Dir db 0 ;alloc1 dw 16 ;checked directories dw 2 ;track offset (system tracks) page ssdddpb:: ;single sided double density dw 8*ddpspt ;128 byte sectors per track if mini and m48tpi db 3,7 ; 1k block size else db 4,15 ; 2k block size endif db 0 dw (tracks*ddpspt/2)-1 ;each of 76 tracks has ddpspt/2 2K blocks if mini dw 63 db 80h else dw 127 db 0c0h endif db 0 dw 32 dw 1 dsdddpb:: ;double sided double density dw 16*ddpspt ;one track consists of both sides db 4 db 0fh db 0 dw (tracks*ddpspt)-1 ;each of 76 tracks has ddpspt 2K blocks if mini dw 127 db 0c0h else dw 255 db 0f0h endif db 0 dw 32 dw 1 page trans:: ;single density translate table db 1,7,13,19,25,5,11,17,23,3,9,15,21 ;sectors 1-13 db 2,8,14,20,26,6,12,18,24,4,10,16,22 ;secotrs 14-16 home:: ld C,0 settrk:: ld A,C ld (iotrk),A ret setsec:: ld A,C ld (iosec),A ret page ; ; Fseldsk selects the physical floppy in A (0-3) ; B=0 if last disk selected was a different floppy ; C=logical disk the floppy corresponds to seldsk:: ld D,0 ;physcial floppy ld E,C ;save logical disk call getden ;will set density byte if successful or A jr nz,fbadsel ;couldn't get density ;all physical operations OK here ld (hwptr),IX ;store for later use ld A,(IX+density) inc A ;make 1-3 ld B,A ld HL,fdpbase-dpblen ld DE,dpblen fgetdpb:: add HL,DE djnz fgetdpb ;HL=DPB address ld C,L ld B,H ld HL,fdphbase ld A,(IX+density) or A jr z,setran ;single density,set translate vector xor A ld (HL),A inc HL ld (HL),A jr putdpb setran:: ld DE,trans ;single density translate table ld (HL),E inc HL ld (HL),D putdpb:: ld DE,9 ;offset of DPB in DPH add HL,DE ld (HL),C inc HL ld (HL),B dec HL dec HL sbc HL,DE ;restore DPH (carry reset by or A) ret fbadsel::ld HL,0 ret ;return error page ; ; Seldrv selects the drive , head from (head) ; (bit 0 set for head1), and density from (IX+density) ; it assembles the correct byte and outputs to wait ; and updates the track register with the most recent information seldrv:: ld A,(IX+density) or A jr z,setdens ld A,00001000b ;set double density bit ld B,A ld A,(head) rlca rlca ;move head bit to bit 2 or B setdens:: ld B,A IF MINI SET 4,A ; SUPER SIX BENEFIT ENDIF out (wait),A ld A,(IX+drvtrk) ;get track from parameter table ;this may be first physical i/o out (trk),A ret page ; ; Seek attempts to step the R/W head to the track in (iotrk) ; seek:: ld A,retries ld (retryc),A seek2:: ld A,(iotrk) ld C,A ;track stays in C in A,(trk) sub C ret z ;already there ld A,C  out (data),A ld A,(IX+seekrt) ;seek rate mask or 1ch ;seek with verify di out (cmd),A in A,(wait) ei rla jr c,seekerr ;no INTRQ from FDC in A,(cmd) and 10011001b ;seek error, CRC error, or incomplete jr nz,seekerr ;seek successful ld (IX+drvtrk),C ret seekerr:: ld E,1ch ;seek command call diskerror jr seek2 page ; ; Read reads the sector from the selected disk ; In double density, the sector may already be in the host buffer ; read:: ld IX,(hwptr) ;restore parameter pointer ld A,(IX+density) ;density byte or A jr z,rdsngl ;singl density call inbuf jr c,rddbl ;sector not in buffer ; sector is in buffer movrd:: call mkbufad ;HL=start of sector in buffer ldir ret ;transfer done rddbl:: call sidesec call readprep or A ret nz jr movrd rdsngl:: ld A,(iosec) ld (psec),A ;physical sector same as CP/M sector ;in single density readprep:: ld A,0A2h ;second byte of INI instruction ld (iotran+1),A ;patch rdwrite routine ld A,08ch ;sector read command ld (oper),A page strtsel:: call seldrv ;physically select drive and head call seek ;step to correct track ; ; diskio actually reads or writes the necessary sector ; it assumes that the head has already settled on the correct track ; (and that the head has been selected on the correct side!) ; and that the bytes in rdwrite for R/W and sector size have been filled diskio:: ld A,retries ld (retryc),A iotry:: ld A,0d0h ;force interrupt no conditions out (cmd),A ld A,(oper) ld B,A ld C,data ;prepare for indirect I/O instruction ex (SP),HL ;waste some time ex (SP),HL ex (SP),HL ex (SP),HL di ;no interrupts from here to end of transfer in A,(cmd) and 20h ;bit 5=head loaded rrca rrca rrca ;move bit 5 to bit 2 cpl and B ; the purpose of these manipulations has been ; to set bit 2 of the FDC command if the head ; isn't settled. Bit 2 will give a 15 ms delay ld E,A ld A,(IX+density) or A ld D,1 ;one sector i/o transfer for single denisty jr z,dmasingl ;use the CP/M DMA buffer in single density ld HL,hstbuf ;use host buffer for double density operations ld D,hstcnt ;number of 128 byte units to transfer jr strtio dmasingl:: ld HL,(iodma) strtio:: ld A,(psec) out (sec),A ;set physical sector ld A,E out (cmd),A ;start read/write operation call rdwrite ;do the actual i/o in A,(cmd) ei ;now ok to interrupt-status is saved ld E,A ;save status or B ;B returned from rdwrite is lost bytes count ret z ;if status OK and no lost bytes call diskerror call seek or A jr z,iotry ;if nonzero then hopeless seek error ret ; ; rdwrite does the actual transfer to/from the FDC ; HL set to DMA address on entry, D=number of 128 byte units to transfer ; transfer direction has been set by poking INI or OUTI instruction rdwrite:: ld B,128 ;bytes in one CP/M sector loop:: in A,(wait) or A ret p ;no more DRQ iotran:: ini ;start with read ;the second byte of this instruction is patched to ;be either INI or OUTI depending on need jr nz,loop dec D jr nz,rdwrite jr loop ;sector done, wait for INTRQ from fdc page ; ; disk error will eventually have all kinds of nice messages ; diskerror:: ld A,(retryc) dec A jr nz,restore ;more retries to attempt ld A,E cp 1ch ;was it a seek error? jr z,pseekerr cp 0ach ;writing? jr z,pwriterr ld DE,rderr jr perrtyp pwriterr:: ld DE,wrterr jr perrtyp pseekerr:: ld DE,skerr perrtyp:: call pmsg ld DE,trkerr call pmsg ld A,(iotrk) call phex ld DE,secerr call pmsg ld A,(psec) call phex ld DE,siderr call pmsg ld A,(head) call phex pdrv:: ld DE,drverr call pmsg ld DE,crlf call pmsg ld A,255 ret page ; ; Restore is called from a disk operation with A=retries left ; restore:: ld (retryc),A in A,(cmd) and 00010000b ;bit 4=record not found ret z ;try again if record was found but ;read/written with error resto1:: ;restore to track 0 and seek again ld A,(IX+seekrt) ;get seek rate mask or 00001100b ;head load, restore, verify track 0 out (cmd),A tk0wait:: in A,(cmd) and 00000100b ;at track 0 jr z,tk0wait xor A out (trk),A ;back at track 0 ld (IX+drvtrk),A ;update track table ret page ; ; sidesec is the read/write preparation for double density ; sidesec computes the correct physical sector and side ; sidesec:: ld A,(iosec) and not(hstcnt-1) ;computer first CP/M sector in block ld (blksec),A sideflsh:: ;called to set up for a flush rept hstshft rrca endm ;A=physical sector number, but it may ;be on the second side ld B,(IX+pspt) cp B ld C,0 jr c,side0 sub B inc C side0:: inc A ld (psec),A ;physical sector on one side ld A,C ld (head),A ;set head control byte ret page ; ; inbuf returns carry flag set if sector not in buffer ; also returns (iosec) in D ; if sector is in buffer, returns offset (0 - hstcnt-1) in A ; inbuf:: ld A,(iosec) ld D,A ld A,(bufvalid) ;0 if contains valid data, else 255 rra ret c inbuf2:: ld HL,(iodrvtrk) ;check for 2nd sector ;of unallocated block ld BC,(blkdrvtrk) sbc HL,BC ;same drive and track jr z,rttrk scf ret ;not a match rttrk:: ld A,(blksec) ld B,A ld A,D sub B ret C ;sector lower # than buffer cp hstcnt ;carry set if in buffer ccf ret ; stores drive, track, sector of contents of buffer for use by flush ; also saves hardware pointer and sets buffer valid flag ; returns HL=start of sector in buffer, DE=DMA address, BC=128, A=0 mkbufad:: ld (blkptr),IX ld HL,(iodrvtrk) ld (blkdrvtrk),HL ld A,(iosec) ld B,A and not(hstcnt-1) ld (blksec),A ld A,B and hstcnt-1 ld B,A ;B=relative sector in buffer inc B ld HL,hstbuf-128 ld DE,128 shft2:: add HL,DE djnz shft2 ld BC,128 ;make ready for sector LDIR ld DE,(iodma) xor A ld (bufvalid),A ret page ; ; returns IX=start of DHPB (disk hardware parameter block) for ; the drive in A (0-3) ; uses B,DE also, returns D=0 getparm:: ld B,A inc B ld IX,dskparm-parmlen ;hardware parameter block ld DE,parmlen shft1:: add IX,DE djnz shft1 ret page ; ; Getden attempts to find the density of the disk in drive (D) ; by trying to read the current track address in both densities ; If the attempt is successful, Getden will update the ; dens, pspt, and drvtrk fields of the paramter table ; If E (logical disk) is zero, then getden assumes the density hasn't ; changed (if it has, then we can't do a warm boot-table is wrong getden:: ld A,0d0h ;reset FDC out (cmd),A ld A,D and 7fh call getparm ld A,(7fh) ;code byte for disk type OR A jr z,codeok ;some SD disks have old loaders here sub 0e5h ;code for a normal single density disk cp 3 jr c,codeok ld DE,badcode ;not our code byte call pmsg call pdrv ld A,255 ret codeok:: ld (IX+density),A or A jr z,snglspt ld A,ddpspt ;physical sectors on one side of DD jr putpspt snglspt:: ld A,26d ;single density physical sectors putpspt:: ld (IX+pspt),A xor A ret ;no errors logdin::call getparm ld A,(IX+density) jr codeok ; drive can't change density else ;iff hard SUBTTL Hard disk drivers page .lfcond ; ; Hard disk drive driver module ; ; ; CP/M Hard disk tables ; hDPHbase:: hddisks hdldrvs ;set up disk parameter headers ; ; DPB's for HARD DISKS ; ; hdpbase equ $+4 hddpbs hddsks ;set up disk parameter blocks page home:: ld BC,0 ;force track 0 settrk:: ld (hdiotrk),BC ;save track number ret setsec:: ld (hdiosec),BC ;save sector number ret ; ; Hseldsk selects the hard disk seldsk:: ld HL,hdphbase ;add in base address ret ; and go ; ; Seldrv selects the drive from (curhdsk), head from (hhead) ; it assembles the correct byte and outputs it ; and updates the track register with the most recent information hseldrv:: ld A,(hhead) ;get head or 20h ;set sector size to 512 bytes out (sdh),a ;send to controller ret page ; ; Seek sets head to the track in (hdiotrk) ; and sector to (hpsec), sector count to one ; hseek:: ld a,(hdiotrk) ;send low order byte of track out (cyllo),a ld a,(hdiotrk+1) ;send high byte out (cylhi),a ld A,(hpsec) ;send physical sector out (secno),A ld A,1 ;set sector count out (secnt),A ret page ; ; Read reads the sector from the selected disk ; it handles any necessary buffering ; read:: call hinbuf ;is it in the buffer jr c,hrd ;sector not in buffer ; sector is in buffer hmvrd:: call hmkbfad ;HL=start of sector in buffer ldir ret ;transfer done hrd:: call hsidselc call hrdprep or A ret nz jr hmvrd ; ; read preperation ; hrdprep:: call hseldrv ;physically select drive and head call hseek ;step to correct track ; ; this actually reads the necessary sector ; it assumes that the head has already settled on the correct track ; (and that the proper head has been selected) ld HL,hstbuf ;point to buffer ld BC,hdcdata ;count and port di ;protect transfer ld A,cread ;send read command out (comnd),A hrdw:: in A,(status) ;done yet and A jp m,hrdw ;if not wait inir ;256 bytes twice inir ei in A,(status) and 1 ;any errors ret z ;return if not ; page ; ; hard disk error message processor ; ; This routine gives the user a detailed error report ; herrors:: push AF ;save error indication ld DE,herrst CALL pmsg ; First the error code IN A,(HDCERR) CALL phex ld DE,errhd CALL pmsg ; then the head IN A,(SDH) push AF ;save drive no AND 7 CALL hex1 ; Print single digit ld DE,errcyl CALL pmsg ; the cylinder IN A,(CYLHI) ; Report CYLHI first CALL phex IN A,(CYLLO) ; then CYLLO CALL phex ld DE,errsec CALL pmsg ; and finally the sector IN A,(SECNO) CALL phex ld DE,errdr ;send drive mess call pmsg pop AF rlca ;get drive rlca rlca and 3 call hex1 ld A,crest ;restore drive out (comnd),A herrlp:: in A,(status) rlca jr c,herrlp ;wait until done pop AF RET page ; ; hsidselc is the read/write preparation for hard disk ; hsidselc computes the correct physical sector and side ; hsidselc:: ld HL,(hdiosec) ld E,L ;save L ld A,L and not(31) ;compute first cp/m sector in buffer ld L,A ld (hblksec),HL ;save it ld L,E ;restore sector to HL hflsdsc:: ;called to set up for a flush or a ;clear carry ld C,-1 ;set up head count ld DE,secs*4 ;set up number cpm sectors per head sdsclp: inc C ;increment head count sbc HL,DE ;subtract out one heads worth of sectors jp p,sdsclp ;if not negitive do more add HL,DE ;restore sector number to HL ld A,L srl A ;find physical sector srl A ld (hpsec),A ld A,C ld (hhead),A ;set head control byte ret page ; ; hinbuf returns carry flag set if sector not in buffer ; if sector is in buffer, returns offset (0 - hdstcnt-1) in A ; hinbuf:: ld A,(bufvalid) ;0 if contains valid data, else 255 rra ret c hinbu2f:: ld A,(hiodrvtrk) ;check for right drive ld B,A ld A,(hblkdrvtrk) sub B jr z,rthdd ;skip if right drive scf ret ;wrong drive return with carry set rthdd:: ld HL,(hiodrvtrk+1) ;check for right track ld BC,(hblkdrvtrk+1) sbc HL,BC ;same drive and track scf ret nz ;not a match ld DE,(hblksec) ld HL,(hdiosec) ld A,D ;high bytes = cp H scf ;set failure flag ret nz ;exit if not equal ccf ;clear carry sbc HL,DE ret C ;sector lower # than buffer ld A,L cp hdstcnt ;carry set if in buffer ccf ret ; ; stores drive, track, sector of contents of buffer for use by flush ; also sets buffer valid flag ; returns HL=start of sector in buffer, DE=DMA address, BC=128, A=0 ; hmkbfad:: ld A,(hiodrvtrk) ld (hblkdrvtrk),a ld HL,(hiodrvtrk+1) ld (hblkdrvtrk+1),HL ld HL,(hdiosec) ld B,L ld A,L and not(hdstcnt-1) ld L,A ld (hblksec),HL ld A,B and hdstcnt-1 ld B,A ;B=relative sector in buffer inc B ld HL,hstbuf-128 ld DE,128 hshft2:: add HL,DE djnz hshft2 ld BC,128 ;make ready for sector LDIR ld DE,(iodma) xor A ld (bufvalid),A ret endif SUBTTL Floppy disk storage page ; ; Floppy disk driver storage ; bufvalid:: db 0ffh ;buffer contains valid data for (blksec) ;0 = valid data iodma:: ds 2,0 ;dma storage .sfcond iff hard ;if not hard .lfcond iodrvtrk:: curfpy:: db 0 ;current selected physical floppy drive iotrk:: ds 1,0 ;current track for current disk blkdrvtrk:: ds 2,0 ;drive and track for deblocking buffer iosec:: ds 1,0 ;current logical sector for DD, physical for SD blksec:: ds 1,0 ;first logical sector in current host blk2sec:: ds 1,0 ;8th CP/M sector in an unallocated 2K block psec:: ds 1,0 ;current physical sector wrtpend:: db 0 ;write pending from buffer retryc:: db 0 ;number of retries left newfpy:: db 0 ;new floppy to be selected head:: db 0 ;head control = 0 or 1 oper:: db 0 ;operation (read/write) to be performed next hwptr:: dw dskparm ;storage for pointer to current hw parameters blkptr:: dw dskparm ;pointer to paramters for block drive SUBTTL Hard disk storage page ; ; Hard disk driver storage ; else .lfcond hiodrvtrk:: curhdsk:: db 0 ;current selected physical hard disk drive hdiotrk:: ds 2,0 ;current track for current disk hblkdrvtrk:: ds 3,0 ;drive and track for deblocking buffer hdiosec:: ds 2,0 ;current logical sector hblksec:: dw 0 ;first logical sector in host buffer hunalsec:: dw 0 ;first logical sector in current host unallocated block unalcv:: db 0 ;unallocated block vector hpsec:: ds 1,0 ;current physical sector hwrtpnd:: db 0 ;write pending from buffer hhead:: db 0 ;head control endif SUBTTL Error messages page .sfcond iff hard .lfcond ; ; Floppy error messages ; badcode:: db 'Can''t recognize density of disk in$' rderr:: db 'Read$' wrterr:: db 'Write$' skerr:: db 'Seek$' trkerr:: db ' error on track $' secerr:: db ' sector $' siderr:: db ' side $' drverr:: db ' drive $' crlf:: db 0dh,0ah,'$' page ; ; Hard disk error messages ; else .lfcond herrst:: DB 0dH,0ah,'HD1001 Error $' errhd:: DB ' on Head $' errcyl:: DB ', Cylinder $' errsec:: DB ', Sector $' errdr:: db ', Drive $' endif SUBTTL Disk buffers and Cold Boot code page ; ; disk buffers ; These are not part of the floppy driver module as such and ; should be shared by all disk modules as much as possible dirbuf:: hstbuf equ dirbuf+128 ;sector deblocking buffer ; ; lastadd equ $ SUBTTL SYMBOLS end ng from buffer hhead:: db 0 ;head control endif SUBTTL Error messages page .sfcond iff hard .lfcond ; ; Floppy error messages ; badcode:: db 'Can''t recognize density of disk in$' rderr:: db 'Read$' wrterr:: db 'Write$' skerr:: db TITLE TURBODOS COLD BOOT LOADER EQUATES 1/17/84 doc ; Here is the parameters for constructing a track 0 cold boot loader. ; If "HD0" is set to anything but FALSE, the floppy parameters will ; be ignored and a hard disk track 0 loader will be constructed. TRUE EQU -1 FALSE EQU 0 ;**** FLOPPY DRIVE EQUATES **** SEEKRATE EQU 2 ; drive seek rate, 0=3ms, 1=6ms, 2=10ms, 3=20ms ; if MINI is set to TRUE, times will be doubled MINI EQU FALSE ; TRUE if 5 1/4 minifloppy, else 8 inch. M48TPI EQU FALSE ; TRUE if 48 tpi minifloppy, else 96 tpi. SINGLE EQU true ; TRUE if single density, else double density DOUBLE EQU false ; TRUE if double sided floppy ; NOTE: double sided, single density is ; NOT ALLOWED ! ; HARD DISK TABLE ;*** Hard Disk selection choices *** ST503 EQU 1 ; Seagate Technology ST503 ST506 EQU 2 TM601S EQU 3 ; Tandon Magnetics TM601S TM602S EQU 4 TM603S EQU 5 TM603SE EQU 6 TM501 EQU 7 ; Tandon Magnetics TM501 or Seagate ST406 TM502 EQU 8 ; Tandon Magnetics TM502 or Seagate ST412 TM503 EQU 9 ; Tandon Magnetics TM503 or Seagate ST419 SA602 EQU 10 ; Shugart Associates SA602 SA604 EQU 11 SA606 EQU 12 SA1002 EQU 13 ; Shugart Associates SA1002 SA1004 EQU 14 Q2010 EQU 15 ; Quantum Q2010 Q2020 EQU 16 Q2030 EQU 17 Q2040 EQU 18 M4010 EQU 19 ; MiniScribe 4010 M4020 EQU 20 ;**** HARD DISK EQUATE **** HD0 EQU FALSE ; Set to FALSE if you are making a floppy ; loader, otherwise, enter a choice from ; the table above. E EQU false ; TRUE if double sided floppy ; NOTE: double sided, single density is ; NOT ALLOWED ! ; HARD DISK TABLE ;*** Hard Disk selection choices *** ST503 EQU 1 ; Seagate Technology ST503 ST506 EQU 2 TM601S EQU 3 ; Tandon Magnetics TM601S TM602S EQU 4 TM603S EQU 5 TM603SE EQU 6 TM501 EQU 7 ; Tandon Magnetics TM501 or Seagate ST406 TM502 EQU  TITLE TURBODOS COLD BOOT LOADER FRONT END 1/17/84 doc .z80 memry equ 16h ; memory control port ; HDC-1001 port equates HDCBASE EQU 0E0H ; Base of HDC1001 HDCDATA EQU HDCBASE ; Data port WPC EQU HDCBASE+1 ; Write precomp port HDCERR EQU WPC ; Error port SECNT EQU HDCBASE+2 ; Sector count SECNO EQU HDCBASE+3 ; Sector number CYLLO EQU HDCBASE+4 ; Cylinder low CYLHI EQU HDCBASE+5 ; Cylinder high SDH EQU HDCBASE+6 ; Size/Drive/Head COMND EQU HDCBASE+7 ; Command register STATUS EQU COMND ; Status register ; HDC-1001 commands CREST EQU 10H ; Restore command CSEEK EQU 70H ; Seek command CREAD EQU 20H ; Read sector command sectors equ 10 cseg start: ld A,06fh ;get command to memory port out (memry),A ;turn off prom ld BC,hdcdata ;get port number and transfer length ld HL,?beg?## ;starting address less this program ld d,0 ;sector 0 ld e,sectors ;number of sectors to xfer loop: ld A,D ;send sector to controller out (secno),A ld A,cread ;send read command out (comnd),A wait: in A,(status) ;wait till done and 80h jr nz,wait inir inir inc D ;increment sector to read dec E ;decrement sector count jr nz,loop ;if more go do it jp osboot## ;else go execute loader error: ld A,04fh ;turn prom back on out (memry),A jp 0f030h ;return to monitor hard disk error return code equ $-start END TATUS EQU COMND ; Status register ; HDC-1001 commands CREST EQU 10H ; Restore command CSEEK EQU 70H ; Seek command CREAD EQU 20H ; Read sector command sectors equ 10 cseg start: ld A,06fh ;get command to memory port out (memry),A ;turn off prom ld BC,hdcdata ;get port number and transfer length ld HL,?beg?## ;starting address less this program ld d,0 ;sector 0 ld e,sectors ;number of sectors to xfer loop: ld A,D ;send sector to controller out (secno),A title Hard disk specification table subttl Advanced Digital 7/3/84 name ('TL213') ; Module name (6 chars only) tracks equ 640 ; physical tracks heads equ 2 ; physical heads steprt equ 0 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 1024 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 16 ; sectors per track (head) secsiz equ 512 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable dseg ; locate in data segment TL213@:: ; Global entry point for patching (6 chrs only) ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if  bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db ((dirsiz*8)/blksiz)*4 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end title Hard disk specification table subttl Advanced Digital 7/3/84 name ('TL226') ; Module name (6 chars only) tracks equ 640 ; physical tracks heads equ 4 ; physical heads steprt equ 0 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 1024 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 16 ; sectors per track (head) secsiz equ 512 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable dseg ; locate in data segment TL226@:: ; Global entry point for patching (6 chrs only) ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if  bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db ((dirsiz*8)/blksiz)*4 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end title Hard disk specification table subttl Advanced Digital 7/3/84 name ('TL240') ; Module name (6 chars only) tracks equ 640 ; physical tracks heads equ 6 ; physical heads steprt equ 0 ; step rate (refer to the hdc1001 manual ; for step rates) dirsiz equ 1024 ; number of directory entries blksiz equ 4096 ; block size trkoff equ 1 ; res tracks (can be used to partition drives) hdoffst equ 0 ; set to amount of heads to ignore phydrv equ 0 ; physical drive number set to 0,1,2 or 3 ecc equ 0 ; set to 1 for ecc enabled else 0 sectrk equ 16 ; sectors per track (head) secsiz equ 512 ; sector size 512 or 256 fixed equ 1 ; set to 1 for fixed media else 0 for removable dseg ; locate in data segment TL240@:: ; Global entry point for patching (6 chrs only) ;Don't change anything below this point! setparm macro size ; macro to determine block sizes bls set high size ; initialize bls blocks set 0 ; clear block value rept 8 ; repeat a max of 8 if  bls ne 0 ; is bls <> 0 bls set bls shr 1 ; shift until bls=0 blocks set blocks+1 ; increment block by 1 endif ; end of if statement endm ; end of repeat endm ; end of macro setparm blksiz ; determine block size db fixed shl 7 or blocks ; block size if sectrk*secsiz lt blksiz ; test for underflow dw sectrk*secsiz*(heads-hdoffst)/blksiz*(tracks-trkoff) ; total blocks else dw sectrk*secsiz/blksiz*(heads-hdoffst)*(tracks-trkoff) ; total blocks endif db ((dirsiz*8)/blksiz)*4 ; directory blocks setparm secsiz ; determine sector size db blocks ; sector size dw sectrk*(heads-hdoffst) ; sectors per cylinder dw tracks ; tracks per disk dw trkoff ; track offset db ecc shl 7 or ((blocks and 1) shl 6) or steprt ;ecc,drvtyp,step rate db hdoffst ; head offset db phydrv ; physical drive number dw sectrk ; physical sectors per track end  title TURBODOS OPERATING SYSTEM - SUPER SIX BANKED SWITCHED TPA DRIVER subttl copyright 1983, software 2000, inc. .z80 ; ; copyright 1983, software 2000, inc. ; converted to MICROSOFT M80 format by ; Advanced Digital Corp. ; ; version: 07/01/83 ; name ('S6BNK') ;module id ; include DREQUATE.LIB ;driver symbolic equivalences ; memcr1 equ 16h ;memory control register ##1 memcr2 equ 17h ;memory control register ##2 ; common /?bank?/ ;locate in common area ; bnknit:: ld (spsave),SP ;save stack pointer ld sp,auxstk ;set up auxilliary stack ld hl,0 ;initialize memory parity (bank 0) ld de,0 ld bc,0 ldir ld a,1 ;get bank 1 call selmem ;select bank 1 ld hl,0 ;initialize memory parity (bank 1) ld de,0 ld bc,0 ldir ld a,68h ;reset parity error latch out (memcr1),a ld a,0e8h ;enable parity error detection out (memcr1),a ld hl,rtcint ;get interrupt service address ld (ctcvec##+2),hl ;set interrupt vector ld hl,dskint ;get interrupt service address ld (ctcvec##+6),hl ;set interrupt vector ld hl,sioint ;get interrupt service address ld (siovec##),hl ;set interrupt vector xor a ;get bank 0 call selmem ;select bank 0 ld sp,(spsave) ;restore stack pointer ret ;done ; rtcint: ld (spsave),sp ;save stack pointer ld sp,auxstk ;set up auxilliary stack push af ;save af-reg xor a ;get bank 0 call selmem ;select bank 0 call rtcisr## ;process real time clock interrupt di ;disable interrupts ld a,1 ;get bank 1 call selmem ;select bank 1 pop af ;restore af-reg ld sp,(spsave) ;restore stack pointer ei ;enable interrupts ret ;done ; dskint: ld (spsave),sp ;save stack pointer ld sp,auxstk ;set up auxilliary stack push af ;save af-reg xor a ;get bank 0 call selmem ;select bank 0 call dskisr## ;process disk interrupt di ;disable interrupts ld a,1 ;get bank 1 call selmem ;select bank 1 pop af ;restore af-reg ld sp,(spsave) ;restore stack pointer ei ;enable interrupts ret ;done ; sioint: ld (spsave),sp ;save stack pointer ld sp,auxstk ;set up auxilliary stack push af ;save af-reg xor a ;get bank 0 call selmem ;select bank 0 call sioisr## ;process serial i/o interrupt di ;disable interrupts ld a,1 ;get bank 1 call selmem ;select bank 1 pop af ;restore af-reg ld sp,(spsave) ;restore stack pointer ei ;enable interrupts ret ;done ; selbnk:: di ;disable interrupts call selmem ;select memory bank ei ;enable interrupts ret ;done ; selmem: or a ;bank 0 requested? jr nz,..bnk1 ;if not, continue xor a ;else, get bank 1 command out (memcr2),a ;de-select lower 48k of memory ld a,0efh ;get bank 0 command out (memcr1),a ;enable lower 48k of memory jp frebnk ;free bank 1 mutual exclusion ..bnk1: call lokbnk ;gain bank 1 mutual exclusion ld a,0e8h ;get bank 0 command out (memcr1),a ;de-select lower 48k of memory ld a,07h ;get bank 1 command out (memcr2),a ;enable lower 48k of memory ret ;done ; spsave: dw 0 ;stack pointer save area ds 16*2 ;auxilliary stack area auxstk equ $ ;top of auxilliary stack area ; dseg ;locate in data area ; bk1sph: dw 1 ;memory bank 1 exclusion semaphore ..mxhd: dw ..mxhd dw ..mxhd ; cseg ;locate in program area ; lokbnk:: push bc ;save registers push de push hl ld a,r ;get interrupt status push af ;save interrupt status ld hl,bk1sph ;get mutual exclusion semaphore call wait## ;wait on mutual exclusion di ;disable interrupts pop af ;restore interrupt status jp po,..x ;if interrupts disabled, continue ei ;else, enable interrupts ..x: pop hl ;restore registers pop de pop bc ret ;done ; frebnk:: push bc ;save registers push de push hl ld hl,bk1sph ;get mutual exclusion semaphore call signal## ;release mutual exclusion pop hl ;restore registers pop de pop bc ret ;done ; end  TITLE TURBODOS OPERATING SYSTEM - SUPER SIX DISK DRIVER subttl copyright 1983, software 2000, inc. .Z80 ; ; copyright 1983, software 2000, inc. ; converted to MICROSOFT M80 format by ; Advanced Digital Corp. ; ; version: 02/16/84 doc ; NAME ('S6DSK') ;module id ; INCLUDE DREQUATE.LIB ;driver symbolic equivalences ; false equ 0 ;logical equates true equ not false ; banked equ true ;true for banked 1.3 system ; ; ctcch3 equ 0bh ;ctc channel 3 register ; fdccsr equ 0ch ;fdc command/status register fdctrk equ 0dh ;fdc track register fdcsec equ 0eh ;fdc sector register fdcdat equ 0fh ;fdc data register ; dmactl equ 10h ;dma control register ; fdcdsr equ 14h ;fdc drive select register ; fdccal equ 08h ;fdc re-calibrate command fdcskn equ 10h ;fdc seek command without head load fdcskh equ 18h ;fdc seek command with head load fdcrdc equ 82h ;fdc read sector command fdcwrc equ 0a2h ;fdc write sector command fdcrid equ 0c0h ;fdc read id command fdcint equ 0d0h ;fdc interrupt command fdcfmt equ 0f0h ;fdc format track command ; hsdbit equ 2 ;head settle delay bit ; dmardc equ 01h ;dma read command dmawrc equ 05h ;dma write command ; tsd equ 2 ;two sided disk bit ddd equ 3 ;double density disk bit mini equ 4 ;mini-floppy disk bit tpi96 equ 5 ;96-tpi disk bit ; maxtry equ 10 ;max disk try count ; PUBLIC maxfpy ; DSEG ;locate in data area ; drvtbl:: db 0,0,1 shl mini,1 shl mini or 1 shl tpi96 ;drive table ; drive: db 0ffh ;drive number sector: db 0 ;sector number seccnt: db 0 ;sector count trycnt: db 0 ;try counter dlybit: db 0 ;head settle delay bit intcst: db 0 ;interrupt completion status rwerrs: db 0 ;read/write error status dsrsav: db 0 ;drive select register save ndxcnt: db 0 ;index pulse sequence count ndxtic: db 0 ;index pulse tick count retsp: dw 0 ;error return stack pointer trktbl: db 0ffh,0ffh,0ffh,0ffh ;track save table ridbuf: ds 6 ;read id buffer ; dmxsph: ;mutual exclusion semaphore dw 1 ;semaphore count ..dmxh: dw ..dmxh ;semaphore p/d head dw ..dmxh ; dwtsph: ;disk wait semaphore dw 0 ;semaphore count ..dwth: dw ..dwth ;semaphore p/d head dw ..dwth ; dmapgm: ;dma controller program list db 0c3h ;write register 6 db 08bh ;write register 6 db 79h ;write register 0 dmaadr: dw 0 ;dma address dmalen: dw 0 ;dma length db 14h ;write register 1 db 28h ;write register 2 db 85h ;write register 4 db fdcdat ;fdc data port address db 8ah ;write register 5 db 0cfh ;write register 6 dmarwc: db 05h ;dma read/write command db 0cfh ;write register 6 db 87h ;write register 6 ; dmapll equ $-dmapgm ;dma controller program list length ; common /?init?/ ;locate in initialization area ; dskin@:: call clrfdc ;clear fdc ld hl,dskisr ;get interrupt service routine ld (ctcvec##+6),hl ;set interrupt vector address ret ;done ; cseg ;locate in program area ; dskdr@:: ld hl,dmxsph ;get mutual exclusion semaphore call wait## ;dispatch if necessary call ..dd ;call disk driver push af ;save return code ld hl,dmxsph ;get mutual exclusion semaphore call signal## ;signal process as ready pop af ;restore return code ret ;done ; ..dd: ld (retsp),sp ;save error return stack pointer ld a,(ix+pdrfcn) ;get function number or a ;function number=0? jr z,rddsk ;if so, continue dec a ;function number=1? jr z,wrdsk ;if so, continue dec a ;function number=2? jp z,retdst ;if so, continue dec a ;function number=3? jp z,retrdy ;if so, continue dec a ;function number=4? jr z,fmtdsk ;if so, continue ret ;else, done ; rddsk: ld a,maxtry ;get max try count ld (trycnt),a ;set try counter ..rd: call setup ;do common setup jr nz,..err ;if seek error, continue ..rdl: call rwcom1 ;else, do read/write common #1 ld de,fdcrdc shl 8 or 9dh ;get fdc read command/mask call rwcom2 ;do read/write common #2 ld a,dmardc ;get dma read command call dmacom ;do dma common call rwcom3 ;do read/write common #3 jr nz,..rdl ;if not last sector, continue ld a,(rwerrs) ;else, get read/write error status or a ;read/write error status=0? ret z ;if so, done ..err: call retry ;else, re-calibrate drive jr ..rd ;try again ; wrdsk: ld a,maxtry ;get max try count ld (trycnt),a ;set try counter ..wr: call setup ;do common setup jr nz,..err1 ;if seek error, continue ..wrl: call rwcom1 ;else, do read/write common #1 ld de,fdcwrc shl 8 or 0fdh ;get fdc read command/mask call rwcom2 ;do read/write common #2 ld a,dmawrc ;get dma write command call dmacom ;do dma common call rwcom3 ;do read/write common #3 jr nz,..wrl ;if not last sector, continue ld a,(rwerrs) ;else, get read/write error status or a ;read/write error status=0? jr nz,..err1 ;if not, continue call setup ;else, do common setup jr nz,..err1 ;if seek error, continue ..vfl: call rwcom1 ;else, do read/write common #1 ld d,fdcrdc ;get fdc read command call rwcom2 ;do read/write common #2 ld a,d ;get fdc read command call fdccmd ;output fdc read command and 99h ;extract relevant status bits call rwcom3 ;do read/write common #3 jr nz,..vfl ;if not last sector, continue ld a,(rwerrs) ;else, get read/write error status or a ;read/write error status=0? ret z ;if so, done ..err1: call retry ;else, re-calibrate drive jr ..wr ;try again ; fmtdsk: ld a,maxtry ;get max try count ld (trycnt),a ;set try counter ..fmt: call seldsk ;select disk jp nz,fatal ;if drive not ready, continue ld a,(dsrsav) ;get saved drive select register bit 7,(ix+pdrsec) ;double density requested? jr nz,..ddr ;if so, continue res 3,a ;else, reset double density bit ..ddr: bit 7,(ix+pdrsec+1) ;side one requested? jr z,..s1nr ;if not, continue set 2,a ;else, set side one select bit ..s1nr: out (fdcdsr),a ;select drive/side/density ld (dsrsav),a ;save drive select register value ld a,(ix+pdrtrk) ;get requested track number or a ;requested track number=0? call z,recal ;if so, re-calibrate drive call seek ;seek to requested track jr nz,..err2 ;if seek error, continue ld l,(ix+pdrdma) ;get requested dma address ld h,(ix+pdrdma+1) ld (dmaadr),hl ;set dma address ld l,(ix+pdrtc) ;get requested transfer count ld h,(ix+pdrtc+1) dec hl ;decrement requested transfer count ld (dmalen),hl ;set dma length ld de,fdcfmt shl 8 or 0e1h ;get format command/mask ld a,dmawrc ;get dma write command call dmacom ;do dma common ret z ;if no errors, done ..err2: call retry ;else, re-calibrate drive jr ..fmt ;try again ; setup: ld a,(ix+pdrsec) ;get requested sector number ld (sector),a ;set sector number ld a,(ix+pdrsc) ;get requested sector count ld (seccnt),a ;set sector count ld l,(ix+pdrdma) ;get requested dma address ld h,(ix+pdrdma+1) ld (dmaadr),hl ;set dma address ld b,(ix+secsiz) ;get sector size inc b ;increment sector size ld hl,128/2 ;get sector size=0 (/2) ..sl: add hl,hl ;shift sector size left djnz ..sl ;sector size times dec hl ;decrement sector size ld (dmalen),hl ;set dma length xor a ld (rwerrs),a ;set read/write error status=0 call seldsk ;select disk jp nz,fatal ;if drive not ready, continue call seek ;else, seek to requested track ret ;done ; rwcom1: call gettca ;get disk type code address ld a,(hl) ;get disk type code ld hl,dsrsav ;get saved drive select register bit ddd,a ;double density disk? jr nz,..ddd ;if so, continue res 3,(hl) ;else, reset double density bit ..ddd: bit tsd,a ;two sided disk? ld a,(sector) ;get sector number jr z,..ntsd ;if not two sided disk, continue ld c,(ix+sectrk) ;get number of sectors/track srl c ;calc number of sectors/side cp c ;requested sector on side one? jr c,..ntsd ;if not, continue sub c ;else, adjust sector number set 2,(hl) ;set side one select bit ..ntsd: ld c,a ;sector number to c-reg ld a,(ix+pdrtrk) ;get track or a ;if it's zero jr z,..nstr ;don't translate sector call getxlt ;get translation table address jr z,..nstr ;if no sector translation, continue ld b,0 ;make sector number double length add hl,bc ;index into translation table ld c,(hl) ;get translated sector number ..nstr: ld a,c ;get sector number inc a ;increment sector number to base 1 out (fdcsec),a ;set fdc sector register ld a,(dsrsav) ;get saved drive select register out (fdcdsr),a ;select drive/side/density ret ;done ; rwcom2: ld a,(dsrsav) ;get saved drive select register bit 2,a ;side one selected? ret z ;if not, done set 3,d ;else, set side one verify bit ret ;done ; rwcom3: ld hl,rwerrs ;get read/write error status or (hl) ;combine with completion status ld (hl),a ;update read/write error status ld hl,(dmaadr) ;get dma address ld de,(dmalen) ;get dma length inc de ;increment dma length add hl,de ;calc next dma address ld (dmaadr),hl ;update dma address ld hl,sector ;get sector number inc (hl) ;increment sector number ld hl,seccnt ;get sector count dec (hl) ;decrement sector count ret ;done ; retry: ld c,abel ;get bell character call conout## ;output bell character to console ld a,(trycnt) ;get try counter and 01h ;even try? call nz,recal ;if not, re-calibrate drive ld a,(trycnt) ;get try counter push af ;save try counter ld hl,(retsp) ;get error return stack pointer push hl ;save error return stack pointer ld hl,dmxsph ;get mutual exclusion semaphore call signal## ;signal process as ready ld hl,0 ;set delay count=0 call delay## ;dispatch ld hl,dmxsph ;get mutual exclusion semaphore call wait## ;dispatch if necessary pop hl ;restore error return stack pointer ld (retsp),hl ;set error return stack pointer pop af ;restore try counter dec a ;decrement try counter ld (trycnt),a ;update try counter ret nz  ;if count not exhausted, done ; fatal: ld sp,(retsp) ;restore stack pointer ld a,0ffh ;return error code ret ;done ; retdst: call retrdy ;return ready status or a ;drive ready? ret z ;if not, done ld (ix+pdrtrk),1 ;and seek to track 1, will recal if first time call seek call readid ;read sector id jr nz,..nrdy ;if read unsuccessful, continue ld a,(ridbuf+3) ;else, get sector size ld c,a ;sector size to c-reg ld a,(dsrsav) ;get saved drive select register bit 3,a ;double density bit set? jr z,..nddd ;if not, continue set ddd,c ;else, set double density disk bit ..nddd: set 2,a ;set side one select bit out (fdcdsr),a ;select requested drive ld (dsrsav),a ;save drive select register value call clrfdc ;clear fdc and 80h ;drive ready? jr nz,..ntsd1 ;if not, continue push bc ;else, save disk type code call readid ;read sector id pop bc ;restore disk type code jr nz,..ntsd1 ;if read unsuccessful, continue ld a,(ridbuf+1)  ;get id side byte cp 1 ;is it head 1 jr nz,..ntsd1 ;skip if not ld a,(dsrsav) ;get saved drive select register xor c ;compare side one/two densities and 1 shl ddd jr nz,..ntsd1 ;if densities different, continue ld a,(ridbuf+3) ;get sector size xor c ;compare side one/two sector sizes and 3 jr nz,..ntsd1 ;if sizes different, continue set tsd,c ;else, set two sided disk bit ..ntsd1: call getdta ;get drive table address ld a,(hl) ;get drive table value and 1 shl mini or 1 shl tpi96 ;extract relevant bits or c ;combine with disk type code ld c,a ;disk type code to c-reg ld de,dstbls## ;get dst table base ..dstl: ld hl,dtco## ;get offset to disk type code add hl,de ;calc disk type code address ld a,c ;get disk type code cp (hl) ;dst type code match? ex de,hl ;dst address to hl-reg jr z,..dstf ;if dst found, continue ld e,(hl) ;else, get next dst address inc hl ld d,(hl) ld a,d or e ;end of dst chain? jr nz,..dstl ;if not, continue ..nrdy: xor a ;else, set return code=0 ret ;done ..dstf: inc hl ;advance past link pointer inc hl ld (ix+pdrdst),l ;set dst address ld (ix+pdrdst+1),h ld a,0ffh ;set return code=0ffh ret ;done ; seek: in a,(fdctrk) ;get fdc track register inc a ;fdc track register=0ffh? call z,recal ;if so, re-calibrate drive in a,(fdctrk) ;else, get fdc track register cp (ix+pdrtrk) ;fdc track=requested track? ret z ;if so, done ld a,1 shl hsdbit ;get head settle delay bit ld (dlybit),a ;set head settle delay bit call clrfdc ;clear fdc ld a,(ix+pdrtrk) ;get requested track number out (fdcdat),a ;output requested track number call getdta ;get drive table address ld a,(hl) ;get drive table value and 3 ;extract step rate or fdcskh ;combine with fdc seek command call fdccmd ;output fdc seek command and 91h ;extract relevant status bits ret ;done ; recal: ld a,1 shl hsdbit ;get head settle delay bit ld (dlybit),a ;set head settle delay bit call clrfdc ;clear fdc call getdta ;get pointer to step rate ld a,(hl) ;get it and 3 ;save only step rate or fdccal ;or in recal command call fdccmd ;output fdc re-calibrate command ret ;done ; retrdy: ld a,(ix+pdrdrv) ;get requested drive maxfpy equ $+1 ;point to max drive number for patching cp 4 ;test for valid drive number ld a,0 ;preset return code=0 ret nc ;if invalid drive, return not ready call seldsk ;else, select requested drive ld a,0 ;preset return code=0 ret nz ;if drive not ready, done cpl ;else, set return code=0ffh ld hl,dsrsav ;get saved drive select register bit 4,(hl) ;mini-floppy disk bit set? ret z ;if not, done ld a,2 ;get index pulse sequence count ld (ndxcnt),a ;set index pulse sequence count=2 call enactc ;enable ctc interrupt controller ld a,fdcint or 1 shl 2 ;get fdc interrupt command out (fdccsr),a ;output fdc interrupt command ld hl,60 ;get one second delay count call delay## ;delay for one second ld a,03h ;get ctc reset command out (ctcch3),a ;reset ctc channel 3 call clrfdc ;clear fdc ld hl,ndxcnt ;set index pulse sequence count ld a,(hl) ;get index pulse sequence count ld (hl),0 ;set index pulse sequence count=0 or a ;index pulse sequence count=0? cpl ;preset return code=0ffh ret z ;if sequence count=0, done xor a ;else, set return code=0 ret ;done ; seldsk: ld a,(ix+pdrdrv) ;get requested drive set 3,a ;set double density bit call getdta ;get drive table address bit mini,(hl) ;mini-floppy disk? jr z,..nmfd ;if not, continue set 4,a ;else, set mini-floppy disk bit ..nmfd: out (fdcdsr),a ;select requested drive ld (dsrsav),a ;save drive select register value call clrfdc ;clear fdc and 80h ;drive ready? ret nz ;if not, done ld (dlybit),a ;else, set head settle delay bit=0 ld a,(drive) ;get drive number cp (ix+pdrdrv) ;drive number=requested drive? ret z ;if so, done cp 0ffh ;drive number invalid? jr z,..dni ;if so, continue call ..gtta ;else, get track save table address in a,(fdctrk) ;get fdc track register ld (hl),a ;save fdc track register ..dni: ld a,(ix+pdrdrv) ;get requested drive ld (drive),a ;set drive number call ..gtta ;get track save table address ld a,(hl) ;get fdc track register out (fdctrk),a ;set fdc track register out (fdcdat),a ;set fdc data register ld a,fdcskn ;get fdc seek command call fdccmd ;output fdc seek command xor a ;set return code=0 ret ;done ..gtta: ld e,a ;drive number to de-reg ld d,0 ;double length ld hl,trktbl ;get track save table add hl,de ;index into track save table ret ;done ; readid: ld hl,ridbuf ;get read id buffer ld (dmaadr),hl ;set dma address ld hl,6-1 ;get sector id length (-1) ld (dmalen),hl ;set dma length ld hl,dsrsav ;get saved drive select register set 3,(hl) ;set double density bit ld a,(hl) ;get saved drive select register out (fdcdsr),a ;select drive/side/density ..ridl: ld de,fdcrid shl 8 or 9dh ;get read id command/mask ld a,dmardc ;get dma read command call dmacom ;read id ret z ;if read ok, done ld a,(dsrsav) ;get saved drive select register xor 1 shl 3 ;toggle single/double density bit out (fdcdsr),a ;output drive select register value ld (dsrsav),a ;save drive select register value and 1 shl 3 ;double density selected? jr z,..ridl ;if not, continue ret ;else, done ; dmacom: ld (dmarwc),a ;set dma read/write command if banked call lokbnk## ;gain mutual exclusion on bank 1 endif call clrfdc ;clear fdc ld hl,dmapgm ;get dma program list ld bc,dmapll shl 8 or dmactl ;b=program length/c=port otir ;program dma controller ld a,(dlybit) ;get head settle delay bit or d ;combine with fdc command push de ;save error mask call fdccmd ;output fdc command pop de ;restore error mask and e ;extract relevant status bits push af ;save error status  ld a,0c3h ;get dma reset command out (dmactl),a ;disable dma controller xor a ld (dlybit),a ;set head settle delay bit=0 if banked call frebnk## ;free mutual exclusion on bank 1 endif pop af ;restore error status ret ;done ; fdccmd: push af ;save fdc command call enactc ;enable ctc interrupt controller pop af ;restore fdc command out (fdccsr),a ;output fdc command ld hl,dwtsph ;get disk wait semaphore call wait## ;wait for operation to complete ld a,(intcst) ;get interrupt completion status ret ;done ; clrfdc: ld a,fdcint ;get fdc interrupt command out (fdccsr),a ;output fdc interrupt command ex (sp),hl ;delay ex (sp),hl ex (sp),hl ex (sp),hl ex (sp),hl ex (sp),hl ex (sp),hl ex (sp),hl in a,(fdcdat) ;clear drq in a,(fdccsr) ;clear intrq ret ;done ; dskisr:: ld (intsp##),SP ;save interrupt stack pointer ld sp,intstk## ;set up aux stack push af ;save registers push bc push de push hl in a,(fdccsr) ;get fdc completion status ld (intcst),a ;save interrupt completion status ld a,(ndxcnt) ;get index pulse sequence count dec a ;index pulse sequence count=0? jp m,..isc0 ;if so, continue jr nz,..fip ;if first index pulse, continue ld a,(ndxtic) ;else, get index pulse tick count ld c,a ;index pulse tick count to c-reg ld a,(ticcnt##) ;get current tick count ld (ndxtic),a ;update index pulse tick count sub c ;calc elapsed tick counts cp 14 ;index pulse timing within limits? jr nc,..isrx ;if not, continue xor a ld (ndxcnt),a ;set index pulse sequence count=0 jr ..iscx ;continue ..fip: ld (ndxcnt),a ;set index pulse sequence count=1 ld a,(ticcnt##) ;get tick count ld (ndxtic),a ;save index pulse tick count jr ..isrx ;continue ..isc0: ld hl,dwtsph ;get disk wait semaphore call signal## ;signal process as ready ..iscx: ld a,03h ;get ctc reset command out (ctcch3),a ;reset ctc channel 3 ..isrx: pop hl ;restore registers pop de pop bc pop af ld sp,(intsp##) ;restore stack pointer ei ;enable interrupts reti ;done ; enactc: ld a,0d7h ;get ctc channel 3 control word out (ctcch3),a ;initialize ctc channel 3 ld a,1 ;get ctc channel 3 time constant out (ctcch3),a ;set ctc channel 3 time constant ret ;done ; getxlt: call getdst ;get dst address ld de,xltbl## ;get offset to translation table add hl,de ;calc translation table address ld e,(hl) ;get translation table address inc hl ld d,(hl) ex de,hl ;translation table to hl-reg ld a,h or l ;translation table required? ret ;done ; gettca: call getdst ;get dst address ld de,typcod## ;get offset to disk type code add hl,de ;calc disk type code address ret ;done ; getdst: ld l,(ix+pdrdst) ;get dst address ld h,(ix+pdrdst+1) ret ;done ; getdta: ld e,(ix+pdrdrv) ;get requested drive ld d,0 ;double length ld hl,drvtbl ;get drive table add hl,de ;index into drive table ret ;done ; end  title TURBODOS OPERATING SYSTEM - FLOPPY DISK DRIVE SPECIFICATION TABLES subttl copyright 1983, software 2000, inc. .z80 ; ; copyright 1983, software 2000, inc. ; converted to MICROSOFT M80 format by ; Advanced Digital Corp. ; ; version: 01/27/84 doc ; name ('dskfmt') ;module id ; include DREQUATE.LIB ;driver symbolic equivalences ; false equ 0 ;logical equates true equ not false ; ; cpm equ TRUE ;set to false for TURBODOS 0 track offsets ; on double density disks ; tsd equ 2 ;two-sided disk bit (type code) ddd equ 3 ;double density disk bit (type code) mini equ 4 ;mini-floppy disk bit (type code) tpi96 equ 5 ;96-tpi disk bit (type code) ; public xltbl,dtco,typcod,gaplen ; cseg ;locate in program area ; ; 1024 byte sector, double-density, two-sided ; dstbls:: dw $+dstl ;disk spec table link pointer db 4 ;block size if cpm dw (76*(16*(1 shl 3)))/(1 shl 4);number of blocks else dw (77*(16*(1 shl 3)))/(1 shl 4);number of blocks endif db 4 ;number of directory blocks db 3 ;physical sector size (2^n*128) dw 16 ;physical sectors per track dw 77 ;physical tracks per disk if cpm dw 1 ;number of reserved tracks else dw 0 ;number of reserved tracks endif dw 0 ;translation table address db 1 shl ddd or 1 shl tsd or 3 ;disk type code db 35h ;gap length ; ; 1024 byte sector, double-density, two-sided, 96-tpi (mini) ; dw $+dstl ;disk spec table link pointer db 4 ;block size if cpm dw (76*(8*(1 shl 3)))/(1 shl 4);number of blocks db 2 ;number of directory blocks db 3 ;physical sector size (2^n*128) dw 8 ;physical sectors per track dw 77 ;physical tracks per disk dw 1 ;number of reserved tracks else dw (80*(10*(1 shl 3)))/(1 shl 4);number of blocks db 4 ;number of directory blocks db 3 ;physical sector size (2^n*128) dw 10 ;physical sectors per track dw 80 ;physical tracks per disk dw 0 ;number of reserved tracks endif dw 0 ;translation table address db 1 shl tpi96 or 1 shl mini or 1 shl ddd or 1 shl tsd or 3;disk type code db 35h ;gap length ; ; 1024 byte sector, double-density, two-sided (mini) ; dw $+dstl ;disk spec table link pointer db 4 ;block size if cpm dw (39*(8*(1 shl 3)))/(1 shl 4);number of blocks db 2 ;number of directory blocks db 3 ;physical sector size (2^n*128) dw 8 ;physical sectors per track dw 40 ;physical tracks per disk dw 1 ;number of reserved tracks else dw (40*(10*(1 shl 3)))/(1 shl 4);number of blocks db 2 ;number of directory blocks db 3 ;physical sector size (2^n*128) dw 10 ;physical sectors per track dw 40 ;physical tracks per disk dw 0 ;number of reserved tracks endif dw 0 ;translation table address db 1 shl mini or 1 shl ddd or 1 shl tsd or 3;disk type code db 35h ;gap length ; ; 1024 byte sector, double-density, one-sided ; dw $+dstl ;disk spec table link pointer db 4 ;block size if cpm dw (76*(8*(1 shl 3)))/(1 shl 4);number of blocks else dw (77*(8*(1 shl 3)))/(1 shl 4);number of blocks endif db 3 ;number of directory blocks db 3 ;physical sector size (2^n*128) dw 8 ;physical sectors per track dw 77 ;physical tracks per disk if cpm dw 1 ;reserved tracks else dw 0 ;reserved tracks endif dw 0 ;translation table address db 1 shl ddd or 3 ;disk type code db 35h ;gap length ; ; 1024 byte sector, double-density, one-sided, 96-tpi (mini) ; dw $+dstl ;disk spec table link pointer db 4 ;block size if cpm dw (76*(4*(1 shl 3)))/(1 shl 4);number of blocks db 1 ;number of directory blocks db 3 ;physical sector size (2^n*128) dw 4 ;physical sectors per track dw 77 ;physical tracks per disk dw 1 ;reserved tracks else dw (80*(5*(1 shl 3)))/(1 shl 4);number of blocks db 2 ;number of directory blocks db 3 ;physical sector size (2^n*128) dw 5 ;physical sectors per track dw 80 ;physical tracks per disk dw 0 ;reserved tracks endif dw 0 ;translation table address db 1 shl tpi96 or 1 shl mini or 1 shl ddd or 3;disk type code db 35h ;gap length ; ; 1024 byte sector, double-density, one-sided (mini) ; dw $+dstl ;disk spec table link pointer db 3 ;block size ; db 4 if cpm dw (39*(4*(1 shl 3)))/(1 shl 3);number of blocks ; db 1 ;number of directory blocks db 2 db 3 ;physical sector size (2^n*128) dw 4 ;physical sectors per track dw 40 ;physical tracks per disk dw 1 ;reserved tracks else dw (40*(5*(1 shl 3)))/(1 shl 3);number of blocks db 2 ;number of directory blocks db 3 ;physical sector size (2^n*128) dw 5 ;physical sectors per track dw 40 ;physical tracks per disk dw 0 ;reserved tracks endif dw 0 ;translation table address db 1 shl mini or 1 shl ddd or 3 ;disk type code db 35h ;gap length ; ; 512 byte sector, double-density, one-sided mini (Kaypro DD) ; dw $+dstl ;disk spec table link pointer db 3 ;block size dw (39*(10*(1 shl 2)))/(1 shl 3) ;number of blocks db 2 ;number of directory blocks db 2 ;physical sector size (2^n*128) dw 10 ;physical sectors per track dw 40 ;physical tracks per disk dw 1 ;reserved tracks dw kayskw ;translation table address db 1 shl ddd or 1 shl mini or 2 ;disk type code db 1bh ;gap length ; ; 512 byte sector, single-density, two-sided ; dw $+dstl ;disk spec table link pointer db 4 ;block size dw (77*(16*(1 shl 2)))/(1 shl 4);number of blocks db 3 ;number of directory blocks db 2 ;physical sector size (2^n*128) dw 16 ;physical sectors per track dw 77 ;physical tracks per disk dw 0 ;reserved tracks dw 0 ;translation table address db 1 shl tsd or 2 ;disk type code db 1bh ;gap length ; ; 512 byte sector, single-density, one-sided ; dw $+dstl ;disk spec table link pointer db 4 ;block size dw (77*(8*(1 shl 2)))/(1 shl 4);number of blocks db 2 ;number of directory blocks db 2 ;physical sector size (2^n*128) dw 8 ;physical sectors per track dw 77 ;physical tracks per disk dw 0 ;reserved tracks dw 0 ;translation table address db 2 ;disk type code db 1bh ;gap length ; ; 256 byte sector, single-density, two-sided ; dw $+dstl ;disk spec table link pointer db 4 ;block size dw (77*(30*(1 shl 1)))/(1 shl 4) ;number of blocks db 3 ;number of directory blocks db 1 ;physical sector size (2^n*128) dw 30 ;physical sectors per track dw 77 ;physical tracks per disk dw 0 ;reserved tracks dw 0 ;translation table address db 1 shl tsd or 1 ;disk type code db 0eh ;gap length ; ; 256 byte sector, single-density, one-sided ; dw $+dstl ;disk spec table link pointer db 4 ;block size dw (77*(15*(1 shl 1)))/(1 shl 4) ;number of blocks db 2 ;number of directory blocks db 1 ;physical sector size (2^n*128) dw 15 ;physical sectors per track dw 77 ;physical tracks per disk dw 0 ;reserved tracks dw 0 ;translation table address db 1 ;disk type code db 0eh ;gap length ; ; 256 byte sector, single-density, one-sided 48-tpi mini (Osborne SD) ; dw $+dstl ;disk spec table link pointer db 4 ;block size dw (37*(10*(1 shl 1)))/(1 shl 4) ;number of blocks db 1 ;number of directory blocks db 1 ;physical sector size (2^n*128) dw 10 ;physical sectors per track dw 37 ;physical tracks per disk WAS 37 dw 3 ;reserved tracks dw osbskw ;translation table address db 1 shl mini or 1 ;disk type code db 0eh ;gap length ; ; 128 byte sector, single-density, two-sided ; dw $+dstl ;disk spec table link pointer db 4 ;block size dw (77*(52*(1 shl 0)))/(1 shl 4) ;number of blocks db 2 ;number of directory blocks db 0 ;physical sector size (2^n*128) dw 52 ;physical sectors per track dw 77 ;physical tracks per disk dw 0 ;reserved tracks dw 0 ;translation table address db 1 shl tsd ;disk type code db 7 ;gap length ; ; 128 byte sector, single-density, single-sided 48-tpi mini (Xerox SD) ; dw $+dstl ;disk spec table link pointer db 3 ;block size dw (37*(18*(1 shl 0)))/(1 shl 3) ;number of blocks db 1 ;number of directory blocks db 0 ;physical sector size (2^n*128) dw 18 ;physical sectors per track dw 40 ;physical tracks per disk dw 3 ;reserved tracks dw xrxskw ;translation table address db 1 shl mini ;disk type code db 7 ;gap length ; ; 128 byte sector, single-density, one-sided ; dsta: dw 0 ;disk spec table link pointer dstb: db 3 ;block size dw (75*(26*(1 shl 0)))/(1 shl 3);number of blocks db 2 ;number of directory blocks db 0 ;physical sector size (2^n*128) dw 26 ;physical sectors per track dw 77 ;physical tracks per disk dw 2 ;reserved tracks ; xltbl equ $-dstb ;translation table address offset ; dw trtbl ;translation table address ; dtco equ $-dsta ;disk type code offset typcod equ $-dstb ;disk type code offset ; db 0 ;disk type code ; gaplen equ $-dstb ;gap length offset ; db 7 ;gap length ; dstl equ $-dsta ;disk spec table length ; ; single-density/single-sided (8", IBM-3740) sector translation table ; trtbl: db 0,6,12,18,24,4,10,16,22 db 2,8,14,20,1,7,13,19,25 db 5,11,17,23,3,9,15,21 ; ; Kaypro II sector translation table ; kayskw: db 0FFH,00,01,02,03,04,05,06,07,08 ; ; Osborne SD sector translation table ; osbskw: db 0,2,4,6,8,1,3,5,7,9 ; ; Xerox SD sector translation table ; xrxskw: db 0,5,10,15,2,7,12,17,4,9,14,1,6,11,16,3,8,13 ; END w (75*(26*(1 shl 0)))/(1 shl 3);number of blocks db 2 ;number of directory blocks db 0 ;physical sector size (2^n*128) dw 26 ;physical sectors per track dw 77 ;physical tracks per disk dw 2 ;reserved tracks ; xltbl equ $-dstb ;translation table address offset ; dw trtbl ;translation table address ; dtco equ $-dsta ;disk type code offset typcod equ $-dstb ;disk type code offset ; db 0 ;disk type code ; gaplen equ $-dstb ;gap length offset ; db 7 ;gap length ; dstl equ $-dsta ;disk spec table length ; ; single-density/single-sided (8", IBM-3740) sector translation table ; trtbl: db 0,6,12,18 title TURBODOS OPERATING SYSTEM - SUPER SIX HARDWARE INITIALIZATION subttl copyright 1983, software 2000, inc. .Z80 ; ; copyright 1983, software 2000, inc. ; converted to MICROSOFT M80 format by ; Advanced Digital Corp. ; ; version: 07/01/83 ; name ('S6NIT') ;module id ; include DREQUATE.LIB ;driver symbolic equivalences ; sioadr equ 00h ;sio port a data register sioacr equ 01h ;sio port a control register siobdr equ 02h ;sio port b data register siobcr equ 03h ;sio port b control register ; pioadr equ 04h ;pio port a data register piobdr equ 05h ;pio port b data register pioacr equ 06h ;pio port a control register piobcr equ 07h ;pio port b control register ; ctcch0 equ 08h ;ctc channel 0 register ctcch1 equ 09h ;ctc channel 1 register ctcch2 equ 0ah ;ctc channel 2 register ctcch3 equ 0bh ;ctc channel 3 register ; fdccsr equ 0ch ;fdc command/status register fdctrk equ 0dh ;fdc track register fdcsec equ 0eh ;fdc sector register fdcdat equ 0fh ;fdc data register ; dmactl equ 10h ;dma control register ; fdcdsr equ 14h ;fdc drive select register tssojr equ 15h ;two-sided status/option jumper reg extadr equ 15h ;extended address register ; memcr1 equ 16h ;memory control register ##1 memcr2 equ 17h ;memory control register ##2 ; siobrr equ 18h ;sio baud rate generator register ; aseg org 0 ;locate in base page ; intpag: ;im2 interrupt page ds 8 ;(reserved for turbodos) ctcvec:: ds 4 ;ctc interrupt vector siovec:: ds 8 ;sio interrupt vector ; common /?init?/ ;locate in init-code area ; hdwnit:: LD a,0efh ;disable prom/power on jump out (memcr1),a xor a ;disable second memory bank out (memcr2),a ld (iobyte),a ;set i/o byte=0 ld hl,0 ;initialize memory parity ld de,0 ld bc,0 ldir ld a,6fh ;reset parity error latch out (memcr1),a ld a,0efh ;enable parity error detection out (memcr1),a ld a,18h out (sioacr),a ;reset sio port a out (siobcr),a ;reset sio port b ld a,03h out (ctcch0),a ;reset ctc channel 0 out (ctcch1),a ;reset ctc channel 1 out (ctcch2),a ;reset ctc channel 2 out (ctcch3),a ;reset ctc channel 3 ld a,07h out (pioacr),a ;reset pio port a interrupts out (piobcr),a ;reset pio port b interrupts ld a,HIGH intpag ;get interrupt page ld i,a ;set interrupt page register im 2 ;set interrupt mode 2 ld a,LOW ctcvec ;get ctc interrupt vector out (ctcch0),a ;initialize ctc interrupt vector call bnknit## ;initialize banked tpa driver call sionit## ;initialize serial i/o call rtcnit## ;initialize real time clock call dskina## ;initialize disk driver a call dskinb## ;initialize disk driver b call dskinc## ;initialize disk driver c call dskind## ;initialize disk driver d call cktina## ;initialize circuit driver a call cktinb## ;initialize circuit driver b call cktinc## ;initialize circuit driver c jp cktind## ;initialize circuit driver d ; end  title TURBODOS OPERATING SYSTEM - SUPER SIX REAL TIME CLOCK DRIVER subttl copyright 1983 by software 2000, inc. .z80 ; ; copyright 1983 by software 2000, inc. ; converted to MICROSOFT M80 format by ; Advanced Digital Corp. ; ; version: 07/01/83 ; name ('S6RTC') ;module id ; include DREQUATE.LIB ;driver symbolic equivalences ; ctcch0 equ 08h ;ctc channel 0 register ctcch1 equ 09h ;ctc channel 1 register ; dseg ;locate in data area ; ticctr: db 0 ;tick counter ; COMMON /?init?/ ;locate in initialization area ; rtcnit:: ld hl,rtcisr ;get interrupt service address ld (ctcvec##+2),hl ;set interrupt service vector ld a,47h ;get ctc channel 0 control word out (ctcch0),a ;initialize ctc channel 0 ld a,250 ;get time constant value out (ctcch0),a ;set ctc channel 0 time constant ld a,0c7h ;get ctc channel 1 control word out (ctcch1),a ;initialize ctc channel 1 ld a,100 ;get time constant value out (ctcch1),a ;set ctc channel 1 time constant ret ;done ; cseg ;locate in program area ; rtcisr:: ld (intsp##),SP ;save stack pointer ld sp,intstk## ;set up aux stack pointer push af ;save registers push bc push de push hl ld hl,ticctr ;get tick counter inc (hl) ;increment tick counter ld a,(hl) ;get tick count cp 60 ;seconds count reached? jr c,..nsec ;if not, continue ld (hl),0 ;else, reset tick counter call rtcsec## ;service real time clock manager ..nsec: call dlytic## ;service dispatcher delay manager pop hl ;restore registers pop de pop bc pop af ld sp,(intsp##) ;restore stack pointer jp isrxit## ;continue ; end  ;get time constant value out (ctcch0),a ;set ctc channel 0 time constant ld a,0c7h ;get ctc channel 1 control word out (ctcch1),a ;initialize ctc channel 1 ld a,100 ;get time constant value out (ctcch1),a ;set ctc channel 1 time constant title TURBODOS OPERATING SYSTEM - SUPER SIX SERIAL I/O DRIVER subttl copyright 1983, software 2000, inc. .z80 ; ; copyright 1983, software 2000, inc. ; converted to MICROSOFT M80 format by ; Advaced Digital Corp. ; ; version: 07/12/83 ; name ('S6SIO') ;module id ; include DREQUATE.LIB ;driver symbolic equivalences ; sioadr equ 00h ;sio port a data register sioacr equ 01h ;sio port a control register siobdr equ 02h ;sio port b data register siobcr equ 03h ;sio port b control register ; ; siobrr equ 18h ;sio baud rate generator register ; rda equ 0 ;received data available bit tbe equ 2 ;transmit buffer empty bit dcd equ 3 ;data carrier detect bit cts equ 3 ;clear to send bit ; DSEG ;locate in data area ; baudrt: db 0 ;baud rate register value ; s0ibsz:: dw 64 ;serial 0 input buffer size s0ibuf: dw 0 ;serial 0 input buffer address s0iptr: dw 0 ;serial 0 input pointer s0optr: dw 0 ;serial 0 output pointer s0icnt: dw 0 ;serial 0 input count s0iwct: db 0 ;serial 0 input wait count s0ochr: db 0 ;serial 0 output character s0br: db 0 ;serial 0 baud rate code ; s0isph: ;serial 0 input semaphore dw 0 ;semaphore count ..s0ih: dw ..s0ih ;semaphore p/d head dw ..s0ih ; ;serial 0 output semaphore s0osph: dw 0 ;semaphore count ..s0oh: dw ..s0oh ;semaphore p/d head dw ..s0oh ; s1ibsz:: dw 16 ;serial 1 input buffer size s1ibuf: dw 0 ;serial 1 input buffer address s1iptr: dw 0 ;serial 1 input pointer s1optr: dw 0 ;serial 1 output pointer s1icnt: dw 0 ;serial 1 input count s1iwct: db 0 ;serial 1 input wait count s1ochr: db 0 ;serial 1 output character s1br: db 0 ;serial 1 baud rate code ; ;serial 1 input semaphore s1isph: dw 0 ;semaphore count ..s1ih: dw ..s1ih ;semaphore p/d head dw ..s1ih ; ;serial 1 output semaphore s1osph: dw 0 ;semaphore count ..s1oh: dw ..s1oh ;semaphore p/d head dw ..s1oh ; COMMON /?init?/ ;locate in initialization area ; sionit:: ld hl,siovec## ;get interrupt vector address ld a,l ;get lsb of interrupt vector ld (wr2cwd),a ;set write register 2 control word ld hl,sioisr ;get interrupt service address ld (siovec##),hl ;set interrupt vector address ld hl,siopgm ;get sio program list ld bc,sioapl shl 8 or sioacr ;b=length/c=control reg otir ;program sio port a ld hl,siopgm ;get sio program list ld bc,siobpl shl 8 or siobcr ;b=length/c=control reg otir ;program sio port b ld hl,(s0ibsz) ;get serial 0 input buffer size call alloc## ;allocate packet for serial buffer ld (s0ibuf),hl ;save serial 0 input buffer address ld (s0iptr),hl ;set serial 0 input pointer ld (s0optr),hl ;set serial 0 output pointer ld hl,(s1ibsz) ;get serial 1 input buffer size call alloc## ;allocate packet for serial buffer ld (s1ibuf),hl ;save serial 1 input buffer address ld (s1iptr),hl ;set serial 1 input pointer ld (s1optr),hl ;set serial 1 output pointer ret ;done ; siopgm: db 18h ;reset channel db 4 ;select wr4 db 44h ;write register 4 control word db 5 ;select wr5 db 0eah ;write register 5 control word db 3 ;select wr3 db 0c1h ;write register 3 control word db 1 ;select wr1 db 10h ;write register 1 control word ; sioapl equ $-siopgm ;sio port a program length ; db 2 ;select wr2 wr2cwd: db 0 ;write register 2 control word ; siobpl equ $-siopgm ;sio port b program length ; cseg ;locate in program area ; serial:: comdrv:: ld a,e ;get function number or a ;function number=0? jr z,serst ;if so, continue cp 10 ;function number=10? jp z,seropt ;if so, continue dec a ;function number=1? jr z,serin ;if so, continue dec a ;function number=2? jp z,serout ;if so, continue dec a ;function number=3? jp z,sersbr ;if so, continue dec a ;function number=4? jp z,serrbr ;if so, continue dec a ;function number=5? jp z,sersmc ;if so, continue dec a ;function number=6? jp z,serrmc ;if so, continue ret ;else, done ; serst: ld a,b ;get channel number ld bc,(s0icnt) ;get serial 0 input buffer count ld hl,(s0optr) ;get serial 0 output pointer or a ;channel number=0 jr z,..com ;if so, continue ld bc,(s1icnt) ;get serial 1 input buffer count ld hl,(s1optr) ;get serial 1 output pointer ..com: ld a,b or c ;serial input buffer count=0? ret z ;if so, done ld c,(hl) ;else, get serial input character ld a,0ffh ;set return code=0ffh ret ;done ; serin: ld a,b ;get channel number or a ;channel number=0? jr nz,..s1i ;if not, continue ..s0i: di ;else, disable interrupts ld hl,(s0icnt) ;get serial 0 input count ld a,h or l ;serial 0 input count=0? jr z,..wt0 ;if so, continue dec hl ;decrement serial 0 input count ld (s0icnt),hl ;update serial 0 input count ld hl,(s0optr) ;get serial 0 output pointer ld a,(hl) ;get character from buffer inc hl ;increment serial 0 output pointer ex de,hl ;serial 0 output pointer to de-reg ld hl,(s0ibsz) ;get serial 0 input buffer size dec hl ;decrement input buffer size ld bc,(s0ibuf) ;get serial 0 input buffer address add hl,bc ;calc last input buffer address sbc hl,de ;buffer wrap-around? jr nc,..nwa0 ;if not, continue ld e,c ;get serial 0 input buffer address ld d,b ..nwa0: ld (s0optr),de ;update serial 0 output pointer ei ;enable interrupts ret ;done ..wt0: ld hl,s0iwct ;get serial 0 input wait count inc (hl) ;increment input wait count ld hl,s0isph ;get serial 0 input semaphore call wait## ;wait for console input jr ..s0i ;continue ..s1i: di ;disable interrupts ld hl,(s1icnt) ;get serial 1 input count ld a,h or l ;serial 1 input count=0? jr z,..wt1 ;if so, continue dec hl ;decrement serial 1 input count ld (s1icnt),hl ;update serial 1 input count ld hl,(s1optr) ;get serial 1 output pointer ld a,(hl) ;get character from buffer inc hl ;increment serial 1 output pointer ex de,hl ;serial 1 output pointer to de-reg ld hl,(s1ibsz) ;get serial 1 input buffer size dec hl ;decrement input buffer size ld bc,(s1ibuf) ;get serial 1 input buffer address add hl,bc ;calc last input buffer address sbc hl,de ;buffer wrap-around? jr nc,..nwa1 ;if not, continue ld e,c ;get serial 1 input buffer address ld d,b ..nwa1: ld (s1optr),de ;update serial 1 output pointer ei ;enable interrupts ret ;done ..wt1: ld hl,s1iwct ;get serial 1 input wait count inc (hl) ;increment input wait count ld hl,s1isph ;get serial 1 input semaphore call wait## ;wait for console input jr ..s1i ;continue ; seropt: ld a,b ;get channel number or a ;channel number=1? ld a,10h ;get reset external status command jr nz,..s1o ;if channel number=1, continue out (sioacr),a ;else, reset external status in a,(sioacr) ;get sio port a status and 1 shl tbe ;transmit buffer empty? ret z ;if not, done ld a,(s0br) ;else, get serial 0 baud rate code and 1 shl 6 ;cts handshaking requested? jr z,..nhr0 ;if not, continue in a,(sioacr) ;else, get sio port a status and 1 shl cts ;check clear to send status ret z ;if clear to send false, done ..nhr0: ld a,c ;get serial 0 output character out (sioadr),a ;output character ld a,0ffh ;set return code=0ffh ret ;done ..s1o: out (siobcr),a ;reset external status in a,(siobcr) ;get sio port b status and 1 shl tbe ;transmit buffer empty? ret z ;if not, done ld a,(s1br) ;else, get serial 1 baud rate code and 1 shl 6 ;cts handshaking requested? jr z,..nhr1 ;if not, continue in a,(siobcr) ;else, get sio port b status and 1 shl cts ;check clear to send status ret z ;if clear to send false, done ..nhr1: ld a,c ;get serial 1 output character out (siobdr),a ;output character ld a,0ffh ;set return code=0ffh ret ;done ; serout: ld a,b ;get channel number or a ;channel number=1? ld a,10h ;get reset external status command jr nz,..s1o1 ;if channel number=1, continue out (sioacr),a ;else, reset external status in a,(sioacr) ;get sio port a status and 1 shl tbe ;transmit buffer empty? jr z,..s0nr ;if not, continue ld a,(s0br) ;else, get serial 0 baud rate code and 1 shl 6 ;cts handshaking requested? jr z,..nhr2 ;if not, continue in a,(sioacr) ;else, get sio port a status and 1 shl cts ;check clear to send status jr z,..s0nr ;if clear to send false, continue ..nhr2: ld a,c ;get serial 0 output character out (sioadr),a ;output character ret ;done ..s0nr: ld a,c ;get serial 0 output character ld (s0ochr),a ;save output character ld de,s0opol ;get serial 0 out poll routine call lnkpol## ;create poll routine ld hl,s0osph ;get serial 0 out semaphore jp wait## ;dispatch if necessary ..s1o1: out (siobcr),a ;reset external status in a,(siobcr) ;get sio port b status and 1 shl tbe ;transmit buffer empty? jr z,..s1nr ;if not, continue ld a,(s1br) ;else, get serial 1 baud rate code and 1 shl 6 ;cts handshaking requested? jr z,..nhr3 ;if not, continue in a,(siobcr) ;else, get sio port b status and 1 shl cts ;check clear to send status jr z,..s1nr ;if clear to send false, continue ..nhr3: ld a,c ;get serial 1 output character out (siobdr),a ;output character ret ;done ..s1nr: ld a,c ;get serial 1 output character ld (s1ochr),a ;save output character ld de,s1opol ;get serial 1 out poll routine call lnkpol## ;create poll routine ld hl,s1osph ;get serial 1 out semaphore jp wait## ;dispatch if necessary ; s0opol: ;serial 0 output poll routine dw 0 ;successor link pointer dw 0 ;predecessor link pointer ; ld a,10h ;get reset external status command out (sioacr),a ;reset external status in a,(sioacr) ;get sio port a status and 1 shl tbe ;transmit buffer empty? ret z ;if not, done ld a,(s0br) ;else, get serial 0 baud rate code and 1 shl 6 ;cts handshaking requested? jr z,..nhr ;if not, continue in a,(sioacr) ;else, get sio port a status and 1 shl cts ;check clear to send status ret z ;if clear to send false, done ..nhr: ld a,(s0ochr) ;get serial 0 output character out (sioadr),a ;output character ld hl,s0opol ;get serial 0 out poll routine call unlink## ;unlink poll routine ld hl,s0osph ;get serial 0 out semaphore jp signal## ;signal process as ready ; s1opol: ;serial 1 output poll routine dw 0 ;successor link pointer dw 0 ;predecessor link pointer ; ld a,10h ;get reset external status command out (siobcr),a ;reset external status in a,(siobcr) ;get sio port b status and 1 shl tbe ;transmit buffer empty? ret z ;if not, done ld a,(s1br) ;else, get serial 1 baud rate code and 1 shl 6 ;cts handshaking requested? jr z,..nhra ;if not, continue in a,(siobcr) ;else, get sio port b status and 1 shl cts ;check clear to send status ret z ;if clear to send false, done ..nhra: ld a,(s1ochr) ;get serial 1 output character out (siobdr),a ;output character ld hl,s1opol ;get serial 1 out poll routine call unlink## ;unlink poll routine ld hl,s1osph ;get serial 1 out semaphore jp signal## ;signal process as ready ; sioisr:: ld (intsp##),sp ;save stack pointer ld sp,intstk## ;set up aux stack pointer push af ;save registers push bc push de push hl call ..s0i1 ;check for serial 0 input call ..s1i1 ;check for serial 1 input pop hl ;restore registers pop de pop bc pop af ld sp,(intsp##) ;restore stack pointer ei ;enable interrupts reti ;done ; ..s0i1: in a,(sioacr) ;get sio port a status bit rda,a ;character available ret z ;if not, done in a,(sioadr) ;get sio port a data character ld hl,s0br ;get serial 0 baud rate code bit 5,(hl) ;inhibit input flag set? ret nz ;if so, done ld c,a ;serial 0 data character to c-reg bit 7,(hl) ;sign bit on baud rate code? jr z,..nad0 ;if not, continue res 7,c ;else, strip sign bit on character ld a,(atnchr##) ;get attention character cp c ;character=attention character? jr nz,..nad0 ;if not, continue ld hl,(s0iptr) ;else, get serial 0 input pointer ld (s0optr),hl ;reset serial 0 output pointer ld hl,0 ld (s0icnt),hl ;set serial 0 input count=0 ..nad0: ld hl,(s0ibsz) ;get serial 0 input buffer size ld de,(s0icnt) ;get serial 0 input count inc de ;increment serial 0 input count or a ;clear carry flag sbc hl,de ;serial 0 input buffer full? ret c ;if so, done ld (s0icnt),de ;else, update serial 0 input count ld hl,(s0iptr) ;get serial 0 input pointer ld (hl),c ;store input character in buffer inc hl ;increment input pointer ex de,hl ;de=input pointer/hl=buffer size ld hl,(s0ibsz) ;get serial 0 input buffer size dec hl ;decrement input buffer size ld bc,(s0ibuf) ;get serial 0 input buffer address add hl,bc ;calc last input buffer address sbc hl,de ;buffer wrap-around? jr nc,..nwa2 ;if not, continue ld e,c ;get serial 0 input buffer address ld d,b ..nwa2: ld (s0iptr),de ;update serial 0 input pointer ld de,s0iwct ;get serial 0 input wait count ld hl,s0isph ;get serial 0 input semaphore call ..sigc ;signal if necessary jr ..s0i1 ;continue ; ..s1i1: in a,(siobcr) ;get sio port b status bit rda,a ;character available ret z ;if not, done in a,(siobdr) ;get sio port b data character ld hl,s1br ;get serial 1 baud rate code bit 5,(hl) ;inhibit input flag set? ret nz ;if so, done ld c,a ;serial 1 data character to c-reg bit 7,(hl) ;attention detection flag set? jr z,..nad1 ;if not, continue res 7,c ;else, strip sign bit on character ld a,(atnchr##) ;get attention character cp c ;character=attention character? jr nz,..nad1 ;if not, continue ld hl,(s1iptr) ;else, get serial 1 input pointer ld (s1optr),hl ;reset serial 1 output pointer ld hl,0 ld (s1icnt),hl ;set serial 1 input count=1 ..nad1: ld hl,(s1ibsz) ;get serial 1 input buffer size ld de,(s1icnt) ;get serial 1 input count inc de ;increment serial 1 input count or a ;clear carry flag sbc hl,de ;serial 1 input buffer full? ret c ;if so, done ld (s1icnt),de ;else, update serial 1 input count ld hl,(s1iptr) ;get serial 1 input pointer ld (hl),c ;store input character in buffer inc hl ;increment input pointer ex de,hl ;de=input pointer/hl=buffer size ld hl,(s1ibsz) ;get serial 1 input buffer size dec hl ;decrement input buffer size ld bc,(s1ibuf) ;get serial 1 input buffer address add hl,bc ;calc last input buffer address sbc hl,de ;buffer wrap-around? jr nc,..nwa3 ;if not, continue ld e,c ;get serial 1 input buffer address ld d,b ..nwa3: ld (s1iptr),de ;update serial 1 input pointer ld de,s1iwct ;get serial 1 input wait count ld hl,s1isph ;get serial 1 input semaphore call ..sigc ;signal if necessary jr ..s1i1 ;continue ..sigc: ld a,(de) ;get serial input wait count or a ;serial input wait count=0? ret z ;if so, done dec a ;decrement serial input wait count ld (de),a ;update serial input wait count jp signal## ;signal process as ready ; sersbr: ld a,b ;get channel number ld hl,s0br ;get serial 0 baud rate code or a ;channel number=0? jr z,..com1 ;if so, continue ld hl,s1br ;else, get serial 1 baud rate code ..com1: ld (hl),c ;save baud rate code ld a,c ;get requested baud rate code and 0fh ;extract relevant bits ld c,a ;update requested baud rate code ld a,b ;get channel number or a ;channel number=0? ld a,(baudrt) ;get baud rate register value jr z,..ch0 ;if channel number=0, continue and 0fh ;else, strip upper four bits ld b,a ;baud rate register value to b-reg ld a,c ;get requested baud rate code add a,a ;shift baud rate code to msn add a,a add a,a add a,a or b ;combine with baud rate register jr ..com2 ;continue ..ch0: and 0f0h ;strip lower four bits or c ;combine with baud rate register ..com2: out (siobrr),a ;set baud rate generator register ld (baudrt),a ;update baud rate register value ret ;done ; serrbr: ld hl,s0br ;get serial 0 baud rate ld a,b ;get channel number or a ;channel number=0? jr z,..com5 ;if so, continue ld hl,s1br ;else, get serial 1 baud rate ..com5: ld a,(hl) ;get current baud rate code ret ;done ; sersmc: ld a,0eah ;get write register 5 control word and not 82h ;strip rts/cts control bits bit 7,c ;rts requested? jr z,..nrts set 1,a ;if so, set rts bit ..nrts: bit 6,c ;dtr requested? jr z,..ndtr set 7,a ;if so, set dtr bit ..ndtr: ld d,a ;requested modem controls to d-reg ld c,sioacr ;get sio port a control register ld a,b ;get channel number or a ;channel number=0? jr z,..com3 ;if so, continue ld c,siobcr ;get sio port b control register ..com3: ld a,5 ;get write register 5 di ;disable interrupts out (c),a ;select write register 5 out (c),d ;output control word ei ;enable interrupts ret ;done ; serrmc: ld c,sioacr ;get sio port a control register ld a,b ;get channel number or a ;channel number=0? jr z,..com4 ;if so, continue ld c,siobcr ;get sio port b control register ..com4: ld a,10h ;get reset external status command out (c),a ;reset external status in d,(c) ;get sio modem status xor a ;clear return vector bit cts,d ;cts set? jr z,..ncts ;if not, continue set 7,a ;else, set cts bit ..ncts: bit dcd,d ;dcd set? ret z ;if not, done set 5,a ;else, set dcd bit ret ;done ; end  set 7,a ;if so, set dtr bit ..ndtr: ld d,a ;requested modem controls to d-reg ld c,sioacr ;get sio port a control register ld a,b ;get channel number or a ;channel number=0? jr z,..com3 ;if so, continue ld c,siobcr ;get sio port b control register ..com3: ld a,5 ;get write register 5 di ;disable interrupts out (c),a ;select write register 5 out (c),d ;output control word ei ;enable interrupts ret ;done ; serrmc: ld c,sioacr ;get sio port a control regist title TurboDOS operating system - super six sign on message ; name ('usrsom') ;module id ; dseg ; USRSOM:: DB 0DH,0AH,'Advanced Digital Corp. Super Six up.' DB '$' end SQMLT96 AR;S6MLT8 EN HARDTBLSELPRINT M} CPMSUP ELwLSTETX AC5 title TURBODOS OPERATING SYSTEM - ADC CONSOLE DRIVER .z80 ; name ('CONDR') ;module id ; include DREQUATE.LIB ;driver symbolic equivalences ; public conbr ; dseg ;locate in data area ; ffchr:: db aff ;form feed character initc: db 0 ;init complete flag clsstr:: ;clear screen string db 0ch,1ah,1bh,0aah,80h,80h,80h,80h ; cseg ;locate in program area ; condr@:: ld a,e ;get function no sub 2 ;function number = 2? jp m,serial## ;no, go on imediately if 0 or 1. jr z,conout ;yes, output ediately if 0 or 1. sub 6 ;function number=8? jr z,conso ;if so, error shift out dec a ;function number=9? jr z,consi ;if so, error shift in jp serial## ;else, continue ; conout: ;console output character routine ld hl,initc ;get initialization complete flag ld a,(hl) or a ;initialization complete flag set? jr nz,..cdrv ;if so, skip console initialization ; dec (hl) ;set initialization complete flag push de ;save function number push bc ;save channel number/character ld e,3 ;get set baud rate function conbr equ $+1 ld c,08eh ;set default console baud rate call serial## ;and do it pop bc ;restore channel number/character pop de ;restore function number ld a,(ffchr) ;get form feed character or a ;form feed character=0? jp z,serial## ;if so, continue push de ;save function number push bc ;save channel number/character ld c,a ;form feed character to c-reg call ..cdrva ;output form feed pop bc ;restore channel number/character pop de ;restore function number jp serial## ;and exit ; ..cdrv: ld a,(ffchr) ;do we have a ff char defined or a jp z,serial## ;leave if not cp c ;otherwise if outgoing char a ff jp nz,serial## ;leave if not ..cdrva: ld hl,clsstr ;otherwise get clear screen string address ..cdrvl: ld a,(hl) ;get char to send and 7fh ;clear parity bit ld c,a ;get set to send it push bc push de push hl call serial## ;send char pop hl pop de pop bc ld a,(hl) ;test if last char bit 7,a ret nz ;return if true inc hl ;else do more jr ..cdrvl ; conso: ;error message pre & post call consi: call dms## ;position to next line db acr,alf+80h ret ;done ; end hr) ;get form feed character or a ;form feed character=0? jp z,serial## ;if so, continue push de ;save function number push bc ;save channel number/character ld c,a ;form feed character to c-reg call ..cdrva ;output form feed pop bc ;restore channel number/character pop de ;restore function number jp serial## ;and exit ; ..cdrv: ld a,(ffchr) ;do we have a ff char defined or a jp z,serial## ;leave if not cp c ;otherwise if outgoing char a ff jp nz,serial## ;leave if not ..cdrva: ld hl,clsstr ;otherwise get clear screen string address ..cdrvl: ld a,(hl) ;get char to send and 7fh ;clear parity bit ld c,a ;get set to send it push bc push de push hl call serial## ;send char pop hl pop; ; ASCII EQUIVALENCES ; anul equ 00h ;NULL asoh equ 01h ;SOH astx equ 02h ;STX aetx equ 03h ;ETX aeot equ 04h ;EOT aenq equ 05h ;ENQ aack equ 06h ;ACK abel equ 07h ;BELL abs equ 08h ;BS aht equ 09h ;HT alf equ 0ah ;LF avt equ 0bh ;VT aff equ 0ch ;FF acr equ 0dh ;CR aso equ 0eh ;SO asi equ 0fh ;SI adle equ 10h ;DLE adc1 equ 11h ;DC1 adc2 equ 12h ;DC2 adc3 equ 13h ;DC3 adc4 equ 14h ;DC4 anak equ 15h ;NAK asyn equ 16h ;SYN aetb equ 17h ;ETB acan equ 18h ;CAN aem equ 19h ;EM asub equ 1ah ;SUB aesc equ 1bh ;ESC afs equ 1ch ;FS ags equ 1dh ;GS ars equ 1eh ;RS aus equ 1fh ;US asp equ 20h ;SPACE arub equ 7fh ;RUBOUT (DEL) ; Supports my drivers (K.A.) nul equ 00h ;NULL soh equ 01h ;SOH stx equ 02h ;STX etx equ 03h ;ETX eot equ 04h ;EOT enq equ 05h ;ENQ ack equ 06h ;ACK bel equ 07h ;BELL bs equ 08h ;BS ht equ 09h ;HT lf equ 0ah ;LF vt equ 0bh ;VT ff equ 0ch ;FF cr equ 0dh ;CR so equ 0eh ;SO si equ 0fh ;SI dle equ 10h ;DLE dc1 equ 11h ;DC1 dc2 equ 12h ;DC2 dc3 equ 13h ;DC3 dc4 equ 14h ;DC4 nak equ 15h ;NAK syn equ 16h ;SYN etb equ 17h ;ETB can equ 18h ;CAN em equ 19h ;EM sub equ 1ah ;SUB esc equ 1bh ;ESC fs equ 1ch ;FS gs equ 1dh ;GS rs equ 1eh ;RS us equ 1fh ;US spc equ 20h ;SPACE rub equ 7fh ;RUBOUT (DEL) ; wboot equ 0000h ;WARM START ENTRYPOINT iobyte equ 0003h ;I/O CONFIGURATION BYTE curdrv equ 0004h ;CURRENT DEFAULT DRIVE opsysc equ 0005h ;OPERATING SYSTEM ENTRYPOINT (CP/M) opsyst equ 0050h ;OPERATING SYSTEM ENTRYPOINT (TDOS) tfcb equ 005ch ;DEFAULT FILE CONTROL BLOCK tbuf equ 0080h ;DEFAULT DISK BUFFER ADDRESS tpa equ 0100h ;TRANSIENT PROGRAM AREA BASE ; .phase 0 ;WORKING STORAGE RELATIVE TO 0 ; pdrdp: ;PD REQUEST DESCRIPTOR PACKET pdrfcn: ds 1 ;PD REQUEST FUNCTION NUMBER pdrdrv: ds 1 ;PD REQUEST DRIVE NUMBER pdrtrk: ds 2 ;PD REQUEST TRACK NUMBER pdrsec: ds 2 ;PD REQUEST SECTOR NUMBER pdrsc: ds 2 ;PD REQUEST SECTOR COUNT pdrtc: ds 2 ;PD REQUEST TRANSFER COUNT pdrdma: ds 2 ;PD REQUEST DMA ADDRESS pdrdst: ds 2 ;PD REQUEST DRIVE SPEC TABLE ADDR pdrlen equ $-pdrdp ;PD REQUEST DESCRIPTOR PACKET LENGTH dsknfo: ;DISK TYPE INFORMATION blksiz: ds 1 ;BLOCK SIZE nmblks: ds 2 ;NUMBER OF BLOCKS nmbdir: ds 1 ;NUMBER OF DIRECTORY BLOCKS secsiz: ds 1 ;PHYSICAL SECTOR SIZE (2^N*128) sectrk: ds 2 ;PHYSICAL SECTORS PER TRACK trkdsk: ds 2 ;PHYSICAL TRACKS PER DISK restrk: ds 2 ;NUMBER OF RESERVED TRACKS dnfol equ $-dsknfo ;DISK INFO LENGTH ; .dephase h ;DEFAULT FILE CONTROL BLOCK tbuf equ 0080h ;DEFAULT DISK BUFFER ADDRESS tpa equ 0100h ;TRANSIENT PROGRAM AREA BASE ; .phase 0 ;WORKING STORAGE RELATIVE TO 0 ; pdrdp: ;PD REQUEST DESCRIPTOR PACKET pdrfcn: ds 1 ;PD REQUEST FUNCTION NUMBER pdrdrv: ds 1 ;PD REQUEST DRIVE NUMBER pdrtrk: ds 2 ;PD REQUEST TRACK NUMBER pdrsec: ds 2 ;PD REQUEST SECTOR NUMBER pdrsc: ds 2 ;PD REQUEST SECTOR COUNT pdrtc: ds 2 ;PD REQUEST TRANSFER COUNT pdrdma: ds 2 ;PD REQUEST DMA ADDRESS pdrdst: ds 2 ;PD REQUEST DRI .xlist .xcref ; ; ASCII EQUIVALENCES ; The Ron Raikes way anul equ 00h ;NULL asoh equ 01h ;SOH astx equ 02h ;STX aetx equ 03h ;ETX aeot equ 04h ;EOT aenq equ 05h ;ENQ aack equ 06h ;ACK abel equ 07h ;BELL abs equ 08h ;BS aht equ 09h ;HT alf equ 0ah ;LF avt equ 0bh ;VT aff equ 0ch ;FF acr equ 0dh ;CR aso equ 0eh ;SO asi equ 0fh ;SI adle equ 10h ;DLE adc1 equ 11h ;DC1 adc2 equ 12h ;DC2 adc3 equ 13h ;DC3 adc4 equ 14h ;DC4 anak equ 15h ;NAK asyn equ 16h ;SYN aetb equ 17h ;ETB acan equ 18h ;CAN aem equ 19h ;EM asub equ 1ah ;SUB aesc equ 1bh ;ESC afs equ 1ch ;FS ags equ 1dh ;GS ars equ 1eh ;RS aus equ 1fh ;US asp equ 20h ;SPACE arub equ 7fh ;RUBOUT (DEL) ; extras to support my drivers (K.A.) nul equ 00h ;NULL soh equ 01h ;SOH stx equ 02h ;STX etx equ 03h ;ETX eot equ 04h ;EOT enq equ 05h ;ENQ ack equ 06h ;ACK bel equ 07h ;BELL bs equ 08h ;BS ht equ 09h ;HT lf equ 0ah ;LF vt equ 0bh ;VT ff equ 0ch ;FF cr equ 0dh ;CR so equ 0eh ;SO si equ 0fh ;SI dle equ 10h ;DLE dc1 equ 11h ;DC1 dc2 equ 12h ;DC2 dc3 equ 13h ;DC3 dc4 equ 14h ;DC4 nak equ 15h ;NAK syn equ 16h ;SYN etb equ 17h ;ETB can equ 18h ;CAN em equ 19h ;EM sub equ 1ah ;SUB esc equ 1bh ;ESC fs equ 1ch ;FS gs equ 1dh ;GS rs equ 1eh ;RS us equ 1fh ;US spc equ 20h ;SPACE rub equ 7fh ;RUBOUT (DEL) ; ; OPERATING SYSTEM EQUIVALENCES ; wboot equ 0000h ;WARM START ENTRYPOINT iobyte equ 0003h ;I/O CONFIGURATION BYTE curdrv equ 0004h ;CURRENT DEFAULT DRIVE opsysc equ 0005h ;OPERATING SYSTEM ENTRYPOINT (CP/M) opsyst equ 0050h ;OPERATING SYSTEM ENTRYPOINT (TDOS) tfcb equ 005ch ;DEFAULT FILE CONTROL BLOCK tbuf equ 0080h ;DEFAULT DISK BUFFER ADDRESS tpa equ 0100h ;TRANSIENT PROGRAM AREA BASE ; wsfcn equ 0 ;FUNCTION 0 (WARM START) cifcn equ 1 ;FUNCTION 1 (CONSOLE INPUT) cofcn equ 2 ;FUNCTION 2 (CONSOLE OUTPUT) rcifcn equ 3 ;FUNCTION 3 (RAW CONSOLE INPUT) rcofcn equ 4 ;FUNCTION 4 (RAW CONSOLE OUTPUT) lofcn equ 5 ;FUNCTION 5 (LIST OUTPUT) dcfcn equ 6 ;FUNCTION 6 (DIRECT CONSOLE I/O) ribfcn equ 7 ;FUNCTION 7 (RETURN I/O BYTE) sibfcn equ 8 ;FUNCTION 8 (SET I/O BYTE) pbfcn equ 9 ;FUNCTION 9 (PRINT BUFFER) cibfcn equ 10 ;FUNCTION 10 (CONSOLE IN BUFFERED) csfcn equ 11 ;FUNCTION 11 (CONSOLE STATUS) rvnfcn equ 12 ;FUNCTION 12 (RETURN VERSN NUMBER) rdsfcn equ 13 ;FUNCTION 13 (RESET DISK SYSTEM) selfcn equ 14 ;FUNCTION 14 (SELECT DISK) offcn equ 15 ;FUNCTION 15 (OPEN FILE) cffcn equ 16 ;FUNCTION 16 (CLOSE FILE) sfffcn equ 17 ;FUNCTION 17 (SEARCH FOR 1ST FILE) snffcn equ 18 ;FUNCTION 18 (SEARCH FOR NEXT FILE) dffcn equ 19 ;FUNCTION 19 (DELETE FILE) rsffcn equ 20 ;FUNCTION 20 (READ SEQUENTIAL FILE) wsffcn equ 21 ;FUNCTION 21 (WRITE SEQ FILE) mffcn equ 22 ;FUNCTION 22 (MAKE FILE) rffcn equ 23 ;FUNCTION 23 (RENAME FILE) rlifcn equ 24 ;FUNCTION 24 (RETURN LOGIN VECTOR) rcdfcn equ 25 ;FUNCTION 25 (RETURN CURRENT DISK) sdfcn equ 26 ;FUNCTION 26 (SET DMA) ; wpdfcn equ 28 ;FUNCTION 28 (WRITE PROTECT DISK) rrofcn equ 29 ;FUNCTION 29 (RETURN R/O VECTOR) sfafcn equ 30 ;FUNCTION 30 (SET FILE ATTRIBUTES) dpbfcn equ 31 ;FUNCTION 31 (DISK PARAMETER BLOCK) srufcn equ 32 ;FUNCTION 32 (SET/RETURN USER) rrffcn equ 33 ;FUNCTION 33 (READ RANDOM FILE) wrffcn equ 34 ;FUNCTION 34 (WRITE RANDOM FILE) cfsfcn equ 35 ;FUNCTION 35 (COMPUTE FILE SIZE) srrfcn equ 36 ;FUNCTION 36 (SET RANDOM RECORD) rdfcn equ 37 ;FUNCTION 37 (RESET DRIVE) ; lkrfcn equ 42 ;FUNCTION 42 (LOCK RECORD) frrfcn equ 43 ;FUNCTION 43 (FREE RECORD) sscfcn equ 44 ;FUNCTION 44 (SET SECTOR COUNT) ; dfsfcn equ 46 ;FUNCTION 46 (DISK FREE SPACE) chnfcn equ 47 ;FUNCTION 47 (CHAIN TO PROGRAM) ; dt1fcn equ 104 ;FUNCTION 104 (SET DATE/TIME) dt2fcn equ 105 ;FUNCTION 105 (RETURN DATE/TIME) ; rsnfcn equ 107 ;FUNCTION 107 (RETURN S/N) srcfcn equ 108 ;FUNCTION 108 (SET/RETURN CODE) ; srtfcn equ 110 ;FUNCTION 110 (SET/RET TERMINATOR) pbcfcn equ 111 ;FUNCTION 111 (PRINT BLOCK TO CON) pblfcn equ 112 ;FUNCTION 112 (PRINT BLOCK TO LIST) ; mqfcn equ 134 ;FUNCTION 134 (MAKE QUEUE) oqfcn equ 135 ;FUNCTION 135 (OPEN QUEUE) dqfcn equ 136 ;FUNCTION 136 (DELETE QUEUE) urqfcn equ 137 ;FUNCTION 137 (UNCOND READ QUEUE) crqfcn equ 138 ;FUNCTION 138 (CONDIT READ QUEUE) uwqfcn equ 139 ;FUNCTION 139 (UNCOND WRITE QUEUE) cwqfcn equ 140 ;FUNCTION 140 (CONDIT WRITE QUEUE) dlyfcn equ 141 ;FUNCTION 141 (DELAY) dspfcn equ 142 ;FUNCTION 142 (DISPATCH) ttpfcn equ 143 ;FUNCTION 143 (TERMINATE TRANSIENT) ; pfnfcn equ 152 ;FUNCTION 152 (PARSE FILE NAME) rcnfcn equ 153 ;FUNCTION 153 (RET CONSOLE NUMBER) ; dt3fcn equ 155 ;FUNCTION 155 (RETURN DATE/TIME) ; rosfcn equ 0 ;FUNCTION 0 (RESET O/S) ctpfcn equ 1 ;FUNCTION 1 (CREATE/TERM PROCESS) dpfcn equ 2 ;FUNCTION 2 (DISPATCH PROCESS) amfcn equ 3 ;FUNCTION 3 (ALLOCATE MEMORY) dmfcn equ 4 ;FUNCTION 4 (DE-ALLOCATE MEMORY) smfcn equ 5 ;FUNCTION 5 (SEND MESSAGE) rmfcn equ 6 ;FUNCTION 6 (RECEIVE MESSAGE) sesfcn equ 7 ;FUNCTION 7 (SET ERROR SERVICE) serfcn equ 8 ;FUNCTION 8 (SET ERROR RETURN) sdtfcn equ 9 ;FUNCTION 9 (SET DATE/TIME) rdtfcn equ 10 ;FUNCTION 10 (RETURN DATE/TIME) rdmfcn equ 11 ;FUNCTION 11 (REBUILD DISK MAP) roufcn equ 12 ;FUNCTION 12 (RETURN ORIGIN/UNIT) scffcn equ 13 ;FUNCTION 13 (SET COMPATABILITY) logfcn equ 14 ;FUNCTION 14 (LOG ON/OFF) lffcn equ 15 ;FUNCTION 15 (LOAD FILE) adffcn equ 16 ;FUNCTION 16 (ACTIVATE DO FILE) aldfcn equ 17 ;FUNCTION 17 (AUTO LOAD DISABLE) sclfcn equ 18 ;FUNCTION 18 (SEND COMMAND LINE) ravfcn equ 19 ;FUNCTION 19 (RETURN ALV INFO) rdpfcn equ 20 ;FUNCTION 20 (RETURN DISK PARMS) srsfcn equ 21 ;FUNCTION 21 (SET/RET DISK STATUS) pdafcn equ 22 ;FUNCTION 22 (PHYSICAL DISK ACCESS) sbpfcn equ 23 ;FUNCTION 23 (SET BUFFER PARMS) rbpfcn equ 24 ;FUNCTION 24 (RETURN BUFFER PARMS) lfdfcn equ 25 ;FUNCTION 25 (LOCKOUT/FREE DRIVE) ffbfcn equ 26 ;FUNCTION 26 (FLUSH/FREE BUFFERS) srpfcn equ 27 ;FUNCTION 27 (SET/RET PRINT MODE) eopfcn equ 28 ;FUNCTION 28 (SIGNAL END OF PRINT) srdfcn equ 29 ;FUNCTION 29 (SET/RET DE-SPOOL) qpffcn equ 30 ;FUNCTION 30 (QUEUE PRINT FILE) flbfcn equ 31 ;FUNCTION 31 (FLUSH LIST BUFFER) nlofcn equ 32 ;FUNCTION 32 (NETWORK LIST OUT) rcfcn equ 33 ;FUNCTION 33 (REMOTE CONSOLE) ccsfcn equ 34 ;FUNCTION 34 (COMM CHANNEL STATUS) ccifcn equ 35 ;FUNCTION 35 (COMM CHANNEL INPUT) ccofcn equ 36 ;FUNCTION 36 (COMM CHANNEL OUTPUT) scbfcn equ 37 ;FUNCTION 37 (SET COMM BAUD RATE) rcbfcn equ 38 ;FUNCTION 38 (RETURN COMM BAUD) smcfcn equ 39 ;FUNCTION 39 (SET COMM MODEM CTRL) rmcfcn equ 40 ;FUNCTION 40 (RET COMM MODEM CTRL) usrfcn equ 41 ;FUNCTION 41 (USER DEFINED) rddfcn equ 42 ;FUNCTION 42 (REBUILD DISK DIR) smbfcn equ 43 ;FUNCTION 43 (SELECT MEMORY BANK) .cref .list ETURN BUFFER PARMS) lfdfcn equ 25 ;FUNCTION 25 (LOCKOUT/FREE DRIVE) ffbfcn equ 26 ;FUNCTION 26 (FLUSH/FREE BUFFERS) srpfcn equ 27 ;FUNCTION 27 (SET/RET PRINT MODE) eopfcn equ 28 ;FUNCTION 28 (SIGNAL END OF PRINT) srdfcn equ 29 ;FUNCTION 29 (SET/R title turbodos operating system hard disk format utility .z80 ; version: 05/22/84 K.A. name ('FMTHRD') ;module id include EQUATE.LIB ;symbolic equivalences interleave equ 6 ; interleave flag vfy equ 1 ; verify flag ftrack equ 2 ; format one track flag res equ 3 ; format reserve tracks flag dseg ; locate in data area headno: db 0 ;head number pdrdp: ;pd request packet pdrfcn: db 0 ;pd request function pdrdrv: db 0 ;pd request drive number pdrtrk: dw 0 ;pd request track number pdrsec: dw 0 ;pd request sector number pdrsc: dw 0 ;pd request sector count pdrtc: dw 0 ;pd request transfer count pdrdma: dw 0 ;pd request dma address pdrdst: dw 0 ;pd request dst address vfydst: ;verify dst area blksiz: db 0 ;block size nmblks: dw 0 ;number of allocation blocks nmbdir: db 0 ;number of directory blocks secsiz: db 0 ;sector size sectrak:dw 0 ;sectors/track trkdsk: dw 0 ;tracks/disk restrk: dw 0 ;reserved tracks chrptr: dw 0 ;character pointer trknum: dw 0 ;track number for single format trkoff: dw 0 ;track offset optflg: db 0 ;option flags trkcnt: dw 0 ;track count seccnt: dw 0 ;sector count headct: db 0 ;head count sectrk: db 0 ; number of sectors nmbtrk: dw 0 ; format number of tracks nmbhds: db 0 ; format number of heads typdrv: db 0 ; drive type inter: dw interleave ; interleave sechds: dw 0 ; sector per heads curdriv:db 'Z:' ds 50 ; stack area stack: ; top of stack area itable: ds 512 ; interleave table cseg start: ld sp,stack ; use local stack call dms ;display message db cr,lf db 'Advanced Digital hard disk format utility' db cr,lf+80h ld c,roufcn call opsyst bit 7,b ; must be priviledged jp nz,..ok ; jump if privledged call dms ;display message db cr,lf,lf,bel dc 'NON-privileged user' jp wboot ; done ..ok: ld a,(tfcb) ; get default fcb drive or a jp nz,..ok2 ; jump if drive specified call dms ; display message db cr,lf,lf,bel dc 'no format drive specified' jp wboot ;continue ..ok2: dec a ; make base 0 ld (pdrdrv),a ; save drive number call getopt ; get options ld a,(pdrdrv) call lokdrv ; lockout drive jp z,..ok3 ; jump if drive locked call dms ; display message db cr,lf,lf,bel dc 'unable to lockout format drive' jp wboot ; continue ..ok3: ld c,43 ; are we in bank 1 ? ld e,-1 call opsyst cp 0 jr z,getdrv ; get drive information call dms db cr,lf,bel db 'To format, you must be attached to the master and on bank 0' db cr,lf+80h jp wboot ; cannot execute from bank 1 getdrv: ld a,(pdrdrv) ; get drive number ld e,a ld c,rdpfcn ; get physical disk information call opsyst ld (sechds),hl ; save it ld (trkoff),bc ; save track offset ld (nmbtrk),de ; save number of tracks cp 1 ; 256 byte sectors ? ld a,0 ; clear typ drv ld (typdrv),a ld b,17 ; sectors per surface (512) jr nz,..s512 ; skip if not ld a,80h ; set up for 256 byte sectors ld (typdrv),a ld b,33 ; sectors per surface (256) ..s512: call chk ; check for sectors per head jr nz,report ; sectoring determined report it ld b,16 ld a,(typdrv) or a jr z,..512 ld b,32 ..512: call chk jr nz,report call dms db cr,lf,lf dc 'Can not determine sectors per head, Please check your disk spec table' jp wboot ; exit chk: ld a,b ld (sectrk),a ; set sectors per track ld c,a ; make 16 bit ld b,0 ld hl,(sechds) ; get value xor a ; zero heads and clear carry ..hds: inc a ; head=head+1 ret z ; if a overflows try alternate sectors sbc hl,bc ; divide sectrk by sec per cylinder jr nz,..hds ld (nmbhds),a ; save the number of heads xor -1 ; set good flag ret report: call dms db cr,lf dc 'Hard disk to format is drive ' ld a,(pdrdrv) add a,'A' ld (curdriv),a ; store drive letter call conout ld a,':' call conout call dms db cr,lf dc 'Drive has ' ld hl,(nmbtrk) ;get tracks call decout call dms dc ' tracks and ' ld a,(nmbhds) ld l,a ld h,0 call decout call dms db ' heads' db cr,lf+80h ld hl,(trkoff) ;get track offset xor a ;clear carry adc hl,hl ;check for offset jr z,..nooff call dms dc 'Track offset of ' ld hl,(trkoff) call decout call dms db ' ',cr,lf+80h ..nooff:call dms dc 'Total sectors per head ' ld hl,(sectrk) ld h,0 call decout call dms db cr,lf dc 'Interleave factor of ' ld l,interleave ld h,0 call decout call flshci ; flush console input call dms ;display message db cr,lf,lf dc 'Press to begin ' ..retst:call conin ; test for carriage return or ^c cp cr ; carriage return? jr z,..rdy ; yes jump cp etx ; control c? jp z,wboot ; yes exit call dms ; neither beep db bel+80h jr ..retst ; retest keys ..rdy: ld a,3 ; ready status function ld (pdrfcn),a ; save in packet call xecpda ; test drive for readyness jp nz,..ok4 ; print error message if not ready  call dms ; display message db cr,lf,lf,bel db 'format drive not ready' db cr,lf+80h jp wboot ; continue ..ok4: call dms ; everything ok start to format db cr,lf,lf db 'formatting ... press ^c to abort' db cr,lf,lf+80h ld a,(optflg) ; check for options bit ftrack,a ; format one track only ? jr z,forall ; skip, if not ld a,1 ; one track ld (trkcnt),a ; save track count ld hl,(trknum) ; get the track requested jr forone ; format one track forall: ld hl,(nmbtrk) ; get number of tracks ld (trkcnt),hl ld hl,0 forone: ld a,(optflg) ; check for skip boot tracks bit res,a ; format reserved tracks? jr nz,..norm ; jump if not ld de,(trkoff) ; get offset add hl,de ; add in offset ..norm: ld (pdrtrk),hl ; start with track requested ld a,(nmbhds) ; get number of heads ld (headct),a ; save in head count xor a ; zero a ld (headno),a ; start with head 0 forhds: call trknit ; init track buffer ld a,4 ; format function ld (pdrfcn),a ; save in format packet ..rtry: call xecpda ; format a track using params at pdr jr z,..ok6 ; jump in no errors call dms ; display error message db cr,lf,lf dc 'format' call errcom ; ask for error options jp c,wboot ; exit if abort jr z,..rtry ; retry again ..ok6: call const ; test for input or a ; set flags jr z,..ok7 ; jump if no input call conin ; get input cp etx ; control c? jr nz,..ok6 ; test all input call dms db cr,lf,lf,bel dc 'format aborted' jp wboot ..ok7: ld hl,headno inc (hl) ; point to next head ld hl,headct dec (hl) jp nz,forhds call dms dc '.' ld a,(nmbhds) ; reinit head and track count ld (headct),a xor a ld (headno),a ld hl,(pdrtrk) inc hl ld (pdrtrk),hl ld hl,(trkcnt) dec hl ld (trkcnt),hl ld a,h or l jp nz,forhds call dms db cr,lf dc 'format successful ' ld a,(optflg) bit vfy,a ; verify ? jp z,..x ; skip, if not call dms db cr,lf db 'Verifying... ' db cr,lf+80h ld hl,vfydst ;get verify dst address ld (pdrdma),hl ;set pd request packet dma address ld a,2 ;get return dst function number ld (pdrfcn),a ;set pd request packet function call xecpda ;select verify drive jp z,..vdnr ;if drive not ready, continue ld hl,1 ld (pdrsc),hl ;set pd request sector count ld hl,128 ld a,(secsiz) ;get sector size ..sl: dec a ;decrement sector size jp m,..slx ;if underflow, continue add hl,hl ;else, shift byte count left jr ..sl ;continue ..slx: ld (pdrtc),hl ;set pd request transfer count ld de,itable ;get verify buffer address ld (pdrdma),de ;set pd request packet dma address add hl,de ;calc end of dma address ex de,hl ;end of dma address to de-reg ld hl,(opsysc+1) ;get top of transient program area or a ;clear carry flag sbc hl,de ;sufficient memory for track read? jp c,..ivme ;if not, continue ld a,(optflg) bit ftrack,a ; one track only ? jr z,verall ; skip, if not ld a,1 ld (trkcnt),a ld hl,(trknum) ; verify one track jr verone verall: ld hl,(trkdsk) ;else, get number of tracks/disk ld (trkcnt),hl ;set track count ld hl,0 ;get track 0 verone: ld a,(optflg) ;get options bit res,a ;verify reseved tracks jr nz,..ntskp ;jump if no skip ld de,(trkoff) ;get track offset add hl,de ;add in offset ..ntskp:ld (pdrtrk),hl ;set pd request packet track=0 xor a ;else, get read function ld (pdrfcn),a ;set pd request packet function ..vcl: ld hl,(sectrak) ld (seccnt),hl ;set sector count ld hl,0 ld (pdrsec),hl ;set pd request packet sector=0 call dms dc '.' ..vtl: call xecpda ;read pd request track jr z,..vfyc ;if no errors, continue call dms db cr,lf dc 'verify' call errcom ;process verify error jp c,..errx ;if control c, continue jr z,..vtl ;if carriage return, continue ..vfyc: call const ;else, get console status or a ;character available? jr z,..nca2 ;if not, continue call conin ;else, get console input character cp etx ;character=control c? jr nz,..vfyc ;if not, continue call dms ;else, display message db cr,lf,lf,bel dc 'verify aborted' jp ..errx ;continue ..nca2: ld hl,(pdrsec) ;get pd request sector number inc hl ;increment pd request sector number ld (pdrsec),hl ;update pd request sector number ld hl,(seccnt) ;get sector count dec hl ;decrement sector count ld (seccnt),hl ;update sector count ld a,h or l ;sector count=0? jr nz,..vtl ;if not, continue more: ld hl,(pdrtrk) ;get pd request track number inc hl ;increment pd request track number ld (pdrtrk),hl ;update pd request track number ld hl,(trkcnt) ;get track count dec hl ;decrement head count ld (trkcnt),hl ;update track count ld a,h or l ;track count=0? jp nz,..vcl ;if not, continue call dms ;else, display message db cr,lf,lf dc 'successful verify' jp ..x ;continue ..ivme: call dms ;display message db cr,lf,lf,bel dc 'insufficient memory to verify' jr ..errx ;else, continue ..vdnr: call dms ;display message db cr,lf,lf,bel db 'verify drive not ready' db cr,lf+80h jr ..errx ..x: call dms ;display message db cr,lf+80h ..errx: jp wboot getopt: ld de,tbuf ;get default buffer ld a,(de) ;get buffer count or a ;buffer count=0? ret z ;if so, done ld b,a ;else, buffer count to b-reg ..ssl: inc de ;increment buffer pointer ld a,(de) ;get character from buffer cp ';' ;character=semicolon? jr z,..os ;if so, continue djnz ..ssl ;else, continue ret ;done ..os: ld hl,optflg ; point to option flags dec b ret z inc de ld a,(de) call uprcas cp 'R' ; skip over boot tracks? jr nz,..nskp set res,(hl) jr ..os ..nskp: cp 'V' jr nz,..nver set vfy,(hl) ; set verify flag jr ..os ..nver: cp 'F' jr nz,..os set ftrack,(hl) ; set format track flag call convrt ; get the track number ld (trknum),hl ; save track ret errcom: call dms ;display message dc ' error, drive ' ld a,(pdrdrv) ;get pd request drive add a,'A' ;add ascii bias call conout ;display drive letter ld a,':' ; call conout ;display a colon call dms ;display message dc ', track: ' ld hl,(pdrtrk) ;get pd request track number call decout ;display sorce track number call dms ;display message dc ' (retry, ignore, abort) ' ..cil: call dms ;sound bell db bel+80h call flshci ;flush console input ..csl: call const ;get console status or a ;character available? jr z,..csl ;if not, continue call conin ;else, get console input call uprcas ;force upper case cp 'A' ;character=abort? scf ;set carry flag jr z,..x1 ;if character=control c, continue cp 'R' ;character=retry? jr z,..x1 ;if so, continue cp 'I' ;character=ignore? jr nz,..cil ;if not, continue or a ;else, clear zero flag ..x1: call dms ;display message db cr,lf+80h ret ;done ;create a interleave table trknit: ld bc,(sectrk-1) ;put sectors per track in b ld hl,itable ;point to translat table ld a,-1 ;set a to illegal sector no. ..loop: ld (hl),a ;initialize table to ff inc hl ;point to next value in table djnz ..loop ;fill table xor a ;clear acc ld (itable),a ;set first sector in table to zero ld de,0 ;table index ld b,1 ;sector number ..ilp: ld a,(inter) ;point to interleave factor add a,e ;add interleave factor to index idxchk: ld hl,sectrk ;get table base cp (hl) ;check if illegal subscipt jr c,idxtbl ;jump ovr if within table boundries sub (hl) ;adjust for wrap around idxtbl: ld hl,itable ;point to interleave table ld e,a ;put subscript in e for double add add hl,de ;add index to base address ckuse: ld a,-1 ;all entries initalized to -1? cp (hl) ;check jr z,..savsc ;jump if un-used entry inc de ;entry used, point to next one ld a,e ;pass idx in a to boundry check sbrtn jr idxchk ;jump to check for wrap around ..savsc:ld (hl),b ;save sector no. in table inc b ;point to next sector ld hl,sectrk ;point to sectors per track ld a,b ;put sector # in a cp (hl) ;if sec #=sec per trk then exit jr nz,..ilp ;loop until all sectors done ld hl,itable ; address for format data ld (pdrdma),hl ; init dma address ld a,(headno) ; send head no. in sector ld b,a ; save head number ld a,(sectrk) ; get number of sectors per surface ld (pdrsc),a ; init sector count ld e,a ; make secs per track 16 bit ld d,0 ld hl,0 ; zero sector number ..nxt: add hl,de ; add sectors per track per head djnz ..nxt ; loop head times (b) ld (pdrsec),hl ; save sector number (head) xor a ; clear the high byte of sector count ld (pdrsc+1),a ld a,(typdrv) or a jr z,fmt512 ld hl,256 jr fmtnext fmt512: ld hl,512 fmtnext:ld (pdrtc),hl ; init transfer count ret lokdrv: ld e,a ;format drive to e-reg push de ;save drive ld d,-1 ;d=lock drive flag ld c,lfdfcn ;c=lockout/free drive function call opsyst ;lockout drive pop de ;restore drive number or a ;lockout successful? ret nz ;if not, done ld d,80h ;d=free buffer flag ld c,ffbfcn ;c=flush/free buffers function call opsyst ;flush free drive buffers xor a ;set zero flag ret ;done xecpda: ld de,pdrdp ;get pd request packet address ld c,pdafcn ;c=physical disk access function call opsyst ;perform physical disk access or a ;return code=0? ret ;done flshci: call const ;get console status or a ;character available? ret z ;if not, done call conin ;else ,get console input character jr flshci ;continue decout: ld c,0 ;clear leading zero flag ld de,10000 ;display ten thousands digit call ..do ld de,1000 ;display thousands digit call ..do ld de,100 ;display hundreds digit call ..do ld de,10 ;display tens digit call ..do inc c ;increment leading zero flag ld de,1 ;display units digit ..do: ld b,-1 ;preset quotent or a ;clear carry flag ..dl: inc b ;increment quotent sbc hl,de ;subtract divisor jr nc,..dl ;until underflow add hl,de ;restore underflow ld a,b ;get quotent or a ;quotent=0? jr nz,..dd ;if not, display digit inc c dec c ;leading zero flag set? ret z ;if not, done ..dd: add a,'0' ;add ascii bias call conout ;displat character inc c ;increment leading zero flag ret ;done ;convert ascii-hex-bin-octal characters to hex convrt: ld hl,0 ld (chrptr),de call cnvrt ret cnvrt: push de ld de,(chrptr) ;get char. address inc de ld a,(de) ;get chr ld (chrptr),de pop de call aschex ;convert to hex values ret c ;test for input error cp 10 ;test for radix error ret nc ;jump if error push hl ;copy hl into de pop de ; ld b,9 ;radix=decimal ..add: add hl,de ;add in partial product djnz ..add ld d,0 ;make number 16 bit ld e,a ; add hl,de jr cnvrt ;loop until terminated aschex: call uprcas ;convert to uppercase cp '0' ret c ;ret if < zero cp '9'+1 ;is it numeric? jr c,..numrc ;char is 0 to 9 cp 'A ' ;is it a - f? ret c ;char : to ' ' cp 'F'+1 ;is it > f? ccf ;flip carry sense ret c ;it is > f! sub 7 ;adj for a - f ..numrc:sub '0' ;make binary by removing 30 hex ret dms: ex (sp),hl ;get message address call msghl ;display message ex (sp),hl ;set up return address ret ;done msghl: push af ;save af ..l: ld a,(hl) ;get message byte inc hl ;increment pointer call conout ;display character or a ;last character? jp p,..l ;if not, continue pop af ;else, restore af ret ;done const: push bc ;save registers push de push hl ld c,csfcn ;c=console status function call opsysc ;get console status pop hl ;restore registers pop de pop bc ret ;done conin: push bc ;save registers push de push hl ld c,rcifcn ;c=raw console input function call opsysc ;get console input pop hl ;restore registers pop de pop bc ret ;done conout: push bc ;save registers push de push hl push af  and 7fh ;strip sign bit from character ld e,a ;output character to e-reg ld c,rcofcn ;c=raw console output function call opsysc ;output character to console pop af ;restore registers pop hl pop de pop bc ret ;done uprcas: cp 'A' ;lower case alpha? ret c ;if not, done cp 'Z'+1 ;lower case alpha? ret c ;if not, done sub 20h ;else, force upper case ret ;done end  pop af ;else, restore af ret ;done const: push bc ;save registers push de push hl ld c,csfcn ;c=console status function call opsysc ;get console status pop hl ;restore registers pop de pop bc ret ;done conin: push bc ;save registers push de push hl ld c,rcifcn ;c=raw console input function call opsysc ;get console input pop hl ;restore registers pop de pop bc ret ;done conout: push bc ;save registers push de push hl push af  title TURBODOS OPERATING SYSTEM - DATA TERMINAL READY PRINTER DRIVER subttl copyright 1983 by software 2000, inc. .z80 ; ; copyright 1983 by software 2000, inc. ; converted to MICROSOFT M80 format by ; Advanced Digital Corp. ; ; version: 02/03/83 ; name ('lstcts') ;module id ; include DREQUATE.LIB ;driver symbolic equivalences ; dseg ;locate in data area ; public ctsbr ctsff:: db aff ;form feed character initc: db 0,0,0,0,0,0,0,0 ;initialization complete flags db 0,0,0,0,0,0,0,0 ; cseg ;locate in program area ; lstdr@:: ld hl,initc ;get initialization complete flags push de ;save function number ld e,b ;channel number to de-reg ld d,0 ;double length add hl,de ;index into flags table pop de ;restore function number ld a,(hl) ;get initialization complete flag or a ;initialization complete flag set? call z,..init ;if not, initialize list channel ld a,e ;get function number cp 2 ;function number=2? jr z,lstout ;if so, continue cp 7 ;function number=7? jr z,lstwsr ;if so, continue ret ;else, done ..init: dec (hl) ;set initialization complete flag push de ;save function number push bc ;save channel number/character ctsbr equ $+1 ld c,6eh ;get baud rate code (9600 baud) ld e,3 ;set function number=3 call serial## ;set channel buad rate pop bc ;restore channel number/character pop de ;restore function number ret ;done ; lstwsr: ld a,(ctsff) ;get form feed character ld c,a ;form feed character to c-reg ld e,2 ;set function number=2 ; lstout: jp serial## ;continue ; end unction number ld e,b ;channel number to de-reg ld d,0 ;double length add hl,de ;index into flags table pop de ;restore function number ld a,(hl) ;get initialization complete flag or a ;initialization complete flag set? call z,..init ;if not, initialize list channel ld a,e ;get function number cp 2 ;function number=2? jr z,lstout ;if so, contin title TURBODOS OPERATING SYSTEM - ETX/ACK PRINTER DRIVER subttl copyright 1983 by software 2000, inc. .z80 ; ; copyright 1983 by software 2000, inc. ; converted to MICROSOFT M80 format by ; Advanced Digital Corp. ; ; version: 02/03/83 ; name ('lstetx') ;module id ; include DREQUATE.LIB ;driver symbolic equivalences ; dseg ;locate in data area ; public etxbr etxlen:: db 140 ;character count between etx's etxseq:: db 3 ;max escape sequence length etxff:: db aff ;form feed character chrcnt: db 0,0,0,0,0,0,0,0 ;character count 0,0,0,0,0,0,0,0 seqcnt: db 0,0,0,0,0,0,0,0 ;sequence count 0,0,0,0,0,0,0,0 initc: db 0,0,0,0,0,0,0,0 ;initialization complete flags db 0,0,0,0,0,0,0,0 ; cseg ;locate in program area ; lstdr@:: ld hl,initc ;get initialization complete flags call index ;index into flags table ld a,(hl) ;get initialization complete flag or a ;initialization complete flag set? call z,..init ;if not, initialize list channel ld a,e ;get function number cp 2 ;function number=2? jr z,lstout ;if so, continue cp 7 ;function number=7? jr z,lstwsr ;if so, continue ret ;else, done ..init: dec (hl) ;set initialization complete flag push de ;save function number push bc ;save channel number/character etxbr equ $+1 ld c,7 ;get baud rate code (1200 baud) ld e,3 ;set function number=3 call serial## ;set channel buad rate pop bc ;restore channel number/character pop de ;restore function number ret ;done ; lstwsr: ld a,(etxff) ;get form feed character ld c,a ;form feed character to c-reg ld e,2 ;set function number=2 ; lstout: call ..gcca ;get character count address ld a,(hl) ;get character count ld hl,etxlen ;get character count between etx's cp (hl) ;max character count outstanding? jr c,..out ;if not, continue call ..gsca ;else, get sequence count address ld a,(hl) ;get sequence count or a ;in escape sequence? jr nz,..out ;if so, continue push bc ;else, save output character ld c,aetx ;get etx character call ..sout ;output etx character ..wait: call ..sin ;else, get serial input and 7fh ;strip sign bit sub aack ;character=ack? jr nz,..wait ;if not, wait call ..gcca ;else, get character count address ld (hl),a ;reset character count pop bc ;restore output character ..out: ld a,c ;get output character and 7fh ;strip sign bit cp aesc ;character=escape? jr nz,..nesc ;if not, continue call ..gsca ;else, get sequence count address ld a,(etxseq) ;get max escape sequence length ld (hl),a ;set sequence count ..nesc: call ..sout ;output character call ..gcca ;get character count address inc (hl) ;increment character count call ..gsca ;get sequence count address dec (hl) ;decrement sequence count ret p ;if positive, done inc (hl) ;else, restore count to 0 ret ;done ..sin: push bc ;save channel number/character push de ;save function number ld e,1 ;set function number=1 call serial## ;get serial input jr ..sioc ;continue ..sout: push bc ;save channel number/character push de ;save function number call serial## ;output character ..sioc: pop de ;restore function number pop bc ;restore channel number/character ret ;done ..gcca: ld hl,chrcnt ;get character count table jr index ;continue ..gsca: ld hl,seqcnt ;get sequence count table ; index: push de ;save function number ld e,b ;channel number to de-reg ld d,0 ;double length add hl,de ;index into table pop de ;restore function number ret ;done ; end nt character count call ..gsca ;get sequence count address dec (hl) ;decrement sequence count ret p ;if positive, done inc (hl) ;else, restore count to 0 ret ;done ..sin: push bc ;save channel number/character push de ;save func! title TURBODOS OPERATING SYSTEM - ADC PARALLEL PRINTER DRIVER subttl copyright 1983 by software 2000, inc. .z80 ; ; copyright 1983 by software 2000, inc. ; converted to MICROSOFT M80 format by ; Advanced Digital Corp. ; ; version: 10/03/83 ; name ('LSTPAR') ;module id ; include DREQUATE.LIB ;driver symbolic equivalences ; pio0d equ 4 ;parallel port 0 data port pio0c equ 6 pio1d equ 5 ;parallel port 1 data port pio1c equ 7 ; DSEG ;locate in data area ; parff:: db aff ;form feed character outchr: db 0 ;output character initc: db 0 ;initialization complete flag ; imssph: ;character output semaphore defw 0 ;semaphore count ..imsh: defw ..imsh ;semaphore p/d list head defw ..imsh ; cseg ;locate in program area ; lstdr@:: ld hl,initc ;get initialization complete flag ld a,(hl) or a ;initialization complete flag set? call z,..init ;if not, initialize list channel ld a,e ;get function number cp 2 ;function number=2? jr z,lstout ;if so, continue cp 7 ;function number=7? jr z,lstwsr ;if so, continue ret ;else, done ..init: dec (hl) ;set initialization complete flag ld a,00fh ;put port a in output mode out (pio0c),a ld a,0cfh ;put port b in bit mode out (pio1c),a ld a,01fh ;bits 0-4 input, bits 5-7 output out (pio1c),a ret ;done ; lstwsr: ld a,(parff) ;get form feed character ld c,a ;form feed character to c-reg ; lstout: ld hl,outchr ;get output character ld (hl),c ;save output character ld de,imspol ;get poll routine address call lnkpol## ;create poll routine call imspr ;execute poll routine ld hl,imssph ;get semaphore address jp wait## ;dispatch if necessary ; imspol: ;parallel out poll routine defw 0 defw 0 ; imspr: in a,(pio1d) ;get printer status and 1 ;printer busy? ret z ;if so, done ld a,(outchr) ;get output character out (pio0d),a ;output it ld a,80h ;toggle data strobe out (pio1d),a xor a out (pio1d),a ld hl,imspol ;get poll routine address call unlink## ;unlink poll routine ld hl,imssph ;get semaphore jp signal## ;signal process as ready ; end t (pio1c),a ld a,01fh ;bits 0-4 input, bits 5-7 output out (pio1c),a ret ;done ; lstwsr: ld a,(parff) ;get form feed character ld c,a ;form feed character to c-reg ; lstout: ld hl,outchr ;get output character ld (hl),c ;save output character ld de,imspol ;get poll routine address call lnkpol## ;create poll routine call imspr ;execute poll routine ld hl,imssph ;get semaphore address jp wait## ;dispatch if necessary ; imspol: ;parallel out poll routine defw 0 defw 0 ; imspr: in a,(pio1d) ;get printer status and 1 ;printer busy? ret z ;if so, done ld a,(outchr) ;get output character out (pio0d),a ;output it ld a,80h ;toggle data strobe out (pio1d),a xor a out (pio1d),a ld hl,imspol title TURBODOS OPERATING SYSTEM - XON/XOFF PRINTER DRIVER subttl copyright 1983 by software 2000, inc. .z80 ; ; copyright 1983 by software 2000, inc. ; converted to MICROSOFT M80 format by ; Advanced Digital Corp. ; ; version: 02/03/83 ; name ('lstxon') ;module id ; include DREQUATE.LIB ;driver symbolic equivalences ; dseg ;locate in data area ; public xonbr xonff:: db aff ;form feed character initc: db 0,0,0,0,0,0,0,0 ;initialization complete flags db 0,0,0,0,0,0,0,0 ; cseg ;locate in program area ; lstdr@:: ld hl,initc ;get initialization complete flags push de ;save function number ld e,b ;channel number to de-reg ld d,0 ;double length add hl,de ;index into flags table pop de ;restore function number ld a,(hl) ;get initialization complete flag or a ;initialization complete flag set? call z,..init ;if not, initialize list channel ld a,e ;get function number cp 2 ;function number=2? jr z,lstout ;if so, continue cp 7  ;function number=7? jr z,lstwsr ;if so, continue ret ;else, done ..init: dec (hl) ;set initialization complete flag push de ;save function number push bc ;save channel number/character xonbr equ $+1 ld c,7 ;get baud rate code (1200 baud) ld e,3 ;set function number=3 call serial## ;set channel buad rate pop bc ;restore channel number/character pop de ;restore function number ret ;done ; lstwsr: ld a,(xonff) ;get form feed character ld c,a ;form feed character to c-reg ld e,2 ;set function number=2 ; lstout: call ..sst ;get serial status or a ;character available? jr z,..out ;if not, continue call ..sin ;else, get serial input and 7fh ;strip sign bit cp adc3 ;character=dc3 (xoff)? jr nz,lstout ;if not, wait ..wait: call ..sin ;get serial input and 7fh ;strip sign bit cp adc1 ;character=dc1 (xon)? jr nz,..wait ;if not, wait ..out: jp serial## ;output character ..sst: push bc ;save channel number/character push de ;save function number ld e,0 ;set function number=0 call serial## ;get serial status jr ..ssic ;continue ..sin: push bc ;save channel number/character push de ;save function number ld e,1 ;set function number=1 call serial## ;get serial input ..ssic: pop de ;restore function number pop bc ;restore channel number/character ret ;done ; end acter to c-reg ld e,2 ;set function number=2 ; lstout: call ..sst ;get serial status or a ;character available? jr z,..out ;if not, continue call ..sin ;else, get serial input and 7fh ;strip sign bit cp adc3 ;character=dc3 (xoff)? jr nz,lstout ;if not, wait ..wait: call ..sin ;get serial input and 7fh ;strip sign bit cp adc1 ;character=dc1 (xon)? jr nz,..wait ;if not, wait ..out: jp serial## ;output character ..sst: push bc ;save channel number/character p".z80 title "turbodos vectored interrupt handler (advanced digital super six)" subttl "copyright 1984 by software 2000, inc." ; COPYRIGHT 1984 BY SOFTWARE 2000, INC. ; VERSION: 01/05/84 name ('VECINT') ;MODULE ID include DREQUATE.LIB ;DRIVER SYMBOLIC EQUIVALENCES piobdr equ 05h ;PIO PORT B DATA REGISTER piobcr equ 07h ;PIO PORT B CONTROL REGISTER dseg ;LOCATE IN DATA AREA intmsk: ds 1 ;INTERRUPT MASK isrtbl: ds 16 ;INTERRUPT SERVICE ROUTINE TABLE intsp: ds 2 ;INTERRUPT STACK POINTER SAVE AREA ds 32 ;INTERRUPT STACK AREA intstk equ $ ;TOP OF INTERRUPT STACK AREA common /?init?/ ;LOCATE IN INITIALIZATION AREA icinit::ld hl,piovec##+2 ;GET INTERRUPT VECTOR ADDRESS ld a,l ;GET LSB OF INTERRUPT VECTOR out (piobcr),a ;SET PIO INTERRUPT VECTOR ADDRESS ld hl,pioisr ;GET INTERRUPT SERVICE ADDRESS ld (piovec##+2),hl ;SET INTERRUPT SERVICE VECTOR ld a,0cfh ;GET MODE 3 CONTROL WORD out (piobcr),a ;SET PIO PORT B TO MODE 3 ld a,0ffh ;GET I/O DIRECTION CONTROL WORD out (piobcr),a ;SET PIO PORT B DIRECTION TO INPUT ld a,97h ;GET PIO INTERRUPT CONTROL WORD out (piobcr),a ;ENABLE PIO INTERRUPTS ld a,0ffh ;GET INTERRUPT MASK out (piobcr),a ;MASK ALL INTERRUPTS ld (intmsk),a ;SAVE INTERRUPT MASK ret ;DONE intnit::push psw ;SAVE VECTORED INTERRUPT NUMBER add a,a ;CALC VECTORED INTERRUPT NUMBER * 2 ld c,a ;INTERRUPT NUMBER TO BC-REG ld b,0 ;DOUBLE LENGTH ex de,hl ;INTERRUPT SERVICE ADDR TO DE-REG ld hl,isrtbl ;GET ISR ADDRESS TABLE add hl,bc ;INDEX INTO ISR TABLE ld (hl),e ;STORE ISR ADDRESS IN ISR TABLE inc hl ld (hl),d pop af ;RESTORE VECTORED INTERRUPT NUMBER inc a ;INCREMENT INTERRUPT NUMBER ld b,a ;INTERRUPT NUMBER TO B-REG xor a ;INITIALIZE RESULT VECTOR scf ;SET CARRY FLAG ..sl: adc a,a ;SHIFT CARRY FLAG LEFT djnz ..sl ;INTERRUPT NUMBER + 1 TIMES cpl ;COMPLIMENT RESULT VECTOR ld hl,intmsk ;GET INTERRUPT MASK and (hl) ;RESET INTERRUPT MASK BIT  ld (hl),a ;UPDATE INTERRUPT MASK ld a,97h ;GET PIO INTERRUPT CONTROL WORD out (piobcr),a ;ENABLE PIO INTERRUPTS ld a,(hl) ;GET INTERRUPT MASK out (piobcr),a ;SET PIO INTERRUPT MASK REGISTER ret ;DONE cseg ;LOCATE IN PROGRAM AREA pioisr::ld (intsp),sp ;SAVE STACK POINTER ld sp,intstk ;SET UP AUX STACK POINTER push af ;SAVE REGISTERS push bc push de push hl ..isrl: in a,(piobdr) ;GET VECTORED INTERRUPT STATUS cp -1 ;ANY VECTORED INTERRUPTS PENDING? jr z,..isrx ;IF NOT, CONTINUE ld b,8 ;ELSE, GET MAX NUMBER OF INTERRUPTS ..svcl: rra ;VECTORED INTERRUPT PENDING? jr c,..svcc ;IF NOT, CONTINUE push bc ;ELSE, SAVE INTERRUPT COUNTER push af ;SAVE INTERRUPT STATUS ld a,8 ;GET MAX NUMBER OF INTERRUPTS sub b ;CALC CURRENT INTERRUPT NUMBER add a,a ;CALC CURRENT INTERRUPT NUMBER * 2 ld c,a ;INTERRUPT NUMBER TO BC-REG ld b,0 ;DOUBLE LENGTH ld hl,isrtbl ;GET ISR ADDRESS TABLE add hl,bc ;INDEX INTO ISR TABLE ld e,(hl) ;GET INTERRUPT SERVICE ADDRESS inc hl ld d,(hl) ld hl,..ret ;GET RETURN ADDRESS push hl ;PUSH RETURN ADDRESS ONTO STACK ex de,hl ;INTERRUPT SERVICE ADDR TO HL-REG jp (hl) ;TRANSFER TO INT SERVICE ROUTINE ..ret: di ;DISABLE INTERRUPTS pop af ;RESTORE INTERRUPT STATUS pop bc ;RESTORE INTERRUPT COUNTER ..svcc: djnz ..svcl ;CONTINUE jr ..isrl ;CONTINUE ..isrx: pop hl ;RESTORE REGISTERS pop de pop bc pop af ld sp,(intsp) ;RESTORE STACK POINTER ei ;ENABLE INTERRUPTS reti ;DONE end c ;IF NOT, CONTINUE push bc ;ELSE, SAVE INTERRUPT COUNTER push af ;SAVE INTERRUPT STATUS ld a,8 ;GET MAX NUMBER OF INTERRUPTS sub b ;CALC CURRENT INTERRUPT NUMBER add a,a ;CALC CURRENT INTERRUPT NUMBER * 2 ld c,a ;INTERRUPT NUMBER TO BC-REG ld b,0 ;DOUBLE LENGTH ld hl,isrtbl ;GET ISR ADDRESS TABLE add hl,bc ;INDEX INTO ISR TABLE ld e,(hl) ;GE title TurboDOS operating system - master circuit driver for super slaves .z80 ; name ('mcdss') ;module id ; include DREQUATE.LIB ;system equates ; false equ 0 ;logical equates true equ not false ; sprsix equ true ;true if using SUPER-6 with 4MHZ slaves ; ; Signal table flag equates ; shrtmsg equ 7 ;short message sent sysldd equ 6 ;system loaded to slave systry equ 5 ;tried to load system to slave sndpolf equ 4 ;send poll flag on timeout sndwt equ 3 ;send message waiting rcvpolf equ 2 ;poll for receive slvrqst equ 1 ;slave request bit set slvrdyf equ 0 ;slave ready for transfer ; ; Slave control port bits ; svcrqst equ 3 ;slave service request wrhld equ 0 ;slave write hold status ; ; and masks ; wrhold equ 1 ;write hold rdhold equ 2 ;read hold overrun equ 4 ;overrun error svcrqt equ 8 ;slave service request reset equ 1 ;slave reset bit slvclr equ 8 ;slave clear slvatn equ 2 ;slave atten. int ; cseg ;put into code segment ;  cktdr@:: ld A,C ;get operation code or A ; = 0 jr z,rcvmsg ;receive message dec A ; = 1 jp z,sndmsg ;send message ret ;if here bad command so return rcvmsg: ld A,(slvctr) ;get service counter dec A ;counted down to zero yet jp p,rcver1 ;leave if not inc DE ;else bump pointer to message header inc DE inc DE inc DE ld A,(DE) ;get length of message ld (tranlng),A ;and save it push DE ;save pointer to message header rcvl: ld DE,rcvpol ;link slave poll routine call lnkpol## ld HL,rcvsmph ;and wait for response call wait## call rcvsetup bit slvrdyf,(HL) ;is slave already ready pop HL ;get pointer to message back jr nz,rcvm0 ;leave if flag was set call slvtest ;is slave okay jr c,rcver2 ;leave if error push AF ;save slave request bit dec C ;point to slave data port ld A,15h ;send response to slave out (C),A inc C pop AF ;get request bit back jr nz,rcvm0 ;leave if request is set push HL ;else save pointer to message header call chkstrt jr rcvl ;go back to try again rcvm0: ld A,slvclr ;clear slave control register out (C),A ld B,1 ;set up to receive 1 byte call rcvblk ;go get it jr nz,rcver2 ;leave if error dec HL ;point back at what we received ld A,(HL) ;get it or A ;was it 0 jr z,rcver2 ;is so error so leave ld A,(tranlng) ;get length opsys wants to receive cp (HL) ;is it same as slave wants to send jr c,rcver2 ld B,(HL) ;get amount to receive inc HL ;move buffer pointer up dec B ;dec receive count jr z,rcver2 ;error if no more to receive call rcvblk ;else go get data block jr nz,rcver2 ;error if transfer didn't work call chkstrt ;setup timout for future slave check ld A,(rcvdev) ;get slave no. call failclr ;clear table entry for this slave xor A ;and return with success ret rcver1: ld (slvctr),A ;update slave service counter ld (rcvdev),A ;and receive device no. rcver2: call chkstrt ;setup timout for future slave check ld A,(rcvdev) ;get receive device no. jp slver3 ;and go on chkstrt: ld A,(rcvdev) ;get receive device no. call waitnit ;init wait counter for this slave call sgnlref ;point to flag entry for slave res rcvpolf,(HL) ;clear receive poll bit res slvrdyf,(HL) ;clear slave ready bit bit sndwt,(HL) ;test if send message pending ret z ;return if not res sndwt,(HL) ;else clear send pending bit ld HL,sndsmph ;and signal send message routine jp signal## sndmsg: ex DE,HL ;put address of message buffer into hl inc HL ;and point to message dest. id inc HL inc HL inc HL inc HL ld A,(HL) ;get dest. id dec A ;make it slave no. dec HL ;point to message length inc (HL) ;is message length 0 dec (HL) jp z,slvlod ;leave if so push HL ;save message pointer push AF ;and slave no. ld HL,sncsmph ;wait for other sends call wait## pop AF ;get slave no. back ld (snddev),A ;and update device we're working with snd0: call sndsetup #;init regs bit rcvpolf,(HL) ;do we have a receive poll request jp nz,sndwait ;leave if so bit systry,(HL) ;have we loaded an opsys to this slave jr z,snd1 ;if not send any length message bit sysldd,(HL) ;did opsys take jp z,cntsnd ;leave if not ex (SP),HL ld A,(HL) ;get length of message to send ex (SP),HL cp 8bh ;is it max length jr z,snd1 ;process it if so cp 0ch ;is it short message jp nz,cntsnd ;error exit if not set shrtmsg,(HL) ;else set short message flag snd1: call slvtest ;test if slave is there jp c,slver1 ;skip out if not jr nz,slvreq ;skip out if slave request bit set dec C ;point to data port ld A,6 ;send a 6 out (C),A set slvrdyf,(HL) ;set slave ready bit res sndpolf,(HL) ;clear send poll bit ld DE,sndpol ;link send poll routine call lnkpol## ld A,(snddev) ;init service timer call waitnit ld HL,sndsmph ;and wait until all is ready call wait## call sndsetup res slvrdyf,(HL) ;clear slave ready bit bit sndpolf,(HL) ;test send poll bit jr nz,slver1 ;error out if set ld A,slvclr ;else clear slave out (C),A pop HL ;get pointer to message back ld B,(HL) ;get message length dec B ;decrement it push BC ;and save it ld B,1 ;send message length call sndblk pop BC ;get message length back call z,sndblk ;and send message if no errors jr nz,slver2 ;skip out if errors in transfers call syncsig ;signal done ld A,(snddev) ;reset service timer for this slave call waitnit call sgnlref bit shrtmsg,(HL) ;was it short message jr z,sndgdrtn ;skip if not res shrtmsg,(HL) ;else clear bits res sysldd,(HL) ; opsys loaded res systry,(HL) ; tried to load opsys sndgdrtn: ld A,(snddev) ;clear falure count for this slave call failclr xor A ;and return successful ret ; slvlod: ld C,A ;put slave no. into c push BC ;save it for later call syslod ;try to load slave operating system pop BC ;fix stack ret z ;and exit if no errors ld A,C ;else error out jr slver3 ; slvreq: set slvrqst,(HL) ;set slave request status bit dec C ;point to data port ld A,15h ;and send 15h to slave out (C),A sndwait: set sndwt,(HL) ;set send waiting status bit ld HL,sndsmph ;and wait till ok to go on call wait## jp snd0 ;now go try again syncsig: ld HL,sncsmph ;signal thru now jp signal## ; cntsnd: pop HL ;fix stack call syncsig ;signal this run done call sndsetup ;set up registers jr slverxit ;and go on to exit slver1: pop HL ;clear stack slver2: call syncsig ld A,(snddev) slver3: call rsstp0 ;point to signal table and set flags set slvrdyf,(HL) ; slave ready flag res slvrqst,(HL) ; slave requesting service set systry,(HL) ; tried to load opsys res sysldd,(HL) ; opsys loaded res shrtmsg,(HL) ; short message call failpt ;point to failure table inc (HL) ;and bump counter for this slave slverxit: inc E ;make slave no. = ckt node no. ld A,(ssckt) ;get circuit no. ld D,A ;and put it into d to return it ld A,0ffh ;set return failure flag ret ;and exit syslod: call rsstp0 ;point to signal table ld A,(HL) ;get flags for this slave and 40H ;have we already loaded an opsys to this slave xor 40H ret z ;return if true push HL ;save pointer to signal table call failpt ;point to failure counter ld A,(HL) ;bump it up inc A pop HL ;get hl back ret z ;return if failure counter = 255 set sysldd,(HL) ;else set opsys loaded bit res slvrdyf,(HL) ;clear slave ready bit ld A,(ssckt) ;get slave circuit no. ld H,A ;make up slave default network id ld L,0 ld (ssdid##),HL ;and save in system loader ld A,E ;now make up slave id inc A ld L,A ld (sssid##),HL ;and save in system loader ld HL,ssast ;point to slave system assignment table add HL,DE ld A,(HL) ;get down load suffix ld (ssssl##),A ;and save it in system loader ld A,reset ;reset slave out (C),A ld B,0 ;and wait awhile rstwait: djnz rstwait xor A  ;clear reset out (C),A ld HL,lodbuf ;point to opsys request buffer ld B,0ah call rcvblk ;get slave load request ret nz ;return if there was an error ld A,slvclr ;else clear slave out (C),A ld HL,ssload## ;get address of 1st boot loader ld B,80h call sndblk ;and send it ret nz ;return if it didn't work ld HL,ssblod## ;send load address and size of 2nd loader ld B,4 call sndblk ret nz ;leave if error ld DE,(ssblen##) ;get length of 2nd loader ld B,E ;put length to send in b ld A,E ;correct for even page length or A jr nz,syssndlp dec D syssndlp: push DE call sndblk ;send first block pop DE ret nz ;exit if error in transfer dec D ;more to send? jp p,syssndlp ;go back if so xor A ;else return with success ret ; ;receive poll routine node linkage ; rcvpol: dw 0 dw 0 ld A,(nmbslv) ;get number of slaves or A ;make sure we have some out there ret z ;return if not dec A ;else make it no. of last slave and 0fh ld HL,rcvdev ;point hl to receive device storage inc (HL) ;bump it up cp (HL) ;is past max jr nc,rcvprst ;skip reset if not ld (HL),0 rcvprst: call rcvsetup ;set up registers and point to signal table bit slvrdyf,(HL) ;is slave already ready ret nz ;exit if so bit slvrqst,(HL) ;is slave requesting service already jr nz,rcvp0 ;then skip next test in A,(C) ;read slave status bit svcrqst,A ;is request bit set jr z,rcvp1 ;skip if not rcvp0: res slvrqst,(HL) ;else clear slave request set bit set slvrdyf,(HL) ;set slave ready bit jr rcvp2 ;and skip next rcvp1: call tmrchk ;check if time for slave check ret c ;leave if timer not timed out rcvp2: set rcvpolf,(HL) ;set receive poll flag ld HL,rcvpol ;unlink ourselves call unlink## ld HL,rcvsmph ;and signal receive message handler jp signal## ; ;send poll routine node linkage ; sndpol: dw 0 dw 0 call sndsetup ;set up registers in A,(C) ;get slave status bit svcrqst,A ;is slave service request bit set jr nz,sndp0 ;if so skip next call tmrchk ;else check if time to service anyway ret c ;exit if not set sndpolf,(HL) ;else set send poll bit sndp0: ld HL,sndpol ;unlink send poll routine call unlink## ld HL,sndsmph ;and signal send message handler jp signal## ; slvtest: ld A,slvatn ;set wrd02 bit in slave out (C),A xor A ;and clear it out (C),A ld B,0 ;set time out counter slvtst0: in A,(C) ;is slave in write hold bit wrhld,A jr nz,slvtst1 ;skip out if so djnz slvtst0 ;go back if not timed out yet scf ;else set carry flag ret ;and return in failure slvtst1: dec C ;if slave waiting point to data port in A,(C) ;get response inc C ;point back to control port cp 6 ;is response what we want scf ;set error flag ret nz ;and return if not in A,(C) ;else get control data and svcrqt ;keep request bit ret ;and return successfully ; sndblk: ld d,rdhold ;read hold mask call slvrdy ;wait until ready ret nz dec C ;point to data port sndb0: if sprsix nop ;extra wait time for fast master and slow slave nop nop nop endif nop ;provide some extra time outi ;send byte jr nz,sndb0 ;go back if more jr blkerck ;check for errors ; rcvblk: ld D,wrhold ;set mask to slave write hold call slvrdy ;and wait for slave to be ready to send to us ret nz ;leave if slave not ready dec C ;point to data port rcvb0: if sprsix nop ;extra wait time for fast master and slow slave nop nop nop endif nop ;provide some extra time ini ;get data byte from slave jr nz,rcvb0 ;and go back if more blkerck: inc C ;point back to control port in A,(C) ;get status from slave and overrun ;was there any errors in transfer ret z ;leave if not ld A,0ffh ;else set error flag ret ;and exit ; slvrdy: ld E,0 ;load time counter slvrdy0: in A,(C) ;get slave control port and D ;keep only relevant status bit xor D ;com$plement sense of bit ret z ;will be zero if ready dec E ;not ready so decrement time out count jr nz,slvrdy0 ;try again if not timed out xor A ;else set error return flag dec A ret ;and exit ; waitnit: ld E,A ;make device no 16 bits ld D,0 ld HL,slvtmrtbl ;get table base add HL,DE ;point into table ld A,(ticcnt##) ;set element to tic count ld (HL),A ret ;and return ; tmrchk: push HL ;save hl ld HL,slvtmrtbl ;point to slave service timer table add HL,DE ;and to proper entry ld A,(ticcnt##) ;get present tick count sub (HL) ;find out how much time has elapsed pop HL cp 3CH ;has it been long enough ret ; rcvsetup: ld A,(rcvdev) ;get receive slave no. jr rsstp0 ;and go on to process it sndsetup: ld A,(snddev) ;get send slave no. rsstp0: ld E,A ;make slave no 16 bits ld D,0 ld HL,ssadt ;get base of slave port address table add HL,DE ;point to address of proper slave ld C,(HL) ;get base address for slave inc C ;bump to point to control port sgnlref: ld HL,sgnltbl ;point into nuther table add HL,DE ;proper place for this slave ret ; failclr: ld E,A ;make slave no. 16 bits ld D,0 call failpt ;point to falure table ld (HL),0 ;and clear entry for this slave ret ;and return ; failpt: ld HL,flctrtbl ;point to beginning of failure table add HL,DE ;and now to entry for this slave ret ; dseg ;put into data area ; nmbslv: nmbss@:: ;number of slaves installed db 2 ssckt: ssckt@:: ;default slave circuit number db 0 ssadt: ssadt@:: ;slave port address, default is 70h-8eh db 70h,72h,74h,76h,78h,7ah,7ch,7eh db 80h,82h,84h,86h,88h,8ah,8ch,8eh ssast: ssast@:: ;slave opsys suffix table db ' ' rcvdev: db 0 ;current receive device snddev: db 0 ;current send devece tranlng: ;receive block length db 0 slvctr: db 0 ;slave poll counter ; sgnltbl: ;slave device signal table db 0,0,0,0,0,0,0,0,0,0,0,0,0,0 db 0,0 ; slvtmrtbl: ;slave service timer table db 0,0,0,0,0,0,0,0,0,0,0,0,0,0 db 0,0 ; flctrtbl: ;slave failure counter table db 0,0,0,0,0,0,0,0,0,0,0,0,0,0 db 0,0 ; ;receive message semaphore ; rcvsmph: dw 0 dw rcvsmph+2 dw rcvsmph+2 ; ;send message syncronazation semphore ; sncsmph: dw 1 dw sncsmph+2 dw sncsmph+2 ; ;send message semaphore ; sndsmph: dw 0 dw sndsmph+2 dw sndsmph+2 ; ;operating system load request buffer ; lodbuf: db 0,0,0,0,0,0,0,0,0,0 ; common /?init?/ ;put into initialize area ; cktin@:: ld a,(nmbslv) ;get number of slaves ld (slvctr),a ;and put into service counter ret ;no more init to do end  ' rcvdev: db 0 ;current receive device snddev: db 0 ;current send devece tranlng: ;receive block length db 0 slvctr: db 0 ;slave poll counter ; sgnltbl: ;slave device signal table db 0,0,0,0,0,0,0,0,0,0,0,0,0,0 db 0,0 ; slvtmr.z80 title "Turbodos operating system slave reset processor" subttl "Copyright 1984, software 2000, inc." ; COPYRIGHT 1984, SOFTWARE 2000, INC. ; VERSION: 01/22/84 name ('SLVRES') ;MODULE ID include DREQUATE.LIB ;DRIVER SYMBOLIC EQUIVALENCES dseg ;LOCATE IN DATA AREA slrseq::db us,us,-1,-1,-1 ;SLAVE RESET SEQUENCE slrptr: dw slrseq ;SEQUENCE POINTER cseg ;LOCATE IN PROGRAM AREA slvres::ld hl,(slrptr) ;GET SEQUENCE POINTER ld a,c ;GET CONSOLE CHARACTER and 7fh ;STRIP PARITY cp (hl) ;DOES IT MATCH SEQUENCE? jr nz,..ne ;IF NOT, CONTINUE inc hl ;ELSE, INCREMENT POINTER ld (slrptr),hl ;UPDATE POINTER ld a,(hl) ;GET NEXT CHAR IN SEQUENCE inc a ;END-OF-SEQUENCE? ret nz ;IF NOT, RETURN di ;ELSE, DISABLE INTERRUPTS halt ;HALT ..ne: ld hl,slrseq ;RESET SEQUENCE POINTER ld (slrptr),hl ret ;DONE end  title TURBODOS OPERATING SYSTEM - SUPER SLAVE BANK SWITCHED TPA DRIVER subttl copyright 1983, software 2000, inc. .z80 ; ; copyright 1983, software 2000, inc. ; converted to MICROSOFT format by ; Advanced Digital Corp. ; ; version: 07/01/83 ; name ('SSBNK') ;module id ; include DREQUATE.LIB ;driver symbolic equivalences ; intbas equ 0010h ;interrupt vector base address siovec equ 0020h ;sio interrupt vector ; memctl equ 1dh ;memory control register ; spstat equ 1fh ;slave processor status/ctrl port ; respes equ 1 ;reset parity error status bit ; common /?bank?/ ;locate in common area ; bnknit:: ld (spsave),sp ;save stack pointer ld sp,auxstk ;set up auxilliary stack ld hl,0 ;initialize memory parity bank 0 ld de,0 ld bc,0 ldir ld a,1 ;get bank 1 call selbnk ;select bank 1 ld hl,0 ;initialize memory parity bank 1 ld de,0 ld bc,0 ldir ld a,1 shl respes ;get reset parity error status out (spstat),a ;reset parity error status ld hl,ssint ;get interrupt service address ld (intbas+(2*0)),hl ;set interrupt vector ld hl,rtcint ;get interrupt service address ld (intbas+(2*5)),hl ;set interrupt vector ld hl,sioint ;get interrupt service address ld (siovec),hl ;set interrupt vector ld hl,badmem ;get interrupt service address ld (intbas+(2*4)),hl ;set interrupt vector xor a ;get bank 0 call selbnk ;select bank 0 ld a,4 ;enable memory parity error call intnit## ld sp,(spsave) ;restore stack pointer ret ;done ; ssint: ld (spsave),sp ;save stack pointer ld sp,auxstk ;set up auxilliary stack push af ;save af-reg xor a ;get bank 0 call selbnk ;select bank 0 call ssisr## ;process network interrupt di ;disable interrupts ld a,1 ;get bank 1 call selbnk ;select bank 1 pop af ;restore af-reg ld sp,(spsave) ;restore stack pointer ei ;enable interrupts ret ;done ; rtcint: ld (spsave),sp ;save stack pointer ld sp,auxstk ;set up auxilliary stack push af ;save af-reg xor a ;get bank 0 % call selbnk ;select bank 0 call rtcisr## ;process real time clock interrupt di ;disable interrupts ld a,1 ;get bank 1 call selbnk ;select bank 1 pop af ;restore af-reg ld sp,(spsave) ;restore stack pointer ei ;enable interrupts ret ;done ; sioint: ld (spsave),sp ;save stack pointer ld sp,auxstk ;set up auxilliary stack push af ;save af-reg xor a ;get bank 0 call selbnk ;select bank 0 call sioisr## ;process serial i/o interrupt di ;disable interrupts ld a,1 ;get bank 1 call selbnk ;select bank 1 pop af ;restore af-reg ld sp,(spsave) ;restore stack pointer ei ;enable interrupts ret ;done ; selbnk:: add a,0f1h ;construct bank select command out (memctl),a ;select requested bank ret ;done ; badmem: di ;memory parity error halt ;so stop ; spsave: dw 0 ;stack pointer save area ds 8*2 ;auxilliary stack area auxstk equ $ ;top of auxilliary stack area ; end  title TurboDOS operating system - super slave operating system booter .z80 ; name ('ssboot') ;module id ; ivec equ 10h ;interrupt vector ; ctl equ 1fh ;super slave control port dta equ 1eh ;super slave data port to master ; intctl equ 19h ;interrupt controller control port intdta equ 18h ;interrupt controller data port ; svcrqt equ 8 ;service request bit clrovr equ 4 ;clear overrun error bit clrpar equ 2 ;clear parity error bit rdy equ 7 ;ready for service flag bit ; ; public ssdid,sssid,ssssl ; ssblod:: dw start ;loading address for spbn82 ssblen:: dw rcvhdr-start ;length of spbn82 ; ssboot: .phase 100h ;want it to execute at this address ;in the slave ; ; initialize code ; start: di ld SP,start ;set up stack ld A,clrovr ;clear possible overrun error out (ctl),A im 2 ;use interrupt mode 2 xor A ld I,A ;use base page for interrupt vectors out (intctl),A ;now init 9519 int. controller ld A,80h ;load mode 0-4 out (intctl),A ld A,0c0h ;preset auto clear register out (intctl),A ld A,0ffh ;load auto clear all channels out (intdta),A ld A,0a9h ;load mode 5, 6 and set 7 out (intctl),A ld HL,intsvcr ;interrupt vector address ld (ivec),HL ld A,0e0h ;select channel 0 out (intctl),A ld A,10h ;vector address out (intdta),A ld A,18h ;and clear interrupt zero out (intctl),A ei ld HL,0 ;clear memory parity ld DE,0 ld BC,0 ldir ld A,clrpar ;clear parity error out (ctl),A ; ; send operating system request ; reqdta: ld HL,msglen ;point to block to send master ld B,(HL) ;get amount to send call reqsvc ;wait until master ready to receive otir ;send it ld HL,rdyflg ;point to service flag res rdy,(HL) ;clear serviced bit ; ; receive operating system from master ; nodata: bit rdy,(HL) ;got some stuf to process jr z,nodata ;wait if not ld HL,rcvhdr ;else set up hl call reqsvc ;and go wait for master ready in B,(C) ;get amount to receive ld (HL),B ;save it in buffer inc HL ;update pointers dec B inir ;get block from master ld A,(rcvhdr) ;get amount we received cp 0ch ;was it short block jr z,done ;if so leave ld HL,rcvbuf ;get start address of data in received block ld DE,(bufptr) ;get address to move it to ld BC,80h ldir ;move it ld (bufptr),DE ;save updated address back jr reqdta ;and go do more ; ; got all of operating system, now put where it belongs and execute it ; done: dec HL ;get last char we just received ld A,(HL) ld HL,lodbuf ;point to begining of receive buffer ld E,(HL) ;get starting address of what we received inc HL ld D,(HL) inc HL ld C,(HL) ;get length of what we received inc HL ld B,(HL) add HL,BC ;make hl = end of what we just received ex DE,HL ;save it for now add HL,BC ;make hl = ending load address + 1 dec HL ;correct for +1 ex DE,HL ;put source and dest in proper regs lddr ;move what we just got to execution addr inc DE ;make de point to start of code ld HL,(msgsid) ;get slave source id ld (80h),HL ;and save it in default buffer ex DE,HL ;and now go execute what we got jp (HL) ; ; request service and wait for master to respond ; reqsvc: ld C,dta ;init c to data port ld A,svcrqt ;send service request out (ctl),A notrdy: in A,(ctl) ;is service request still set and svcrqt jr nz,notrdy ;if so wait some more ret ;else return ; ; interrupt response routine ; intsvcr: push AF ;save psw ld A,6 ;send acknowledgement out (dta),A in A,(dta) ;get masters response cp 6 ;was it right jr nz,isrxit ;exit if not ld A,(rdyflg) ;else set master ready flag set rdy,A ld (rdyflg),A isrxit: pop AF ;restore psw ei ;turn ints. on so we can do again reti ;and leave ; ; bufptr: dw lodbuf ;pointer to next space in assemble buffer rdyflg: db 0 ;data ready to trans to assembly buffer ; ; request operating system message ; msglen: db 0ch msgdid: dw 0 ;gets patched to network default id db 0 msgsid: dw 0 ;gets patched to slave network id dw 0 db 0,0,0 msgssl: db ' ' ;gets patched with slave operating system ;down load suffix ; rcvhdr: ds 0bh rcvbuf: ds 80h ;temp receive buffer lodbuf: ;system assembly buffer .dephase ssdid equ ssboot + (msgdid - start) sssid equ ssboot + (msgsid - start) ssssl equ ssboot + (msgssl - start) end  push AF ;save psw ld A,6 ;send acknowledgement out (dta),A in A,(dta) ;get masters response cp 6 ;was it right jr nz,isrxit ;exit if not ld A,(rdyflg) ;else set master ready flag set rdy,A ld (rdyflg),A isrxit: pop AF ;restore psw ei ;turn ints. on so we can do again reti ;and leave ; ; bufptr: dw lodbuf ;pointer to next space in assemble buffer rdyflg: db 0 ;data ready to trans to assembly buffer ; ; request operating system message ; msglen: db 0ch& title TURBODOS OPERATING SYSTEM - SUPER SLAVE CIRCUIT DRIVER subttl copyright 1983, software 2000, inc. .z80 ; ; copyright 1983, software 2000, inc. ; converted to MICROSOFT M80 format by ; Advanced Digital Corp. ; ; version: 06/28/83 ; name ('sscd') ;module id ; include DREQUATE.LIB ;driver symbolic equivalences ; spdata equ 1eh ;slave processor data port spstat equ 1fh ;slave processor status/ctrl port ; promon equ 0 ;prom on bit respes equ 1 ;reset parity error status bit resors equ 2 ;reset overrun error status bit reqest equ 3 ;request bit ; sw equ 6 ;send waiting flag (flags) ra equ 7 ;receive activated flag (flags) ; dseg ;locate in data area ; flags: db 0 ;flags ; rcvsph: dw 0 ;receive message semaphore ..rmhd: dw ..rmhd dw ..rmhd ; smxsph: dw 1 ;send mutual exclusion semaphore ..mxhd: dw ..mxhd dw ..mxhd ; sndsph: dw 0 ;send message semaphore ..smhd: dw ..smhd dw ..smhd ; common /?init?/ ;locate in initialization area  ; cktin@:: xor a ;get interrupt vector number ld hl,ssisr ;get interrupt service address call intnit## ;initialize interrupt vector ld a,(nmbckt##) ;get number of circuits ld b,a ;number of circuits to b-reg ld hl,cktast##+1 ;get circuit assignment table ld a,(tbuf+1) ;get msb of passed destination id ..sl: cp (hl) ;circuit numbers equal? jr z,..didf ;if so, continue inc hl ;else, advance to next table entry inc hl inc hl inc hl djnz ..sl ;continue ret ;done ..didf: dec hl ;back up to lsb of destination id ld a,(tbuf) ;get lsb of passed destination id ld (hl),a ;set lsb of destination id ret ;done ; cseg ;locate in program area ; cktdr@:: ld a,c ;get function number or a ;function number=0? jr z,rcvmsg ;if so, continue dec a ;function number=1? jr z,sndmsg ;if so, continue ret ;else, done ; rcvmsg: inc de ;advance past link pointers inc de inc de inc de ld hl,rcvsph ;get receive message semaphore call wait## ;wait for receive message call srmcom ;do common setup in b,(c) ;get message length ld (hl),b ;store message length in buffer inc hl ;increment buffer pointer dec b ;decrement message length inir ;receive remainder of message ei ;enable interrupts ld hl,flags ;get flags res ra,(hl) ;reset receive activated flag bit sw,(hl) ;send waiting flag set? jr z,..x ;if not, continue res sw,(hl) ;else, reset send waiting flag ld hl,sndsph ;get send message semaphore call signal## ;signal process as ready ..x: xor a ;set return code=0 ret ;done ; sndmsg: inc de ;advance past link pointers inc de inc de inc de ld hl,smxsph ;get mutual exclusion semaphore call wait## ;wait on mutual exclusion ..wtl: ld hl,flags ;get flags di ;disable interrupts bit ra,(hl) ;receive activated flag set? jr z,..send ;if not, continue ei ;else, enable interrupts set sw,(hl) ;set send waiting flag ld hl,sndsph ;get send message semaphore call wait## ;wait for receive completion jr ..wtl ;continue ..send: call srmcom ;do common setup ld b,(hl) ;get message length otir ;send message ei ;enable interrupts ld hl,smxsph ;get mutual exclusion semaphore call signal## ;release mutual exclusion xor a ;set return code=0 ret ;done ; srmcom: ex de,hl ;message packet address to hl-reg ld c,spdata ;c=slave processor data port ld a,1 shl reqest ;get slave request bit out (spstat),a ;set slave processor request bit ei ;enable interrupts ..wtl1: in a,(spstat) ;get slave processor status and 1 shl reqest ;request bit set? jr nz,..wtl1 ;if so, wait di ;else, disable interrupts ret ;done ; ssisr:: ld (intsp##),sp ;save stack pointer ld sp,intstk## ;set up aux stack push af ;save af-reg ld a,aack ;get ascii ack out (spdata),a ;output ack in a,(spdata) ;input byte cp aack ;response=ack? jr nz,..x1 ;if not, continue push bc ;else, save bc-reg push de ;save de-reg push hl ;save hl-reg ld hl,flags ;get flags set ra,(hl) ;set receive activated flag ld hl,rcvsph ;get receive message semaphore call signal## ;signal process as ready pop hl ;restore hl-reg pop de ;restore de-reg pop bc ;restore bc-reg ..x1: pop af ;save af-reg ld sp,(intsp##) ;restore stack pointer jp isrxit## ;continue ; end rocessor request bit ei ;enable interrupts ..wtl1: in a,(spstat) ;get slave processor status and 1 shl reqest ;request bit set? jr nz,..wtl1 ;if so, wait di ;else, disable interrupts ret ;done ; ssisr:: ld (intsp##),sp ;save stack pointer ld sp,intstk## ;set up aux stack push af ;save af-reg ld a,aack ;get ascii ack out (spdata),a ;output ack in a,(spdata) ;input byte cp aack ;response=ack? jr nz,..x1 ;if not, continue push bc ;else, save bc-reg push  title TurboDOS operating system - super slave initial system loader .z80 ; name ('ssload') ;module id ; lodadr equ 0100h ;temp buffer address for ssboot lodlng equ 0102h ; ctl equ 1fh ;super slave control port dta equ 1eh ;super slave data port to master ; clrpar equ 2 ;clear parity bit clrovr equ 4 ;clear overrun bit ; ssload:: .phase 1000h ;want it to execute at this address ;in slave start:: di ;can't be interrupted ld SP,start ;set up stack ld A,clrpar or clrovr ;clear overrun and parity and turn off prom out (ctl),A ld C,dta ;set up data port address ld HL,lodadr ;setup load address ld B,4 ;and amount to load inir ;get info from master about next load ld HL,(lodadr) ;get load address push HL ;save it for later ld DE,(lodlng) ;get length to load ld B,E ;preload count to load ld A,E ;is it even no. of pages or A jr nz,readin ;skip next if not dec D ;else pre decrement repeat counter readin: inir ;read in info dec D ;more to get jp p,readin ;go back if so pop HL ;else get starting address jp (HL) ;and execute what we just got .dephase end ta port to master ; clrpar equ 2 ;clear parity bit clrovr equ 4 ;clear overrun bit ; ssload:: .phase 1000h ;want it to execute at this address ;in slave start:: di ;can't be interrupted ld SP,start ;set up stack ld A,clrpar or clrovr ;clear overrun and parity and turn off prom out (ctl),A ld C,dta ;set up data port address ld HL,lodadr ;setup load address ld B,4 ;and amount to load inir ;get info from master about next load ld HL,(lodadr) ;get load address push HL ;save it for later ld DE,(lodlng) ;get length to load ld B,E ;preload count to load ld A,E ;is it even no. of pages or A jr nz,readin ;skip next if not dec D ;else pre decrement repeat counter readin: inir ;read in i' title TURBODOS OPERATING SYSTEM - SLAVE PARALLEL PRINTER DRIVER subttl copyright 1983 by software 2000, inc. .z80 ; ; copyright 1983 by software 2000, inc. ; converted to MICROSOFT M80 format by ; Advanced Digital Corp. ; ; version: 02/21/84 doc ; name ('SSLSTPAR') ;module id ; include DREQUATE.LIB ;driver symbolic equivalences ; pio0d equ 20 ;parallel port 0 data port pio0c equ 22 pio1d equ 21 ;parallel port 1 data port pio1c equ 23 ; DSEG ;locate in data area ; parff:: db aff ;form feed character outchr: db 0 ;output character initc: db 0 ;initialization complete flag ; imssph: ;character output semaphore defw 0 ;semaphore count ..imsh: defw ..imsh ;semaphore p/d list head defw ..imsh ; cseg ;locate in program area ; lstdr@:: ld hl,initc ;get initialization complete flag ld a,(hl) or a ;initialization complete flag set? call z,..init ;if not, initialize list channel ld a,e ;get function number cp 2 ;function number=2?  jr z,lstout ;if so, continue cp 7 ;function number=7? jr z,lstwsr ;if so, continue ret ;else, done ..init: dec (hl) ;set initialization complete flag ld a,00fh ;put port a in output mode out (pio0c),a ld a,0cfh ;put port b in bit mode out (pio1c),a ld a,01fh ;bits 0-4 input, bits 5-7 output out (pio1c),a ret ;done ; lstwsr: ld a,(parff) ;get form feed character ld c,a ;form feed character to c-reg ; lstout: ld hl,outchr ;get output character ld (hl),c ;save output character ld de,imspol ;get poll routine address call lnkpol## ;create poll routine call imspr ;execute poll routine ld hl,imssph ;get semaphore address jp wait## ;dispatch if necessary ; imspol: ;parallel out poll routine defw 0 defw 0 ; imspr: in a,(pio1d) ;get printer status and 1 ;printer busy? ret z ;if so, done ld a,(outchr) ;get output character out (pio0d),a ;output it ld a,80h ;toggle data strobe out (pio1d),a xor a out (pio1d),a ld hl,imspol ;get poll routine address call unlink## ;unlink poll routine ld hl,imssph ;get semaphore jp signal## ;signal process as ready ; end it mode out (pio1c),a ld a,01fh ;bits 0-4 input, bits 5-7 output out (pio1c),a ret ;done ; lstwsr: ld a,(parff) ;get form feed character ld c,a ;form feed character to c-reg ; lstout: ld hl,outchr ;get output character ld (hl),c ;save output character ld de,imspol ;get poll routine address call lnkpol## ;create poll routine call imspr ;execute poll routine ld hl,imssph ;get semaphore address jp wait## ;dispatch if necessary ; imspol: ;parallel out poll routine defw 0 defw 0 ; imspr: in a,(pio1d) ;get printer status and 1 ;printer busy? ret z ;if so, done ld a,(outchr) ;get output character out (pio0d),a ;output it ld a,80h ;toggle data strobe out (pio1d),a xor a out (pio1d),a  title TURBODOS OPERATING SYSTEM - SUPER SLAVE HARDWARE INITIALIZATION subttl copyright 1983, software 2000, inc. .Z80 ; ; copyright 1983, software 2000, inc. ; converted to MICROSOFT M80 format by ; Advanced Digital Corp. ; ; version: 06/30/83 ; name ('SSNIT') ;module id ; include DREQUATE.LIB ;driver symbolic equivalences ; aseg ;interrupt vector defs org 0 ;force to base page ds 10 piovec:: ds 2 intbas equ 0010h ;9519 interrupt vector base org 20h siovec:: ds 2 ; ; intd equ 18h ;interrupt controller data port intc equ 19h ;interrupt controller control port ; spdata equ 1eh ;slave processor data port spstat equ 1fh ;slave processor status/ctrl port ; promon equ 0 ;prom on parerr equ 1 ;parity error ovrrun equ 2 ;overrun reqest equ 3 ;request ; common /?init?/ ;locate in initialization area ; hdwnit:: ld a,6 ;disable prom/clear overrun/request out (spstat),a xor a ld (iobyte),a ;set i/o byte=0 call incnit ;initialize interrupt controller call bnknit## ;initialize banked tpa driver call sionit## ;initialize serial driver call rtcnit## ;initialize real time clock driver call cktina## ;initialize circuit driver a jp cktinb## ;initialize circuit driver b ; incnit: im 2 ;set z80 interrupt mode 2 xor a ld i,a ;set interrupt vectors to page 0 out (intc),a ;reset int controller ld a,80h ;define int cont mode: out (intc),a ; fixed priority ; individual vector ; interrupt mode ; gint active-low ; ireq active-low ld a,0c0h ;load auto-clear register out (intc),a ld a,0ffh ;auto-clear all channels out (intd),a ld a,0a9h ;enable interrupt controller out (intc),a ret ;done ; ; drivers set up interrupt controller and vectors ; by calling the following subroutine "intnit" with: ; a = interrupt number (0...7) ; hl = interrupt svc routine address ; intnit:: push af ;save interrupt number ex de,hl ;isr address to de add a,a ;vector = interrupt base + 2*n ld c,a ld b,0 ld hl,intbas add hl,bc ;hl = vector address ld (hl),e ;store isr address in vector inc hl ld (hl),d dec hl pop af ;restore interrupt number push af ;save interrupt number or 0e0h ;construct load response memory cmd out (intc),a ;send to interrupt controller ld a,l ;get lsb of vector address out (intd),a ;load into response memory pop af ;restore interrupt number or 18h ;construct clear irr & imr cmd out (intc),a ;send to interrupt controller ret ;done ; end ll channels out (intd),a ld a,0a9h ;enable interrupt controller out (intc),a ret ;done ; ; drivers set up interrupt controller and vectors ; by calling the following subroutine "intnit" with: ; a = interrupt number (0...7) ; hl = interrupt svc routine address ; intnit:: push af ;save interrupt number ex de,hl ;isr address to de add a,a ;vector( TITLE TurboDOS operating system - Super Slave real time clock driver .z80 ; name ('ssrtc') ;module id ; chan equ 5 ;interrupt channel to use for tick int ; dseg ;put into data area ticcnt: db 0 ;seconds counter ; cseg rtcisr:: ld (intsp##),SP ;save stack pointer ld SP,intstk## ;and use interrupt stack push AF ;to save all registers push BC push DE push HL ld HL,ticcnt ;point to tick counter inc (HL) ;bump it up ld A,(HL) ;get count cp 61 ;at 1 second yet jr C,notsec ;skip reset if not ld (HL),0 ;else reset tick counter call rtcsec## ;and signal 1 second has passed notsec: call dlytic## ;signal tick has occured pop HL ;get registers back pop DE pop BC pop AF ld SP,(intsp##) ;restore stack pointer jp isrxit## ;and continue common /?init?/ ;initialization code rtcnit:: ld A,CHAN ;enable interrupt ld HL,rtcisr jp intnit## end  title TURBODOS OPERATING SYSTEM - SUPER SLAVE SERIAL I/O DRIVER FOR TWO PORTS subttl copyright 1983, software 2000, inc. .z80 ; ; copyright 1983, software 2000, inc. ; converted to MICROSOFT M80 format by ; Advaced Digital Corp. ; ; version: 07/12/83 ; name ('SSSIO2') ;module id ; include DREQUATE.LIB ;driver symbolic equivalences ; sioadr equ 00h ;sio port a data register sioacr equ 01h ;sio port a control register siobdr equ 02h ;sio port b data register siobcr equ 03h ;sio port b control register ; ; siobrr equ 10h ;sio baud rate generator register ; rda equ 0 ;received data available bit tbe equ 2 ;transmit buffer empty bit dcd equ 3 ;data carrier detect bit cts equ 3 ;clear to send bit ; DSEG ;locate in data area ; baudrt: db 0 ;baud rate register value ; s0ibsz:: dw 64 ;serial 0 input buffer size s0ibuf: dw 0 ;serial 0 input buffer address s0iptr: dw 0 ;serial 0 input pointer s0optr: dw 0 ;serial 0 output pointer s0icnt: dw 0  ;serial 0 input count s0iwct: db 0 ;serial 0 input wait count s0ochr: db 0 ;serial 0 output character s0br: db 0 ;serial 0 baud rate code ; s0isph: ;serial 0 input semaphore dw 0 ;semaphore count ..s0ih: dw ..s0ih ;semaphore p/d head dw ..s0ih ; ;serial 0 output semaphore s0osph: dw 0 ;semaphore count ..s0oh: dw ..s0oh ;semaphore p/d head dw ..s0oh ; s1ibsz:: dw 16 ;serial 1 input buffer size s1ibuf: dw 0 ;serial 1 input buffer address s1iptr: dw 0 ;serial 1 input pointer s1optr: dw 0 ;serial 1 output pointer s1icnt: dw 0 ;serial 1 input count s1iwct: db 0 ;serial 1 input wait count s1ochr: db 0 ;serial 1 output character s1br: db 0 ;serial 1 baud rate code ; ;serial 1 input semaphore s1isph: dw 0 ;semaphore count ..s1ih: dw ..s1ih ;semaphore p/d head dw ..s1ih ; ;serial 1 output semaphore s1osph: dw 0 ;semaphore count ..s1oh: dw ..s1oh ;semaphore p/d head dw ..s1oh ; COMMON /?init?/ ;locate in initialization area ; sionit:: ld hl,siovec## ;get interrupt vector address ld a,l ;get lsb of interrupt vector ld (wr2cwd),a ;set write register 2 control word ld hl,sioisr ;get interrupt service address ld (siovec##),hl ;set interrupt vector address ld hl,siopgm ;get sio program list ld bc,sioapl shl 8 or sioacr ;b=length/c=control reg otir ;program sio port a ld hl,siopgm ;get sio program list ld bc,siobpl shl 8 or siobcr ;b=length/c=control reg otir ;program sio port b ld hl,(s0ibsz) ;get serial 0 input buffer size call alloc## ;allocate packet for serial buffer ld (s0ibuf),hl ;save serial 0 input buffer address ld (s0iptr),hl ;set serial 0 input pointer ld (s0optr),hl ;set serial 0 output pointer ld hl,(s1ibsz) ;get serial 1 input buffer size call alloc## ;allocate packet for serial buffer ld (s1ibuf),hl ;save serial 1 input buffer address ld (s1iptr),hl ;set serial 1 input pointer ld (s1optr),hl ;set serial 1 output pointer ret ;done ; siopgm: db 18h ;reset channel db 4 ;select wr4 db 44h ;write register 4 control word db 5 ;select wr5 db 0eah ;write register 5 control word db 3 ;select wr3 db 0c1h ;write register 3 control word db 1 ;select wr1 db 10h ;write register 1 control word ; sioapl equ $-siopgm ;sio port a program length ; db 2 ;select wr2 wr2cwd: db 0 ;write register 2 control word ; siobpl equ $-siopgm ;sio port b program length ; cseg ;locate in program area ; serial:: comdrv:: ld a,e ;get function number or a ;function number=0? jr z,serst ;if so, continue cp 10 ;function number=10? jp z,seropt ;if so, continue dec a ;function number=1? jr z,serin ;if so, continue dec a ;function number=2? jp z,serout ;if so, continue dec a ;function number=3? jp z,sersbr ;if so, continue dec a ;function number=4? jp z,serrbr ;if so, continue dec a ;function number=5? jp z,sersmc ;if so, continue dec a ;function number=6? jp z,serrmc ;if so, continue ret ;else, done ; serst: ld a,b ;get channel number ld bc,(s0icnt) ;get serial 0 input buffer count ld hl,(s0optr) ;get serial 0 output pointer or a ;channel number=0 jr z,..com ;if so, continue ld bc,(s1icnt) ;get serial 1 input buffer count ld hl,(s1optr) ;get serial 1 output pointer ..com: ld a,b or c ;serial input buffer count=0? ret z ;if so, done ld c,(hl) ;else, get serial input character ld a,0ffh ;set return code=0ffh ret ;done ; serin: ld a,b ;get channel number or a ;channel number=0? jr nz,..s1i ;if not, continue ..s0i: di ;else, disable interrupts ld hl,(s0icnt) ;get serial 0 input count ld a,h or l ;serial 0 input count=0? jr z,..wt0 ;if so, continue dec hl ;decrement serial 0 input count ld (s0icnt),hl ;update serial 0 input count ld hl,(s0optr) ;get serial 0 output pointer ld a,(hl) ;get character from buffer inc hl ;increment serial 0 output pointer ex de,hl ;serial 0 output pointer to de-reg ld hl,(s0ibsz) ;get serial 0 input buffer size dec hl ;decrement input buffer size ld bc,(s0ibuf) ;get serial 0 input buffer address add hl,bc ;calc last input buffer address sbc hl,de ;buffer wrap-around? jr nc,..nwa0 ;if not, continue ld e,c ;get serial 0 input buffer address ld d,b ..nwa0: ld (s0optr),de ;update serial 0 output pointer ei ;enable interrupts ret ;done ..wt0: ld hl,s0iwct ;get serial 0 input wait count inc (hl) ;increment input wait count ld hl,s0isph ;get serial 0 input semaphore call wait## ;wait for console input jr ..s0i ;continue ..s1i: di ;disable interrupts ld hl,(s1icnt) ;get serial 1 input count ld a,h or l ;serial 1 input count=0? jr z,..wt1 ;if so, continue dec hl ;decrement serial 1 input count ld (s1icnt),hl ;update serial 1 input count ld hl,(s1optr) ;get serial 1 output pointer ld a,(hl) ;get character from buffer inc hl ;increment serial 1 output pointer ex de,hl ) ;serial 1 output pointer to de-reg ld hl,(s1ibsz) ;get serial 1 input buffer size dec hl ;decrement input buffer size ld bc,(s1ibuf) ;get serial 1 input buffer address add hl,bc ;calc last input buffer address sbc hl,de ;buffer wrap-around? jr nc,..nwa1 ;if not, continue ld e,c ;get serial 1 input buffer address ld d,b ..nwa1: ld (s1optr),de ;update serial 1 output pointer ei ;enable interrupts ret ;done ..wt1: ld hl,s1iwct ;get serial 1 input wait count inc (hl) ;increment input wait count ld hl,s1isph ;get serial 1 input semaphore call wait## ;wait for console input jr ..s1i ;continue ; seropt: ld a,b ;get channel number or a ;channel number=1? ld a,10h ;get reset external status command jr nz,..s1o ;if channel number=1, continue out (sioacr),a ;else, reset external status in a,(sioacr) ;get sio port a status and 1 shl tbe ;transmit buffer empty? ret z ;if not, done ld a,(s0br) ;else, get serial 0 baud rate code and 1 shl 6 ;cts handshaking requested? jr z,..nhr0 ;if not, continue in a,(sioacr) ;else, get sio port a status and 1 shl cts ;check clear to send status ret z ;if clear to send false, done ..nhr0: ld a,c ;get serial 0 output character out (sioadr),a ;output character ld a,0ffh ;set return code=0ffh ret ;done ..s1o: out (siobcr),a ;reset external status in a,(siobcr) ;get sio port b status and 1 shl tbe ;transmit buffer empty? ret z ;if not, done ld a,(s1br) ;else, get serial 1 baud rate code and 1 shl 6 ;cts handshaking requested? jr z,..nhr1 ;if not, continue in a,(siobcr) ;else, get sio port b status and 1 shl cts ;check clear to send status ret z ;if clear to send false, done ..nhr1: ld a,c ;get serial 1 output character out (siobdr),a ;output character ld a,0ffh ;set return code=0ffh ret ;done ; serout: ld a,b ;get channel number or a ;channel number=1? ld a,10h ;get reset external status command jr nz,..s1o1 ;if channel number=1, continue out (sioacr),a ;else, reset external status in a,(sioacr) ;get sio port a status and 1 shl tbe ;transmit buffer empty? jr z,..s0nr ;if not, continue ld a,(s0br) ;else, get serial 0 baud rate code and 1 shl 6 ;cts handshaking requested? jr z,..nhr2 ;if not, continue in a,(sioacr) ;else, get sio port a status and 1 shl cts ;check clear to send status jr z,..s0nr ;if clear to send false, continue ..nhr2: ld a,c ;get serial 0 output character out (sioadr),a ;output character ret ;done ..s0nr: ld a,c ;get serial 0 output character ld (s0ochr),a ;save output character ld de,s0opol ;get serial 0 out poll routine call lnkpol## ;create poll routine ld hl,s0osph ;get serial 0 out semaphore jp wait## ;dispatch if necessary ..s1o1: out (siobcr),a ;reset external status in a,(siobcr) ;get sio port b status and 1 shl tbe ;transmit buffer empty? jr z,..s1nr ;if not, continue ld a,(s1br) ;else, get serial 1 baud rate code and 1 shl 6 ;cts handshaking requested? jr z,..nhr3 ;if not, continue in a,(siobcr) ;else, get sio port b status and 1 shl cts ;check clear to send status jr z,..s1nr ;if clear to send false, continue ..nhr3: ld a,c ;get serial 1 output character out (siobdr),a ;output character ret ;done ..s1nr: ld a,c ;get serial 1 output character ld (s1ochr),a ;save output character ld de,s1opol ;get serial 1 out poll routine call lnkpol## ;create poll routine ld hl,s1osph ;get serial 1 out semaphore jp wait## ;dispatch if necessary ; s0opol: ;serial 0 output poll routine dw 0 ;successor link pointer dw 0 ;predecessor link pointer ; ld a,10h ;get reset external status command out (sioacr),a ;reset external status in a,(sioacr) ;get sio port a status and 1 shl tbe ;transmit buffer empty? ret z ;if not, done ld a,(s0br) ;else, get serial 0 baud rate code and 1 shl 6 ;cts handshaking requested? jr z,..nhr ;if not, continue in a,(sioacr) ;else, get sio port a status and 1 shl cts ;check clear to send status ret z ;if clear to send false, done ..nhr: ld a,(s0ochr) ;get serial 0 output character out (sioadr),a ;output character ld hl,s0opol ;get serial 0 out poll routine call unlink## ;unlink poll routine ld hl,s0osph ;get serial 0 out semaphore jp signal## ;signal process as ready ; s1opol: ;serial 1 output poll routine dw 0 ;successor link pointer dw 0 ;predecessor link pointer ; ld a,10h ;get reset external status command out (siobcr),a ;reset external status in a,(siobcr) ;get sio port b status and 1 shl tbe ;transmit buffer empty? ret z ;if not, done ld a,(s1br) ;else, get serial 1 baud rate code and 1 shl 6 ;cts handshaking requested? jr z,..nhra ;if not, continue in a,(siobcr) ;else, get sio port b status and 1 shl cts ;check clear to send status ret z ;if clear to send false, done ..nhra: ld a,(s1ochr) ;get serial 1 output character out (siobdr),a ;output character ld hl,s1opol ;get serial 1 out poll routine call unlink## ;unlink poll routine ld hl,s1osph ;get serial 1 out semaphore jp signal## ;signal process as ready ; sioisr:: ld (intsp##),sp ;save stack pointer ld sp,intstk## ;set up aux stack pointer push af ;save registers push bc push de push hl call ..s0i1 ;check for serial 0 input call ..s1i1 ;check for serial 1 input pop hl ;restore registers pop de pop bc pop af ld sp,(intsp##) ;restore stack pointer ei ;enable interrupts reti ;done ; ..s0i1: in a,(sioacr) ;get sio port a status bit rda,a ;character available ret z ;if not, done in a,(sioadr) ;get sio port a data character ld hl,s0br ;get serial 0 baud rate code bit 5,(hl) ;inhibit input flag set? ret nz ;if so, done ld c,a ;serial 0 data character to c-reg bit 7,(hl) ;sign bit on baud rate code? jr z,..nad0 ;if not, continue res 7,c ;else, strip sign bit on character call slvres## ;check for slave reset ld a,(atnchr##) ;get attention character cp c ;character=attention character? jr nz,..nad0 ;if not, continue ld hl,(s0iptr) ;else, get serial 0 input pointer ld (s0optr),hl ;reset serial 0 output pointer ld hl,0 ld (s0icnt),hl ;set serial 0 input count=0 ..nad0: ld hl,(s0ibsz) ;get serial 0 input buffer size ld de,(s0icnt) ;get serial 0 input count inc de ;increment serial 0 input count or a ;clear carry flag sbc hl,de ;serial 0 input buffer full? ret c ;if so, done ld (s0icnt),de ;else, update serial 0 input count ld hl,(s0iptr) ;get serial 0 input pointer ld (hl),c ;store input character in buffer inc hl ;increment input pointer ex de,hl ;de=input pointer/hl=buffer size ld hl,(s0ibsz) ;get serial 0 input buffer size dec hl ;decrement input buffer size ld bc,(s0ibuf) ;get serial 0 input buffer address add hl,bc ;calc last input buffer address sbc hl,de ;buffer wrap-around? jr nc,..nwa2 ;if not, continue ld e,c ;get serial 0 input buffer address ld d,b ..nwa2: ld (s0iptr),de ;update serial 0 input pointer ld de,s0iwct ;get serial 0 input wait count ld hl,s0isph ;get serial 0 input semaphore call ..sigc ;signal if necessary jr ..s0i1 ;continue ; ..s1i1: in a,(siobcr) ;get sio port b status bit rda,a ;character available ret z ;if not, done in a,(siobdr) ;get sio port b data character ld hl,s1br ;get serial 1 baud rate code bit 5,(hl) ;inhibit input flag set? ret nz ;if so, done ld c,a ;serial 1 data character to c-reg bit 7,(hl) ;attention detection flag set? jr z,..nad1 ;if not, continue res 7,c ;else, strip sign bit on character call slvres## ;check for slave reset ld a,(atnchr##) ;get attention character cp c ;character=attention character? jr nz,..nad1 ;if not, continue ld hl,(s1iptr) ;else, get serial 1 input pointer ld (s1optr),hl ;reset serial 1 output pointer ld hl,0 ld (s1icnt),hl ;set serial 1 input count=1 ..nad1: ld hl,(s1ibsz) ;ge*t serial 1 input buffer size ld de,(s1icnt) ;get serial 1 input count inc de ;increment serial 1 input count or a ;clear carry flag sbc hl,de ;serial 1 input buffer full? ret c ;if so, done ld (s1icnt),de ;else, update serial 1 input count ld hl,(s1iptr) ;get serial 1 input pointer ld (hl),c ;store input character in buffer inc hl ;increment input pointer ex de,hl ;de=input pointer/hl=buffer size ld hl,(s1ibsz) ;get serial 1 input buffer size dec hl ;decrement input buffer size ld bc,(s1ibuf) ;get serial 1 input buffer address add hl,bc ;calc last input buffer address sbc hl,de ;buffer wrap-around? jr nc,..nwa3 ;if not, continue ld e,c ;get serial 1 input buffer address ld d,b ..nwa3: ld (s1iptr),de ;update serial 1 input pointer ld de,s1iwct ;get serial 1 input wait count ld hl,s1isph ;get serial 1 input semaphore call ..sigc ;signal if necessary jr ..s1i1 ;continue ..sigc: ld a,(de) ;get serial input wait count or a ;serial input wait count=0? ret z ;if so, done dec a ;decrement serial input wait count ld (de),a ;update serial input wait count jp signal## ;signal process as ready ; sersbr: ld a,b ;get channel number ld hl,s0br ;get serial 0 baud rate code or a ;channel number=0? jr z,..com1 ;if so, continue ld hl,s1br ;else, get serial 1 baud rate code ..com1: ld (hl),c ;save baud rate code ld a,c ;get requested baud rate code and 0fh ;extract relevant bits ld c,a ;update requested baud rate code ld a,b ;get channel number or a ;channel number=0? ld a,(baudrt) ;get baud rate register value jr z,..ch0 ;if channel number=0, continue and 0fh ;else, strip upper four bits ld b,a ;baud rate register value to b-reg ld a,c ;get requested baud rate code add a,a ;shift baud rate code to msn add a,a add a,a add a,a or b ;combine with baud rate register jr ..com2 ;continue ..ch0: and 0f0h ;strip lower four bits or c ;combine with baud rate register ..com2: out (siobrr),a ;set baud rate generator register ld (baudrt),a ;update baud rate register value ret ;done ; serrbr: ld hl,s0br ;get serial 0 baud rate ld a,b ;get channel number or a ;channel number=0? jr z,..com5 ;if so, continue ld hl,s1br ;else, get serial 1 baud rate ..com5: ld a,(hl) ;get current baud rate code ret ;done ; sersmc: ld a,0eah ;get write register 5 control word and 82h ;strip rts/cts control bits bit 7,c ;rts requested? jr z,..nrts set 1,a ;if so, set rts bit ..nrts: bit 6,c ;dtr requested? jr z,..ndtr set 7,a ;if so, set dtr bit ..ndtr: ld d,a ;requested modem controls to d-reg ld c,sioacr ;get sio port a control register ld a,b ;get channel number or a ;channel number=0? jr z,..com3 ;if so, continue ld c,siobcr ;get sio port b control register ..com3: ld a,5 ;get write register 5 di ;disable interrupts out (c),a ;select write register 5 out (c),d ;output control word ei ;enable interrupts ret ;done ; serrmc: ld c,sioacr ;get sio port a control register ld a,b ;get channel number or a ;channel number=0? jr z,..com4 ;if so, continue ld c,siobcr ;get sio port b control register ..com4: ld a,10h ;get reset external status command out (c),a ;reset external status in d,(c) ;get sio modem status xor a ;clear return vector bit cts,d ;cts set? jr z,..ncts ;if not, continue set 7,a ;else, set cts bit ..ncts: bit dcd,d ;dcd set? ret z ;if not, done set 5,a ;else, set dcd bit ret ;done ; end .ndtr: ld d,a ;requested modem controls to d-reg ld c,sioacr ;get sio port a control register ld a,b ;get channel number or a ;channel number=0? jr z,..com3 ;if so, continue ld c,siobcr ;get sio port b control register ..com3: ld a,5 ;get write register 5 di ;disable interrupts out (c),a ;select write register 5 out (c),d ;output control word ei title TURBODOS OPERATING SYSTEM - SUPER SLAVE SERIAL I/O DRIVER FOR FOUR PORTS subttl copyright 1983, software 2000, inc. .z80 ; ; copyright 1983, software 2000, inc. ; converted to MICROSOFT M80 format by ; Advaced Digital Corp. ; ; version: 10/3/83 ; name ('SSSIO4') ;module id ; include DREQUATE.LIB ;driver symbolic equivalences ; sioadr equ 00h ;sio port a data register sioacr equ 01h ;sio port a control register siobdr equ 02h ;sio port b data register siobcr equ 03h ;sio port b control register ; siocdr equ 0ch ;sio port c data register sioccr equ 0dh ;sio port c control register sioddr equ 0eh ;sio port d data register siodcr equ 0fh ;sio port d control register ; ; siobrr equ 10h ;sio baud rate generator register ; rda equ 0 ;received data available bit tbe equ 2 ;transmit buffer empty bit dcd equ 3 ;data carrier detect bit cts equ 3 ;clear to send bit ; DSEG ;locate in data area ; baudrt: db 0 ;baud rate register value ; s0ibsz:: dw 64 ;serial 0 input buffer size s0ibuf: dw 0 ;serial 0 input buffer address s0iptr: dw 0 ;serial 0 input pointer s0optr: dw 0 ;serial 0 output pointer s0icnt: dw 0 ;serial 0 input count s0iwct: db 0 ;serial 0 input wait count s0ochr: db 0 ;serial 0 output character s0br: db 0 ;serial 0 baud rate code ; s0isph: ;serial 0 input semaphore dw 0 ;semaphore count ..s0ih: dw ..s0ih ;semaphore p/d head dw ..s0ih ; ;serial 0 output semaphore s0osph: dw 0 ;semaphore count ..s0oh: dw ..s0oh ;semaphore p/d head dw ..s0oh ; s1ibsz:: dw 16 ;serial 1 input buffer size s1ibuf: dw 0 ;serial 1 input buffer address s1iptr: dw 0 ;serial 1 input pointer s1optr: dw 0 ;serial 1 output pointer s1icnt: dw 0 ;serial 1 input count s1iwct: db 0 ;serial 1 input wait count s1ochr: db 0 ;serial 1 output character s1br: db 0 ;serial 1 baud rate code ; ;serial 1 input semaphore s1isph: dw 0 ;semaphore count ..s1ih: dw ..s1ih ;semaphore p/d head dw ..s1ih ; ;serial 1 output semaphore s1osph: dw 0 ;semaphore count ..s1oh: dw ..s1oh ;semaphore p/d head dw ..s1oh ; s2ibsz:: dw 16 ;serial 2 input buffer size s2ibuf: dw 0 ;serial 2 input buffer address s2iptr: dw 0 ;serial 2 input pointer s2optr: dw 0 ;serial 2 output pointer s2icnt: dw 0 ;serial 2 input count s2iwct: db 0 ;serial 2 input wait count s2ochr: db 0 ;serial 2 output character s2br: db 0 ;serial 2 baud rate code ; ;serial 2 input semaphore s2isph: dw 0 ;semaphore count ..s2ih: dw ..s2ih ;semaphore p/d head dw ..s2ih ; ;serial 2 output semaphore s2osph: dw 0 ;semaphore count ..s2oh: dw ..s2oh ;semaphore p/d head dw ..s2oh ; s3ibsz:: dw 16 ;serial 3 input buffer size s3ibuf: dw 0 ;serial 3 input buffer address s3iptr: dw 0 ;serial 3 input pointer s3optr: dw 0 ;serial 3 output pointer s3icnt: dw 0 ;serial 3 input count s3iwct: db 0 ;serial 3 input wait count s3ochr: db 0 ;serial 3 output character s3br: db 0 ;serial 3 baud rate code ; ;serial 3 input semaphore s3isph: dw 0 ;semaphore count ..s3ih: dw ..s3ih ;semaphore p/d head dw ..s3ih ; ;serial 3 output semaphore s3osph: dw 0 ;semaphore count ..s3oh: dw ..s3oh ;semaphore p/d head dw ..s3oh ; COMMON /?init?/ ;locate in initialization area ; sionit:: ld hl,siovec## ;get interrupt vector address ld a,l ;get lsb of interrupt vector ld (wr2cwd),a ;set write register 2 control word ld hl,sioisr ;get interrupt service address ld (siovec##),hl ;set interrupt vector address ld hl,siopgm ;get sio program list ld bc,sioapl shl 8 or sioacr ;b=length/c=control reg otir ;program sio port a ld hl,siopgm ;get sio program list ld bc,siobpl shl 8 or siobcr ;b=length/c=control reg otir ;program sio port b ld hl,siopgm ;get sio program list ld bc,sioapl shl 8 or sioccr ;b=length/c=control reg otir ;program sio port a ld hl,siopgm ;get sio program list ld bc,siobpl shl 8 or siodcr+ ;b=length/c=control reg otir ;program sio port b ld hl,(s0ibsz) ;get serial 0 input buffer size call alloc## ;allocate packet for serial buffer ld (s0ibuf),hl ;save serial 0 input buffer address ld (s0iptr),hl ;set serial 0 input pointer ld (s0optr),hl ;set serial 0 output pointer ld hl,(s1ibsz) ;get serial 1 input buffer size call alloc## ;allocate packet for serial buffer ld (s1ibuf),hl ;save serial 1 input buffer address ld (s1iptr),hl ;set serial 1 input pointer ld (s1optr),hl ;set serial 1 output pointer ld hl,(s2ibsz) ;get serial 2 input buffer size call alloc## ;allocate packet for serial buffer ld (s2ibuf),hl ;save serial 2 input buffer address ld (s2iptr),hl ;set serial 2 input pointer ld (s2optr),hl ;set serial 2 output pointer ld hl,(s3ibsz) ;get serial 3 input buffer size call alloc## ;allocate packet for serial buffer ld (s3ibuf),hl ;save serial 3 input buffer address ld (s3iptr),hl ;set serial 3 input pointer ld (s3optr),hl ;set serial 3 output pointer ret ;done ; siopgm: db 18h ;reset channel db 4 ;select wr4 db 44h ;write register 4 control word db 5 ;select wr5 db 0eah ;write register 5 control word db 3 ;select wr3 db 0c1h ;write register 3 control word db 1 ;select wr1 db 10h ;write register 1 control word ; sioapl equ $-siopgm ;sio port a program length ; db 2 ;select wr2 wr2cwd: db 0 ;write register 2 control word ; siobpl equ $-siopgm ;sio port b program length ; cseg ;locate in program area ; serial:: comdrv:: ld a,e ;get function number or a ;function number=0? jr z,serst ;if so, continue cp 10 ;function number=10? jp z,seropt ;if so, continue dec a ;function number=1? jr z,serin ;if so, continue dec a ;function number=2? jp z,serout ;if so, continue dec a ;function number=3? jp z,sersbr ;if so, continue dec a ;function number=4? jp z,serrbr ;if so, continue dec a ;function number=5? jp z,sersmc ;if so, continue dec a ;function number=6? jp z,serrmc ;if so, continue ret ;else, done ; serst: ld a,b ;get channel number ld bc,(s0icnt) ;get serial 0 input buffer count ld hl,(s0optr) ;get serial 0 output pointer or a ;channel number=0 jr z,..com ;if so, continue ld bc,(s1icnt) ;get serial 1 input buffer count ld hl,(s1optr) ;get serial 1 output pointer cp 1 ;channel number=1 jr z,..com ;if so, continue ld bc,(s2icnt) ;get serial 2 input buffer count ld hl,(s2optr) ;get serial 2 output pointer cp 2 ;channel number=2 jr z,..com ;if so, continue ld bc,(s3icnt) ;get serial 3 input buffer count ld hl,(s3optr) ;get serial 3 output pointer ..com: ld a,b or c ;serial input buffer count=0? ret z ;if so, done ld c,(hl) ;else, get serial input character ld a,0ffh ;set return code=0ffh ret ;done ; serin: ld a,b ;get channel number or a ;channel number=0? jr z,..s0i ;if so, continue cp 1 ;channel number=1? jr nz,..s1i ;if so, continue cp 2 ;channel number=2? jr nz,..s2i ;if so, continue jp ..s3i ;else must be channel=3 ; ..s0i: di ;else, disable interrupts ld hl,(s0icnt) ;get serial 0 input count ld a,h or l ;serial 0 input count=0? jr z,..wt0 ;if so, continue dec hl ;decrement serial 0 input count ld (s0icnt),hl ;update serial 0 input count ld hl,(s0optr) ;get serial 0 output pointer ld a,(hl) ;get character from buffer inc hl ;increment serial 0 output pointer ex de,hl ;serial 0 output pointer to de-reg ld hl,(s0ibsz) ;get serial 0 input buffer size dec hl ;decrement input buffer size ld bc,(s0ibuf) ;get serial 0 input buffer address add hl,bc ;calc last input buffer address sbc hl,de ;buffer wrap-around? jr nc,..nwa0 ;if not, continue ld e,c ;get serial 0 input buffer address ld d,b ..nwa0: ld (s0optr),de ;update serial 0 output pointer ei ;enable interrupts ret ;done ..wt0: ld hl,s0iwct ;get serial 0 input wait count inc (hl) ;increment input wait count ld hl,s0isph ;get serial 0 input semaphore call wait## ;wait for console input jr ..s0i ;continue ; ..s1i: di ;disable interrupts ld hl,(s1icnt) ;get serial 1 input count ld a,h or l ;serial 1 input count=0? jr z,..wt1 ;if so, continue dec hl ;decrement serial 1 input count ld (s1icnt),hl ;update serial 1 input count ld hl,(s1optr) ;get serial 1 output pointer ld a,(hl) ;get character from buffer inc hl ;increment serial 1 output pointer ex de,hl ;serial 1 output pointer to de-reg ld hl,(s1ibsz) ;get serial 1 input buffer size dec hl ;decrement input buffer size ld bc,(s1ibuf) ;get serial 1 input buffer address add hl,bc ;calc last input buffer address sbc hl,de ;buffer wrap-around? jr nc,..nwa1 ;if not, continue ld e,c ;get serial 1 input buffer address ld d,b ..nwa1: ld (s1optr),de ;update serial 1 output pointer ei ;enable interrupts ret ;done ..wt1: ld hl,s1iwct ;get serial 1 input wait count inc (hl) ;increment input wait count ld hl,s1isph ;get serial 1 input semaphore call wait## ;wait for console input jr ..s1i ;continue ; ..s2i: di ;else, disable interrupts ld hl,(s2icnt) ;get serial 2 input count ld a,h or l ;serial 2 input count=0? jr z,..wt2 ;if so, continue dec hl ;decrement serial 2 input count ld (s2icnt),hl ;update serial 2 input count ld hl,(s2optr) ;get serial 2 output pointer ld a,(hl) ;get character from buffer inc hl ;increment serial 2 output pointer ex de,hl ;serial 2 output pointer to de-reg ld hl,(s2ibsz) ;get serial 2 input buffer size dec hl ;decrement input buffer size ld bc,(s2ibuf) ;get serial 2 input buffer address add hl,bc ;calc last input buffer address sbc hl,de ;buffer wrap-around? jr nc,..nwa2 ;if not, continue ld e,c ;get serial 2 input buffer address ld d,b ..nwa2: ld (s2optr),de ;update serial 2 output pointer ei ;enable interrupts ret ;done ..wt2: ld hl,s2iwct ;get serial 2 input wait count inc (hl) ;increment input wait count ld hl,s2isph ;get serial 2 input semaphore call wait## ;wait for console input jr ..s2i ;continue ; ..s3i: di ;disable interrupts ld hl,(s3icnt) ;get serial 3 input count ld a,h or l ;serial 3 input count=0? jr z,..wt3 ;if so, continue dec hl ;decrement serial 3 input count ld (s3icnt),hl ;update serial 3 input count ld hl,(s3optr) ;get serial 3 output pointer ld a,(hl) ;get character from buffer inc hl ;increment serial 3 output pointer ex de,hl ;serial 3 output pointer to de-reg ld hl,(s3ibsz) ;get serial 3 input buffer size dec hl ;decrement input buffer size ld bc,(s3ibuf) ;get serial 3 input buffer address add hl,bc ;calc last input buffer address sbc hl,de ;buffer wrap-around? jr nc,..nwa3 ;if not, continue ld e,c ;get serial 3 input buffer address ld d,b ..nwa3: ld (s3optr),de ;update serial 3 output pointer ei ;enable interrupts ret ;done ..wt3: ld hl,s3iwct ;get serial 3 input wait count inc (hl) ;increment input wait count ld hl,s3isph ;get serial 3 input semaphore call wait## ;wait for console input jr ..s3i ;continue ; seropt: ld a,b ;get channel number or a ;channel number=0? jr z,..s0o ;if so continue cp 1 ;channel number=1? jr nz,..s1o ;if so continue cp 2 ;channel number=2? jr nz,..s2o ;if so continue jr ..s3o ;must be channel 3 ; ..s0o: ld a,10h ;get reset external status command out (sioacr),a ;else, reset external status in a,(sioacr) ;get sio port a status and 1 shl tbe ;transmit buffer empty? ret z ;if not, done ld a,(s0br) ;else, get serial 0 baud rate code and 1 shl 6 ;cts handshaking requested? jr z,..nhr0 ;if not, continue in a,(sioacr) ;else, get sio port a status and 1 shl cts ;check clear to send status ret z ;if clear to send false, done ..nhr0: ld a,c ;get serial 0 output character out (sioadr),a ;output character ld a,0ffh ;set retur,n code=0ffh ret ;done ; ..s1o: ld a,10h ;get reset external status command out (siobcr),a ;reset external status in a,(siobcr) ;get sio port b status and 1 shl tbe ;transmit buffer empty? ret z ;if not, done ld a,(s1br) ;else, get serial 1 baud rate code and 1 shl 6 ;cts handshaking requested? jr z,..nhr1 ;if not, continue in a,(siobcr) ;else, get sio port b status and 1 shl cts ;check clear to send status ret z ;if clear to send false, done ..nhr1: ld a,c ;get serial 1 output character out (siobdr),a ;output character ld a,0ffh ;set return code=0ffh ret ;done ; ..s2o: ld a,10h ;get reset external status command out (sioccr),a ;else, reset external status in a,(sioccr) ;get sio port c status and 1 shl tbe ;transmit buffer empty? ret z ;if not, done ld a,(s2br) ;else, get serial 2 baud rate code and 1 shl 6 ;cts handshaking requested? jr z,..nhr2 ;if not, continue in a,(sioccr) ;else, get sio port c status and 1 shl cts ;check clear to send status ret z ;if clear to send false, done ..nhr2: ld a,c ;get serial 2 output character out (siocdr),a ;output character ld a,0ffh ;set return code=0ffh ret ;done ; ..s3o: ld a,10h ;get reset external status command out (siodcr),a ;reset external status in a,(siodcr) ;get sio port d status and 1 shl tbe ;transmit buffer empty? ret z ;if not, done ld a,(s3br) ;else, get serial 3 baud rate code and 1 shl 6 ;cts handshaking requested? jr z,..nhr3 ;if not, continue in a,(siodcr) ;else, get sio port d status and 1 shl cts ;check clear to send status ret z ;if clear to send false, done ..nhr3: ld a,c ;get serial 3 output character out (sioddr),a ;output character ld a,0ffh ;set return code=0ffh ret ;done ; serout: ld a,b ;get channel number or a ;channel number=0? jr z,..s0o1 ;if so continue cp 1 ;channel number=1? jr nz,..s1o1 ;if so continue cp 2 ;channel number=2? jr nz,..s2o1 ;if so continue jp ..s3o1 ;must be channel 3 ; ..s0o1: ld a,10h ;get reset external status command out (sioacr),a ;else, reset external status in a,(sioacr) ;get sio port a status and 1 shl tbe ;transmit buffer empty? jr z,..s0nr ;if not, continue ld a,(s0br) ;else, get serial 0 baud rate code and 1 shl 6 ;cts handshaking requested? jr z,.nhr0 ;if not, continue in a,(sioacr) ;else, get sio port a status and 1 shl cts ;check clear to send status jr z,..s0nr ;if clear to send false, continue .nhr0: ld a,c ;get serial 0 output character out (sioadr),a ;output character ret ;done ..s0nr: ld a,c ;get serial 0 output character ld (s0ochr),a ;save output character ld de,s0opol ;get serial 0 out poll routine call lnkpol## ;create poll routine ld hl,s0osph ;get serial 0 out semaphore jp wait## ;dispatch if necessary ; ..s1o1: ld a,10h ;get reset external status command out (siobcr),a ;reset external status in a,(siobcr) ;get sio port b status and 1 shl tbe  ;transmit buffer empty? jr z,..s1nr ;if not, continue ld a,(s1br) ;else, get serial 1 baud rate code and 1 shl 6 ;cts handshaking requested? jr z,.nhr1 ;if not, continue in a,(siobcr) ;else, get sio port b status and 1 shl cts ;check clear to send status jr z,..s1nr ;if clear to send false, continue .nhr1: ld a,c ;get serial 1 output character out (siobdr),a ;output character ret ;done ..s1nr: ld a,c ;get serial 1 output character ld (s1ochr),a ;save output character ld de,s1opol ;get serial 1 out poll routine call lnkpol## ;create poll routine ld hl,s1osph ;get serial 1 out semaphore jp wait## ;dispatch if necessary ; ..s2o1: ld a,10h ;get reset external status command out (sioccr),a ;else, reset external status in a,(sioccr) ;get sio port c status and 1 shl tbe ;transmit buffer empty? jr z,..s2nr ;if not, continue ld a,(s2br) ;else, get serial 2 baud rate code and 1 shl 6 ;cts handshaking requested? jr z,.nhr2 ;if not, continue in a,(sioccr) ;else, get sio port c status and 1 shl cts ;check clear to send status jr z,..s2nr ;if clear to send false, continue .nhr2: ld a,c ;get serial 2 output character out (siocdr),a ;output character ret ;done ..s2nr: ld a,c ;get serial 2 output character ld (s2ochr),a ;save output character ld de,s2opol ;get serial 2 out poll routine call lnkpol## ;create poll routine ld hl,s2osph ;get serial 2 out semaphore jp wait## ;dispatch if necessary ; ..s3o1: ld a,10h ;get reset external status command out (siodcr),a ;reset external status in a,(siodcr) ;get sio port d status and 1 shl tbe ;transmit buffer empty? jr z,..s3nr ;if not, continue ld a,(s3br) ;else, get serial 3 baud rate code and 1 shl 6 ;cts handshaking requested? jr z,.nhr3 ;if not, continue in a,(siodcr) ;else, get sio port 3 status and 1 shl cts ;check clear to send status jr z,..s3nr ;if clear to send false, continue .nhr3: ld a,c ;get serial 3 output character  out (siobdr),a ;output character ret ;done ..s3nr: ld a,c ;get serial 3 output character ld (s3ochr),a ;save output character ld de,s3opol ;get serial 3 out poll routine call lnkpol## ;create poll routine ld hl,s3osph ;get serial 3 out semaphore jp wait## ;dispatch if necessary ; s0opol: ;serial 0 output poll routine dw 0 ;successor link pointer dw 0 ;predecessor link pointer ; ld a,10h ;get reset external status command out (sioacr),a ;reset external status in a,(sioacr) ;get sio port a status and 1 shl tbe ;transmit buffer empty? ret z ;if not, done ld a,(s0br) ;else, get serial 0 baud rate code and 1 shl 6 ;cts handshaking requested? jr z,..nhr ;if not, continue in a,(sioacr) ;else, get sio port a status and 1 shl cts ;check clear to send status ret z ;if clear to send false, done ..nhr: ld a,(s0ochr) ;get serial 0 output character out (sioadr),a ;output character ld hl,s0opol ;get serial 0 out poll routine call unlink## ;unlink poll routine ld hl,s0osph ;get serial 0 out semaphore jp signal## ;signal process as ready ; s1opol: ;serial 1 output poll routine dw 0 ;successor link pointer dw 0 ;predecessor link pointer ; ld a,10h ;get reset external status command out (siobcr),a ;reset external status in a,(siobcr) ;get sio port b status and 1 shl tbe ;transmit buffer empty? ret z ;if not, done ld a,(s1br) ;else, get serial 1 baud rate code and 1 shl 6 ;cts handshaking requested? jr z,..nhra ;if not, continue in a,(siobcr) ;else, get sio port b status and 1 shl cts ;check clear to send status ret z ;if clear to send false, done ..nhra: ld a,(s1ochr) ;get serial 1 output character out (siobdr),a ;output character ld hl,s1opol ;get serial 1 out poll routine call unlink## ;unlink poll routine ld hl,s1osph ;get serial 1 out semaphore jp signal## ;signal process as ready ; s2opol: ;serial 2 output poll routine dw 0 ;successor link pointer dw 0  ;predecessor link pointer ; ld a,10h ;get reset external status command out (sioccr),a ;reset external status in a,(sioccr) ;get sio port c status and 1 shl tbe ;transmit buffer empty? ret z ;if not, done ld a,(s2br) ;else, get serial 2 baud rate code and 1 shl 6 ;cts handshaking requested? jr z,..nhrc ;if not, continue in a,(sioccr) ;else, get sio port c status and 1 shl cts ;check clear to send status ret z ;if clear to send false, done ..nhrc: ld a,(s2ochr) ;get serial 2 output character out (siocdr),a ;output character ld hl,s2opol ;get serial 2 out poll routine call unlink## ;unlink poll routine ld hl,s2osph ;get serial 2 out semaphore jp signal## ;signal process as ready ; s3opol: ;serial 3 output poll routine dw 0 ;successor link pointer dw 0 ;predecessor link pointer ; ld a,10h ;get reset external status command out (siodcr),a ;reset external status in a,(siodcr) ;get sio port d status and 1 shl tbe ;transmit buffer e-mpty? ret z ;if not, done ld a,(s3br) ;else, get serial 3 baud rate code and 1 shl 6 ;cts handshaking requested? jr z,..nhrd ;if not, continue in a,(siodcr) ;else, get sio port d status and 1 shl cts ;check clear to send status ret z ;if clear to send false, done ..nhrd: ld a,(s3ochr) ;get serial 3 output character out (sioddr),a ;output character ld hl,s3opol ;get serial 3 out poll routine call unlink## ;unlink poll routine ld hl,s3osph ;get serial 3 out semaphore jp signal## ;signal process as ready ; sioisr:: ld (intsp##),sp ;save stack pointer ld sp,intstk## ;set up aux stack pointer push af ;save registers push bc push de push hl call ..s0i1 ;check for serial 0 input call ..s1i1 ;check for serial 1 input call ..s2i1 ;check for serial 2 input call ..s3i1 ;check for serial 3 input pop hl ;restore registers pop de pop bc pop af ld sp,(intsp##) ;restore stack pointer ei ;enable interrupts reti ;done ; ..s0i1: in a,(sioacr) ;get sio port a status bit rda,a ;character available ret z ;if not, done in a,(sioadr) ;get sio port a data character ld hl,s0br ;get serial 0 baud rate code bit 5,(hl) ;inhibit input flag set? ret nz ;if so, done ld c,a ;serial 0 data character to c-reg bit 7,(hl) ;sign bit on baud rate code? jr z,..nad0 ;if not, continue res 7,c ;else, strip sign bit on character call slvres## ;check slave reset ld a,(atnchr##) ;get attention character cp c ;character=attention character? jr nz,..nad0 ;if not, continue ld hl,(s0iptr) ;else, get serial 0 input pointer ld (s0optr),hl ;reset serial 0 output pointer ld hl,0 ld (s0icnt),hl ;set serial 0 input count=0 ..nad0: ld hl,(s0ibsz) ;get serial 0 input buffer size ld de,(s0icnt) ;get serial 0 input count inc de ;increment serial 0 input count or a ;clear carry flag sbc hl,de ;serial 0 input buffer full? ret c ;if so, done ld (s0icnt),de ;else, update serial 0 input count  ld hl,(s0iptr) ;get serial 0 input pointer ld (hl),c ;store input character in buffer inc hl ;increment input pointer ex de,hl ;de=input pointer/hl=buffer size ld hl,(s0ibsz) ;get serial 0 input buffer size dec hl ;decrement input buffer size ld bc,(s0ibuf) ;get serial 0 input buffer address add hl,bc ;calc last input buffer address sbc hl,de ;buffer wrap-around? jr nc,.nwa0 ;if not, continue ld e,c ;get serial 0 input buffer address ld d,b .nwa0: ld (s0iptr),de ;update serial 0 input pointer ld de,s0iwct ;get serial 0 input wait count ld hl,s0isph ;get serial 0 input semaphore call ..sigc ;signal if necessary jr ..s0i1 ;continue ..s1i1: in a,(siobcr) ;get sio port b status bit rda,a ;character available ret z ;if not, done in a,(siobdr) ;get sio port b data character ld hl,s1br ;get serial 1 baud rate code bit 5,(hl) ;inhibit input flag set? ret nz ;if so, done ld c,a ;serial 1 data character to c-reg bit 7,(hl) ;attention detection flag set? jr z,..nad1 ;if not, continue res 7,c ;else, strip sign bit on character call slvres## ;check slave reset ld a,(atnchr##) ;get attention character cp c ;character=attention character? jr nz,..nad1 ;if not, continue ld hl,(s1iptr) ;else, get serial 1 input pointer ld (s1optr),hl ;reset serial 1 output pointer ld hl,0 ld (s1icnt),hl ;set serial 1 input count=1 ..nad1: ld hl,(s1ibsz) ;get serial 1 input buffer size ld de,(s1icnt) ;get serial 1 input count inc de ;increment serial 1 input count or a ;clear carry flag sbc hl,de ;serial 1 input buffer full? ret c ;if so, done ld (s1icnt),de ;else, update serial 1 input count ld hl,(s1iptr) ;get serial 1 input pointer ld (hl),c ;store input character in buffer inc hl ;increment input pointer ex de,hl ;de=input pointer/hl=buffer size ld hl,(s1ibsz) ;get serial 1 input buffer size dec hl ;decrement input buffer size ld bc,(s1ibuf) ;get serial 1 input buffer address add hl,bc ;calc last input buffer address sbc hl,de ;buffer wrap-around? jr nc,.nwa1 ;if not, continue ld e,c ;get serial 1 input buffer address ld d,b .nwa1: ld (s1iptr),de ;update serial 1 input pointer ld de,s1iwct ;get serial 1 input wait count ld hl,s1isph ;get serial 1 input semaphore call ..sigc ;signal if necessary jr ..s1i1 ;continue ; ..s2i1: in a,(sioccr) ;get sio port c status bit rda,a ;character available ret z ;if not, done in a,(siocdr) ;get sio port c data character ld hl,s2br ;get serial 2 baud rate code bit 5,(hl) ;inhibit input flag set? ret nz ;if so, done ld c,a ;serial 2 data character to c-reg bit 7,(hl) ;sign bit on baud rate code? jr z,..nad2 ;if not, continue res 7,c ;else, strip sign bit on character call slvres## ;check slave reset ld a,(atnchr##) ;get attention character cp c ;character=attention character? jr nz,..nad2 ;if not, continue ld hl,(s2iptr) ;else, get serial 2 input pointer ld (s2optr),hl ;reset serial 2 output pointer ld hl,0 ld (s2icnt),hl ;set serial 2 input count=0 ..nad2: ld hl,(s2ibsz) ;get serial 2 input buffer size ld de,(s2icnt) ;get serial 2 input count inc de ;increment serial 2 input count or a ;clear carry flag sbc hl,de ;serial 2 input buffer full? ret c ;if so, done ld (s2icnt),de ;else, update serial 2 input count ld hl,(s2iptr) ;get serial 2 input pointer ld (hl),c ;store input character in buffer inc hl ;increment input pointer ex de,hl ;de=input pointer/hl=buffer size ld hl,(s2ibsz) ;get serial 2 input buffer size dec hl ;decrement input buffer size ld bc,(s2ibuf) ;get serial 2 input buffer address add hl,bc ;calc last input buffer address sbc hl,de ;buffer wrap-around? jr nc,.nwa2 ;if not, continue ld e,c ;get serial 2 input buffer address ld d,b .nwa2: ld (s2iptr),de ;update serial 2 input pointer ld de,s2iwct ;get serial 2 input wait count ld hl,s2isph ;get serial 2 input semaphore call ..sigc ;signal if necessary jr ..s2i1 ;continue ; ..s3i1: in a,(siodcr) ;get sio port d status bit rda,a ;character available ret z ;if not, done in a,(sioddr) ;get sio port d data character ld hl,s3br ;get serial 3 baud rate code bit 5,(hl) ;inhibit input flag set? ret nz ;if so, done ld c,a ;serial 3 data character to c-reg bit 7,(hl) ;attention detection flag set? jr z,..nad3 ;if not, continue res 7,c ;else, strip sign bit on character call slvres## ;check slave reset ld a,(atnchr##) ;get attention character cp c ;character=attention character? jr nz,..nad3 ;if not, continue ld hl,(s3iptr) ;else, get serial 3 input pointer ld (s3optr),hl ;reset serial 3 output pointer ld hl,0 ld (s3icnt),hl ;set serial 3 input count=1 ..nad3: ld hl,(s3ibsz) ;get serial 3 input buffer size ld de,(s3icnt) ;get serial 3 input count inc de ;increment serial 3 input count or a ;clear carry flag sbc hl,de ;serial 3 input buffer full? ret c ;if so, done ld (s3icnt),de ;else, update serial 3 input count ld hl,(s3iptr) ;get serial 3 input pointer ld (hl),c ;store input character in buffer inc hl ;increment input pointer ex de,hl ;de=input pointer/hl=buffer size ld hl,(s3ibsz) ;get serial 3 input buffer size dec hl ;decrement input buffer size ld bc,(s3ibuf) ;get serial 3 input buffer address add hl,bc ;calc last input buffer address sbc hl,de ;buffer wrap-around? jr nc,.nwa3 ;if not, continue ld e,c ;get serial 3 input buffer address ld d,b .nwa3: ld (s3iptr),de ;update serial 3 input pointer ld de,s3iwct ;get serial 3 input wait count ld hl,s3isph ;get serial 3 input semaphore call ..sigc ;signal if necessary jr ..s3i1 ;continue ; ..sigc: ld a,(de) ;get serial input wait count or a ;serial input wait count=0? ret z ;if so, done dec a ;decrement serial input wait count ld (de),a ;update serial input wait count jp signal## ;signal process as ready ; ; .sersbr: ld a,b ;get channel number ld hl,s0br ;get serial 0 baud rate code or a ;channel number=0? jr z,..com1 ;if so, continue ld hl,s1br ;else, get serial 1 baud rate code cp 1 ;channel number=1? jr z,..com1 ;if so, continue ld hl,s2br ;else, get serial 2 baud rate code cp 2 ;channel number=2? jr z,..com1 ;if so, continue ld hl,s3br ;else, get serial 3 baud rate code ..com1: ld (hl),c ;save baud rate code and 2 ;was it channel 2 or 3 ret nz ;if so done ld a,c ;get requested baud rate code and 0fh ;extract relevant bits ld c,a ;update requested baud rate code ld a,b ;get channel number or a ;channel number=0? ld a,(baudrt) ;get baud rate register value jr z,..ch0 ;if channel number=0, continue and 0fh ;else, strip upper four bits ld b,a ;baud rate register value to b-reg ld a,c ;get requested baud rate code add a,a ;shift baud rate code to msn add a,a add a,a add a,a or b ;combine with baud rate register jr ..com2 ;continue ..ch0: and 0f0h ;strip lower four bits or c ;combine with baud rate register ..com2: out (siobrr),a ;set baud rate generator register ld (baudrt),a ;update baud rate register value ret ;done ; serrbr: ld hl,s0br ;get serial 0 baud rate ld a,b ;get channel number or a ;channel number=0? jr z,..com5 ;if so, continue ld hl,s1br ;else, get serial 1 baud rate code cp 1 ;channel number=1? jr z,..com5 ;if so, continue ld hl,s2br ;else, get serial 2 baud rate code cp 2 ;channel number=2? jr z,..com5 ;if so, continue ld hl,s3br ;else, get serial 3 baud rate code ..com5: ld a,(hl) ;get current baud rate code ret ;done ; sersmc: ld a,0eah ;get write register 5 control word and 82h ;strip rts/cts control bits bit 7,c ;rts requested? jr z,..nrts set 1,a ;if so, set rts bit ..nrts: bit 6,c ;dtr requested? jr z,..ndtr set 7,a ;if so, set dtr bit ..ndtr: ld d,a ;requested modem controls to d-reg ld c,sioacr ;get sio port a control register ld a,b ;get channel number or a ;channel number=0? jr z,..com3 ;if so, continue ld c,siobcr ;get sio port b control register cp 1 ;channel number=1? jr z,..com3 ;if so, continue ld c,sioccr ;get sio port c control register cp 2 ;channel number=2? jr z,..com3 ;if so, continue ld c,siodcr ;get sio port d control register ..com3: ld a,5 ;get write register 5 di ;disable interrupts out (c),a ;select write register 5 out (c),d ;output control word ei ;enable interrupts ret ;done ; serrmc: ld c,sioacr ;get sio port a control register ld a,b ;get channel number or a ;channel number=0? jr z,..com4 ;if so, continue ld c,siobcr ;get sio port b control register cp 1 ;channel number=1? jr z,..com4 ;if so, continue ld c,sioccr ;get sio port c control register cp 2 ;channel number=2? jr z,..com4 ;if so, continue ld c,siodcr ;get sio port d control register ..com4: ld a,10h ;get reset external status command out (c),a ;reset external status in d,(c) ;get sio modem status xor a ;clear return vector bit cts,d ;cts set? jr z,..ncts ;if not, continue set 7,a ;else, set cts bit ..ncts: bit dcd,d ;dcd set? ret z ;if not, done set 5,a ;else, set dcd bit ret ;done ; end ister ..com3: ld a,5 ;get write register 5 di ;disable interrupts out (c),a ;select write register 5 out (c),d ;output control word ei ;enable interrupts ret ;done ; serrmc: ld c,sioacr ;get sio port a control register ld a,b ;get channel number or a ;channel number=0? jr z,..com4 ;if so, continue ld c,siobcr ;get sio port b control register cp 1 ;channel number=1? jr z,..com4 ;if so, continue ld c,sioccr ;get sio port c control register cp 2 ;channel number=2? jr z,..com4 ;if so, continue ld c,siodcr ;get sio port d control register ..com4: ld a,10h ;get reset extern title TurboDOS operating system - super slave sign on message ; name ('usrsom') ;module id ; dseg ; USRSOM:: DB 0DH,0AH,'Advanced Digital Corp. Super Slave up.' DB ' $' end t, done set 5,a ;else, set dcd bit ret ;done ; end ister ..com3: ld a,5 ;get write register 5 di ;disable interrupts out (c),a ;select write register 5 out (c),d ;/0123456789:;<=>?@ABCDEFGHIJKL