; Tarbell CP/M-86 Bios for Duplex 816 Board ; Copyright (c) 1983, 1984 by Tarbell Electronics. ; Last changed 4-9-85 by Don Tarbell. ; truth equates. true equ -1 ; value of true for assembler. false equ not true ; value of false for assembler. mini equ false ; true to boot on 5-inch floppy disks. loader equ false ; true if loader bios / false if system bios. mpmldr equ false ; true if MP/M-86 loader bios. sizmem equ true ; true if size cp/m-86 for maximum memory. chksiz equ 128 ; bytes/sector on track 0. dual equ false ; true if persci drives. ; Define number and kind of disk drives on system. nflop8 equ 2 ; number of 8-inch floppy drives. nflop5 equ 2 ; number of 5-inch floppy drives. nhard equ 2 ; number of hard disk drives. mrms12 equ false ; true for Morrow and RMS-12 hard disk. mcmi19 equ true ; true for Morrow and CMI-19 hard disk. mrod20 equ false ; true for Morrow and Rodime 20 hard disk. mq540 equ false ; true for Morrow and Quantum Q540. ; define which drives are 8-inch and which are 5-inch. ; 5-inch floppy drives are numbered 0-3, 8-inch from 4-7. ; Hard disk drives are numbered from 8-0feh. ; Undefined drive letters are numbered 0ffh. if not mini ; if booting on 8-inch floppies. drivea equ 4 ; drive a is 8-inch drive 0. driveb equ 5 ; drive b is 8-inch drive 1. drivec equ 0 ; drive c is 5-inch drive 0. drived equ 1 ; drive d is 5-inch drive 1. endif if mini ; if booting on 5-inch floppies. drivea equ 0 ; drive a is 5-inch drive 0. driveb equ 1 ; drive b is 5-inch drive 1. drivec equ 4 ; drive c is 8-inch drive 0. drived equ 5 ; drive d is 8-inch drive 1. endif if nhard gt 0 ; if 1 or more hard disks. drivee equ 8 ; drive e is hard disk. endif if nhard le 0 ; if no hard disks. drivee equ 0ffh ; drive e is undefined. endif if nhard gt 1 ; if 2 or more hard disks. drivef equ 9 ; drive f is hard disk. endif if nhard le 1 ; if no more than 1 hard disk. drivef equ 0ffh ; drive f is undefined. endif driveg equ 0ffh ; drive g is undefined. driveh equ 0ffh ; drive h is undefined. drivei equ 0ffh ; drive i is undefined. drivej equ 0ffh ; drive j is undefined. drivek equ 0ffh ; drive k is undefined. drivel equ 0ffh ; drive l is undefined. drivem equ 0ffh ; drive m is undefined. driven equ 0ffh ; drive n is undefined. driveo equ 0ffh ; drive o is undefined. drivep equ 0ffh ; drive p is undefined. ; define disk control variables for system. hlab equ 8 ; fdc head load: 8=before, 0=after, seek. stprat equ 0 ; fdc seek rate: 0=3ms, 1=6ms, 2=10ms, 3=20ms. pctrk equ 43 ; pre-compensation above this track. ibmtpd equ 40 ; DR/ibm tracks per 5-inch floppy. rtcnt equ 10 ; fdc read/write, fail retry count. srtcnt equ 2 ; fdc seek retry count. pcsbas equ 0f000h ; peripheral ports base address. ; console port addresses and mask bytes. cbase equ pcsbas+180h ; port base address. condat equ cbase+06h ; data port. consts equ cbase+02h ; status port. contbe equ 04h ; transmit buffer empty mask. conrda equ 01h ; receive data available mask. conpos equ true ; true if positive logic. ; printer port addresses and mask bytes. lbase equ pcsbas+190h ; port base address. lptdat equ lbase+06h ; data port. lptsts equ lbase+02h ; status port. lptcom equ lbase+04h ; command port. lptinp equ lbase+0ah ; input port (for both channels). lptdsr equ 40h ; bit 6 of lptdat = 0 for dsr ready. lpttbe equ 04h ; transmit buffer empty mask. lptrda equ 01h ; receive data available mask. lbaud equ 0bh ; Baud Rate: b=9600, c=19200. ; Floppy disk controller port addresses. fbase equ pcsbas+80h ; 2793 base address. fdisk equ fbase ; command/status port. ftrk equ fbase+2 ; track port. fsect equ fbase+4 ; sector port. fdata equ fbase+6 ; data port. fcont equ pcsbas+100h ; control port. ; Floppy DMA port addresses and command words. dmabas equ pcsbas+0fc0h ; dma controller base adr. dmacon0 equ dmabas+0ah ; control port. dmatc0 equ dmabas+08h ; transfer count register. dmadpu0 equ dmabas+06h ; destination pointer upper. dmadpl0 equ dmabas+04h ; destination pointer lower. dmaspu0 equ dmabas+02h ; source pointer upper. dmaspl0 equ dmabas ; source pointer lower. fdmard equ 0a266h ; floppy-to-memory command. fdmawt equ 016a6h ; memory-to-floppy command. ; additional system equates. fresh equ 1 ; bdos fresh disk access bit mask. eof equ 1ah ; end of file value. cr equ 0dh ; ascii carriage return. lf equ 0ah ; ascii line feed. tab equ 09h ; ascii tab. spc equ 20h ; ascii space. z816bios equ false ; so we can use same hard disk stuff for both. ; equates for Sector Blocking / Deblocking ; CP/M to host disk constants ; blksiz equ 4096 ;CP/M allocation size hstsiz equ 512 ;host disk sector size hstspt equ 16 ;host disk sectors/trk hstblk equ hstsiz/128 ;CP/M sects/host buff ; secshf equ 2 ;log2(hstblk) cpmspt equ hstblk * hstspt ;CP/M sectors/track secmsk equ hstblk-1 ;sector mask ; Bdos constants on entry to write wrall equ 0 ;write to allocated wrdir equ 1 ;write to directory wrual equ 2 ;write to unallocated ; define address refs for system or loader. bdos_int equ 224 ; reserved bdos interrupt. if not loader ; start condition (loader_false). bios_code equ 2500h ; offset to start of bios within segment. ccp_offset equ 0000h ; offset to base of cp/m within segment. bdos_ofst equ 0b06h ; offset to bdos entry point within segment. endif ; end condition (loader_false). if loader ; start condition (loader_true). bios_code equ 1200h ; offset to start of bios within segment. if not mpmldr ; if not mp/m loader. ccp_offset equ 0003h ; offset to base of cp/m within segment. endif if mpmldr ; if mp/m loader. ccp_offset equ 0103h ; offset to base of mp/m within segment. endif bdos_ofst equ 0406h ; offset to bdos entry point within segment. endif ; end condition (loader_true). cseg org ccp_offset ; define ccp code segment area. ccp: org bios_code ; start of bios code segment area. ; ********************************************************* ; ********** cp/m bios entry vector addresses ************* ; ********************************************************* jmp coldstart ; cold start. jmp warmstart ; warm start. jmp const ; console status. jmp conin ; console read. jmp conout ; console write. jmp lstout ; printer write. jmp punch ; paper tape punch. jmp reader ; paper tape reader. jmp home ; move head of selected drive to track zero. jmp seldsk ; select drive. jmp settrk ; seek track number. jmp setsec ; set sector number. jmp setdma ; set direct memory address. jmp read ; read selected sector. jmp write ; write selected sector. jmp pollpt ; printer status. jmp sectrn ; sector translate. jmp setdmab ; set segment base dma operations. jmp retsegt ; return offset of memory descriptor table jmp retiobt ; return i/o byte value. jmp setiobt ; set i/o byte value. ; ********************************************************* ; ******************* cold-start entry ******************** ; ********************************************************* coldstart: ; initialize system. cli ; disable interrupts during ini. mov ax,cs ; use segment passed with jmpf. mov ss,ax ; stack segment. mov ds,ax ; data segment. mov es,ax ; extra segment. mov sp,(offset stkbase) ; use local stack for ini. cld ; use incrementing indexes. xor ax,ax mov iobyte,al ; ini iobyte (tty: for consistancy). push ds ; save data segment. mov ds,ax ; clear data segment. if not loader mov es,ax ; clear extra segment. mov int0_offset,(offset int_trap) ; set int 0 vector. mov int0_segment,cs mov di,4 ; start at int 1. mov si,0 ; come from int 0. mov cx,510 ; do rest of 255 int's. rep movsw ; write em out. endif ; set-up bdos offset and segment vectors. mov bdos_offset,bdos_ofst if loader ; start condition (loader_true). mov bdos_segment,cs ; bdos segment is interrupt segment. endif ; end condition (loader_true). pop ds ; restore data segment. ; The loader initializes the printer port. if loader ; start condition (loader_true). ; initialize printer port. mov dx,lbase ; port for data format. mov al,13h ; char, no parity, out dx,al mov al,07h ; 8 data bits, 1 stop bit. out dx,al mov dx,lptsts ; get clock select port. mov al,(lbaud shl 4)+lbaud ; get baud rate code. out dx,al ; set baud rate. mov dx,lptcom ; get command port. mov al,45h ; reset errors, enable. out dx,al endif ; Print sign-on message (different for loader or bios). mov bx,(offset signon) call prtmsg ; print signon. ; the system locates the top of ram memory, and ; sets up the memory segment table to reflect to match. if (not loader) and sizmem push es ; save extra segment. mov ax,cs ; get base segment of cp/m. add ax,tpaseg ; add offset to tpa segment. push ax ; save tpa segment. mov es,ax ; into extra segment. mov si,0000h ; offset of 0. fndtop: mov bx,es:[si] ; save contents of memory. mov ax,5555h ; get test pattern. mov es:[si],ax ; write it to memory. cmp es:[si],ax ; same as test pattern? jne topfnd ; no, must be top of ram. mov es:[si],bx ; same, restore memory location. mov ax,es ; get segment base. cmp ax,0fc00h ; last possible segment? jae topfnd ; yes, stop. add ax,400h ; no, bump es by 16k. mov es,ax ; set new base. jmps fndtop ; loop till top of ram memory. topfnd: mov ax,es ; get last good segment. pop bx ; get base of tpa segment. mov tpabas,bx ; put in segtable. sub ax,bx ; calculate segment length. sub ax,bx ; remove cp/m offset. mov memlen,ax ; put in segtable. pop es ; recover extra segment. endif mov cl,0 ; default to drive a: on coldstart. sti ; re-enable interrupts. jmp ccp ; entry into ccp/loader. ; Compute physical dma address from segment and offset. ; Inputs: ax = segment, dx = offset. ; Outputs: msb20 = most signifcant bits, lsb20 = least sig. comdma: mov cl,4 ; shift count. rol ax,cl ; shift segment left 4. mov cl,al ; save shifted out top 4 bits. and cl,0fh ; mask for top 4 bits only. and ax,0fff0h add dx,ax ; add shifted segment to offset. mov al,0 ; clear. adc al,cl ; add top 4 & carry. mov msb20,al ; save bits a16-a19. mov lsb20,dx ; save bits a00-a15. ret ; ********************************************************* ; ******************* warm-start entry ******************** ; ********************************************************* warmstart: ; no special housekeeping required in this configuration. ; just re-entry the ccp. jmp ccp+6 ; ********************************************************* ; ********************** trap entry *********************** ; ********************************************************* if not loader ; start condition (loader_false). int_trap: ; this is a bad place to be, tell'em so and die. cli ; disable interrupts during service. mov ax,cs mov ds,ax ; get our data segment. mov bx,(offset trpmsg) call prtmsg ; print trap message. hlt ; hard stop. endif ; end condition (loader_false). ; ********************************************************* ; ****** console, printer, punch, & reader handlers ******* ; ********************************************************* ; console status check. const: if not loader push dx ; save port register. mov dx,consts ; get status port adr. in al,dx ; read status port. pop dx ; restore dx. and al,conrda ; test for ready. jz cs_ext ; result zero, exit test (00=not ready). or al,255 ; not zero, set al (ff=ready). cs_ext: endif ret ; return from console status (flag in al). ; console input. conin: if not loader call const ; get status. or al,al ; see if ready. jz conin ; wait for ready if not. push dx ; save dx. mov dx,condat ; get console data port adr. in al,dx ; read console data. pop dx ; restore dx. and al,7fh ; strip parity. endif ret ; return from console input (char in al). ; console output. conout: push dx ; save dx. mov dx,consts ; get status port adr. conolp: in al,dx ; read status port. and al,contbe ; test for ready. jz conolp ; result zero, cont test (00=not ready). mov al,cl ; get character from cl. mov dx,condat ; get console data port adr. out dx,al ; send character to console. pop dx ; restore dx. ret ; return from console output. ; printer status check. pollpt: if not loader push dx ; save dx. mov dx,lptsts ; get printer status port adr. in al,dx ; read printer status. and al,lpttbe ; mask for desired bits. jz ps_ext ; exit with al=00 if not ready. mov dx,lptinp ; get input port address. in al,dx ; read input port. test al,lptdsr ; look at dsr bit. mov al,0 ; default is zero. jnz ps_ext ; exit with zero if not ready. not al ; else make it ff for ready. ps_ext: pop dx ; restore dx. endif ret ; return from printer status (flag in al). ; printer output. lstout: if not loader call pollpt ; get status. or al,al ; see if ready. jz lstout ; wait for ready if not. mov al,cl ; get character from cl. push dx ; save dx. mov dx,lptdat ; get printer data port adr. out dx,al ; print character. pop dx ; restore dx. endif ret ; return from printer output. ; punch output is same as printer output. punch: jmps lstout ; reader input uses printer input port. reader: if not loader push dx ; save dx. mov dx,lptsts ; get printer status port adr. readlp: in al,dx ; read status. and al,lptrda ; is it ready? jz readlp ; loop if not. pop dx ; restore dx. endif ret ; ********************************************************* ; ************** get & set i/o byte contents ************** ; ********************************************************* ; return io byte (not implemented, but storage allocated). retiobt: mov al,iobyte ; al gets iobyte contents. ret ; set io byte (not implemented, but storage allocated). setiobt: mov iobyte,cl ; iobyte get contents of cl. st_ext: ret ; ********************************************************* ; ************ subroutine to print messages *************** ; ********************************************************* prtmsg: mov cl,[bx] ; get next character from string. test cl,cl ; check if zero. jz st_ext ; if zero branch to return. call conout ; print character at console. nextch: inc bx ; point to next character. jmps prtmsg ; loop till string terminator found. ; ********************************************************* ; ************* disk interface routines *************** ; ********************************************************* ; select disk & disk density of unit given by cl. seldsk: mov drvltr,cl ; save letter code (0-15). xor bx,bx ; clear bx for possible error. mov ch,0 ; clear upper cx for index. mov si,offset drvmap ; si = drive map table address. add si,cx ; si = address of entry. mov al,[si] ; get physical drive number. cmp al,0ffh ; is it undefined? jz st_ext ; error to cpm if so. mov cl,al ; get physical drive number. mov sekdsk,cl ; save new disk number. cmp cl,8 ; is it a hard disk drive? jc selflp ; hop if not. jmp hrdsel ; jump if so. selflp: mov si,cx ; si = physical drive number. mov bx,(offset drvflg) ; bx = address of density table. add bx,cx ; offset into table. and dl,fresh ; fresh access? jnz norst ; no, leave control table alone. mov hstact,0 ; clear host active flag mov word ptr unacnt,0 ; clear unallocated count. mov [bx],ch ; clear tabled control flag. mov dens[si],ch ; clear current flag. mov byte ptr diskno,0ffh ; force new controller setup. norst: mov al,[bx] ; get flag. test al,al ; check for zero. jz notlog ; skip if not logged in. jmp loged ; jump if already logged in. notlog: push bx ; save flag address. ; read stuff from track 0 to determine format of disk. mov al,cl ; get drive number. test al,4 ; is it 5 or 8-inch? jz norst5 ; hop if 5-inch. or al,8 ; set ENMF* bit. norst5: mov dx,fcont ; get floppy control port ad. out dx,al ; tell controller which disk. mov clatch,al ; save the value. mov word ptr seksec,1 ; set sector 1. mov al,stprat+hlab ; restore at fast steprate. mov dx,fdisk ; get command port adr. out dx,al ; start restore. call waitio ; wait for completion. mov bx,(offset trtab) ; get address of track table. if dual ; if persci drive and cl,2 ; index to 1 of 2 entries endif add bx,cx ; add drive offset mov byte ptr [bx],00h ; set to track 0 mov sektrk,0 ; See if it's a DR/IBM format first. test cl,4 ; is it an 8-inch drive? jnz nonibm ; hop if so. call rdadrc ; read address into chkbuf. jnz nonibm ; hop if not. ; must be DR/ibm format, so no need to do all that stuff below. mov al,clatch ; set side 1 bit in latch. or al,40h mov dx,fcont ; get latch port adr. out dx,al ; send to latch. mov clatch,al call rdadr ; read next address info. mov al,0ffh ; get double-sided DR/ibm code. jz selsid ; set sidedness. mov al,0feh ; get single-sided DR/ibm code. selsid: pop bx ; get density flag adr back. jmps selnz ; hop to figure rest of it. ; must not be DR/ibm format, so read single density sector 1. nonibm: mov al,clatch ; get current latch value. or al,10h ; set to single density. mov dx,fcont ; get latch port address. out dx,al ; set floppy control latch. mov clatch,al ; save the value. mov bx,dmaoff ; get current disk offset. push bx ; save address value. mov dmaoff,(offset chkbuf) ; use temporary buffer. mov bx,dmaseg ; get current disk segment. push bx ; save address value. mov dmaseg,cs ; get out local segment. call read ; bios read routine. pop bx ; recover original disk segment. mov dmaseg,bx ; restore to pointer. pop bx ; recover original offset. mov dmaoff,bx ; restore to pointer. pop bx ; restore density flag address. mov al,chkbuf+7eh ; get special byte from buffer. or al,al ; is it a zero? jnz selnz ; hop if not. mov al,0e5h ; big trouble for it to be zero. selnz: mov [bx],al ; put in density table. ; This is where we figure out what density and how many sides. ; Note that there are two kinds of density codes. The one ; stored in the density table at drvflg is the one that comes ; from the first sector of the floppy disk itself. The one ; that's stored at dens is different, and is coded thusly: ; bit 0 = 1 for double density, ; bit 1 = 1 for double sided, ; bit 2 = 1 for 512-byte sectors. ; bit 3 = 1 for Digital Research format for IBM-PC 5-inch. loged: mov bx,(offset dpbt5) ; 5" dpb table address. mov cl,sekdsk ; get drive number. test cl,4 ; is it 5-inch floppy? jz loged5 ; hop if so. mov bx,(offset dpbt8) ; 8" floppy dpb table address. loged5: test byte ptr [bx],0ffh ; is it last table entry (0)? jz setden ; hop out of loop if so. cmp al,[bx] ; is it this density code? jz setden ; hop out of loop if so. add bx,3 ; else to next code entry. jmps loged5 ; try the next one. setden: inc bx ; point at address. mov dx,word ptr [bx] ; get Disk Parameter Block adr. mov bx,dx ; put it in bx. mov al,[bx] ; get density byte from DPB. mov dens[si],al ; set current drive density. inc bx ; bump past density byte. xchg bx,dx ; put table pointer in dx. push dx ; save table pointer. call index ; compute addr of overlay area. pop dx ; get table pointer. xchg bx,dx ; source address in bx. mov ax,[bx] ; get xlt table pointer. xchg bx,dx ; destination address in bx. mov [bx],ax ; put xlt pointer into dph table. add bx,10 ; add offset to dpb area. add dx,2 ; bump past xlt pointer. mov [bx],dx ; put descriptor addr into dph table. mov curspc,cpmspt ; set current sectors per cylinder. index: xor bh,bh ; load disk number and zero byte. mov bl,sekdsk mov dx,(offset dphtab) ; get disk param header table adr. shl bx,1 ; drive number times 2. add bx,dx ; figure table entry address. mov dx,word ptr [bx] ; get address of dph from table. mov bx,dx ; put it in bx. ret ; return from seldsk (& other places). ; Hard disk select routine. hrdsel: if nhard gt 0 ; if one or more hard disk drives. mov curspc,cpmspc ; set current sectors/cylinder. and dl,fresh ; first access? jnz index ; return with dph adr if so. or byte ptr hstwrt,0 ; is dirty flag set? jz hrdse1 ; hop if not. push cx ; save drive to map. call writehst ; update disk. pop cx ; restore drive to map. mov byte ptr hstwrt,0 ; not dirty anymore. hrdse1: sub cl,8 ; hard disk drives 0 up. call mapper ; log in hard disk drive. jnc index ; return with address of dph. xor bx,bx ; else return with error. endif ret ; Read the next id field into chkbuf. rdadrc: mov dx,offset chkbuf ; get destination offset. mov ax,cs ; get destination segment. call comdma ; compute dma address. rdadr: mov cx,0c4d0h ; read address code. mov dx,04006h ; disk-memory, 6 bytes. call dmarwe ; read 6 bytes into chkbuf. and al,9dh ; did it read ok? ret ; home currently selected drive. home: cmp sekdsk,8 ; is it a hard disk drive? jc homed ; hop if not. or byte ptr hstwrt,0 ; write pending? jnz homed mov hstact,0 ;clear host active flag mov hsttrk,0 ; set track = 0. homed: mov cx,0 ;now, set track zero ; set track address given by cx. settrk: mov sektrk,CX ;track to seek ret ; set track sector address given by cx. setsec: mov seksec,cx ;sector to seek ret ; translate sector cx using table at [dx], result in bx. sectrn: xchg bx,cx ; use bx for intermediate. cmp sekdsk,8 ; is it a hard disk drive? jnc sc_ext ; hop if so. call setsi ; si = sekdsk. test dens[si],04h ; test for deblocked disk. jnz sc_ext ; if deblocked - no xlate. inc bl ; just bump the sector. or dx,dx ; are we using a xlat table? jz sc_ext ; no, exit with inc sector number. dec bl ; make address again. add bx,dx ; add sector # to xlate base. mov bl,[bx] ; get xlated sector from xlate table. mov bh,0 ; top is zeroed. sc_ext: mov ax,bx ; for mpm compatibility. ret ; return from sectrn. ; si = sekdsk. setsi: mov al,sekdsk ; si = sekdsk. mov ah,0 mov si,ax ret ; set dma address given by cx. setdma: mov dmaoff,cx ret ; return from setdma. ; set dma segment given by cx. setdmab: mov dmaseg,cx ret ; return from setdmab. ; return base address of segment memory table in bx. retsegt: mov bx,(offset segtab) ret ; return from retsegt. ; read the selected cp/m sector. read: cmp sekdsk,8 ; is it a hard disk? jnc readh ; hop if so. mov cx,sektrk ; get track # or cx,cx ; test for track 0 jz read1 ; if track 0 don't deblock call setsi ; si = sekdsk. test dens[si],04h ; test for deblocked jz read1 ; if not deblocked readh: mov word ptr unacnt,0 ; clear unallocated counter. mov readop,1 ; read operation mov rsflag,1 ; must read data mov wrtype,wrual ; treat as unalloc jmp rwoper ; use deblock routines ; to perform the read. read1: mov dl,sekdsk ; put drive # in dl call seekls ; seek the disk to the proper track. mov dx,dmaoff ; get destination offset. mov ax,dmaseg ; get destination segment. call comdma ; compute physical dma adr. mov ercnt,rtcnt ; reset read retry error counter. rretry: mov ax,seksec ; get sector to read mov cx,088d0h ; floppy read, force interupt cmds. mov dx,04080h ; dma read, dma count 128 bytes. call dmarw ; enter common r/w routine. mov ercode,al ; save status bits. and al,09dh ; look at error bits. jz rc_ext ; none set, return from read. dec ercnt ; decrement retry counter. jnz rretry ; if not zero retry read. mov al,1 ; read error flag. ; disk error handler: on entry al = error type. ; print type, track, sector, & status. ; set error code and return to bdos. recov: push ax ; save error flag. mov bx,(offset errmsg) call prtmsg ; error intro message. pop ax ; get flag back. xor ah,ah ; clear high bits. mov cl,7 ; table offset. mul cl ; multiply by offset. inc bx ; past eom. add bx,ax ; add offset. call prtmsg ; print the error type. mov bx,(offset drvmsg) call prtmsg ; drive message. mov cl,drvltr ; get drive letter code. add cl,'A' ; make into actual letter. call conout ; print the letter. inc bx ; past eom. call prtmsg ; track message. mov cl,trk ; get current track #. call prtdec ; print in decimal. inc bx ; past eom. call prtmsg ; sector message. mov cl,sect ; get current sector #. call prtdec ; print in decimal. inc bx ; past eom. call prtmsg ; status message. mov ah,ercode ; get status bits. mov ch,8 ; eight bits in status. bitlop: mov cl,'0' ; assume bit is 0. rol ah,1 ; test next bit. jnc prtbit ; it's off, leave 0. inc cl ; it's on, make 1. prtbit: call conout ; print bit value. dec ch ; dec bit counter. jnz bitlop ; print all bits. or al,255 ; set error code for bdos. rc_ext: ret ; convert cl to decimal and display at console. prtdec: xor ch,ch ; clear top eight bits. decout: push dx ; save value on stack. mov dx,-1 ; this becomes number / radix. sub10: sub cx,10 ; subtract 10. inc dx ; inc remainder. jnc sub10 ; loop till carry out. add cx,10 ; add radix back in. xchg dx,cx ; switch new/current. test cx,cx ; test for zero reminder. jz cndone ; if zero, conversion complete. call decout ; build bcd digits recursivly. cndone: mov cl,dl ; get bcd value. add cl,'0' ; add ascii bias. call conout ; print the digit. pop dx ; recover next bcd value. ret ; print all digits recursivly. ; ; seek floppy disk in dl to track in cl ; update track table for the drive and return with al = 0 ; if no error. otherwise print error status and return ; perform read id function to recalibrate disk if seek error. ; seekls: mov trk,cl ; save track # cmp byte ptr diskno,dl ; test for new drive jz samedsk ; not a new drive so just seek. mov byte ptr diskno,dl ; update current disk # ; new drive so get present track and seek to it to ; to inform the controller that the head is unloaded. push dx ; save dx. mov dx,ftrk ; get track register port. in al,dx ; read track register. mov dx,fdata ; get data port. out dx,al ; send track to data port. mov al,10h ; get seek command no verify mov dx,fdisk ; get command port adr. out dx,al ; do the (non) seek. call waitio ; wait till done pop dx ; restore dx. ; setup density & such samedsk: xor dh,dh ; clear dh mov si,dx ; si = drive number. if dual ; if persci drive and dl,2 ; index to 1 of 2 entries endif mov bx,(offset trtab) ; point at track table add bx,dx ; add index mov al,[bx] ; get old track # mov dx,ftrk ; get track port adr. out dx,al ; update track register. mov bl,cl ; save track # in bl mov dl,byte ptr diskno ; get drive # or dl,10h ; set single density bit. mov bh,dl ; save in bh mov al,dens[si] ; al = density type byte. test al,00001000b ; is it DR/ibm compatible? jz seekni ; hop if not DR/ibm. ; DR/ibm compatible 5-inch, so check for track greater than 39. and bh,0efh ; clear single density bit. cmp bl,ibmtpd ; is track greater than 39? jc trksd5 ; hop if not. mov al,2*ibmtpd-1 ; subtrack track no. from 80. sub al,bl mov bl,al or bh,40h ; set side select bit. jmps trksd5 ; finish below. seekni: or bl,bl ; is it track zero? jz trksd ; hop if so. test al,2 ; test for double sided jz trkss ; don't /2 if single sided ; figure track to go to and which side to select. test bl,1 ; is it an even track no? jz trkev ; hop if so. or bh,40h ; or in side select if so. trkev: shr bl,1 ; divide track by 2. trkss: test al,1 ; test for double density jz trksd ; hop if single density. and bh,0efh ; clear single density bit. trksd: test dl,4 ; is it 5 or 8-inch floppy? jz trksd5 ; hop if 5-inch floppy. or bh,8 ; set weird bit 3 if 8-inch. trksd5: mov al,bh ; get density-select code push dx ; save dx. mov dx,fcont ; get floppy control port. out dx,al ; set up the latch. mov clatch,al ; save the value. pop dx ; restore dx. mov cl,bl ; put track in cl. ; perform actual seek to track given by cl. seek: push cx ; save cx. mov sercnt,srtcnt ; reset seek retry error counter. push dx ; save dx. mov dx,ftrk ; get track register port. in al,dx ; read present track no. pop dx ; restore dx. cmp al,cl ; same as new track number? jnz nothr ; nope, go move it. pop cx ; restore cx. ret ; return from seek. nothr: ; note: this routine is to allow time for the drive ; tunnel erase to terminate before moving the ; head. the delay is aprx. 700 micro-seconds. mov ax,350 ; about 2 microseconds per loop. busy1: dec ax ; decrease count. jnz busy1 ; loop till zero. mov al,cl ; put dest. in al from cl. push dx ; save dx. mov dx,fdata ; get data port adr. out dx,al ; track to data register. mov al,14h+stprat+hlab ; seek command. mov dx,fdisk ; get command port adr. out dx,al ; set rate, seek with verify. pop dx ; restore dx. call waitio ; poll process complete. push dx ; save dx. mov dx,fdisk ; get status port adr. in al,dx ; read status. pop dx ; restore dx. mov ercode,al ; save status bits. test al,91h ; look at success bits. jnz skerr ; zero if ok. pop cx ; restore track # mov dx,diskno ; get drive index if dual ; if using persci drives. and dl,2 ; index to 1 of 2 entries endif mov bx,(offset trtab) ; point at track table add bx,dx ; add index mov [bx],cl ; update track table ret ; return seek ok. skerr: dec sercnt ; decrement error counter. jnz sretry ; retry if not zero. pop cx ; recover cx. xor al,al ; seek error flag. jmp recov ; return from seek with error set. ; re-seek. sretry: call rdadrc ; read address into chkbuf. jnc chks1 ; hop if read address ok. mov al,stprat+hlab ; restore at fast steprate. push dx ; save dx. mov dx,fdisk ; get status port. in al,dx ; read status. pop dx ; restore dx. call waitio ; wait for completion. jmps chks2 ; go re-seek track. chks1: push dx ; save dx. mov dx,fsect ; get floppy sector port. in al,dx ; read sector. mov dx,ftrk ; get floppy track port. out dx,al ; re-inform controller of proper track. pop dx ; restore dx. chks2: pop cx ; restore track #. jmp seek ; move head to it. ; ; common dma read & write subroutine. ; dmarw: ; set floppy sector register from sect. mov sect,al ; save sector #. push dx ; save dx. mov dx,fsect ; get sector port adr. out dx,al ; set sector number. pop dx ; restore dx. dmarwe: push cx ; save cx. push dx ; save dx. mov dx,fdisk ; get floppy status port. in al,dx ; read floppy status. test al,80h ; is floppy ready? jnz dma_xt ; hop out if not ready. ; get floppy port address and memory transfer address. mov al,msb20 ; get 4 hi bits of adress. mov ah,0 ; get 4 hi bits of floppy port. mov bx,lsb20 ; get 16 lo bits of address. mov cx,fdata ; get 16 lo bits of floppy port. pop dx ; get command flag and count. push dx ; save it back. test dh,80h ; is it a write or read op? mov dx,fdmard ; get dma read command. jz dmard ; must be read if bit 7=0. xchg al,ah ; exchange source and dest ptrs. xchg bx,cx mov dx,fdmawt ; get dma write command. dmard: push dx ; save on stack. ; at this point: destination=bx,al; source=cx,ah. mov dx,dmadpu0 ; get dest upper port. out dx,ax ; set destination upper. mov al,ah ; get source upper in al. mov dx,dmaspu0 ; get source upper port. out dx,ax ; set source upper. mov ax,bx ; get destinaiton lower. mov dx,dmadpl0 ; get dest lower port. out dx,ax ; set destination lower. mov ax,cx ; get source lower. mov dx,dmaspl0 ; get source lower port. out dx,ax ; set source lower. ; set dma count and command. pop bx ; restore read or write comd. pop ax ; restore transfer count. and ah,3fh ; clear old command bits. mov dx,dmatc0 ; get transfer count port. out dx,ax ; set transfer count. mov ax,bx ; get read or write command. mov dx,dmacon0 ; get dma control port. out dx,ax ; initialize dma operation. ; start floppy controller running. pop cx ; restore floppy read/write comd. mov al,ch ; get floppy read/write command. mov dx,fdisk ; get floppy command port adr. out dx,al ; start read or write operation. call waitio ; wait for read or write done. ret dma_xt: pop dx ; restore dx. pop cx ; restore cx. ret ; return from dma common. ; see if head load bit is set in 2793. ; ; write the selected cp/m sector. write: if not loader mov wrtype,cl ; save write type cmp sekdsk,8 ; is it a hard disk drive? jnc writeb ; hop if so. mov cx,sektrk ; get track # or cx,cx ; test for track 0 jz write1 ; if track 0 don't deblock call setsi ; si = sekdsk. test dens[si],04h ; test for deblocked jnz writeb write1: mov dl,sekdsk ; put drive # in dl call seekls ; seek the disk to the proper track. call precmp ; set or clear write precomp. mov dx,dmaoff ; get source offset. mov ax,dmaseg ; get source segment. call comdma ; compute physcial address. mov ercnt,rtcnt ; reset write retry error counter. wretry: mov ax,seksec ; get sector to write. mov cx,0a0d0h ; floppy write, force interrupt cmds. mov dx,08080h ; dma write, dma count byte cmds. call dmarw ; enter common r/w routine. mov ercode,al ; save status bits. and al,0fdh ; look at error bits. jz w_exit ; none set, return from write. dec ercnt ; decrement retry counter. jnz wretry ; if not zero retry write. mov al,2 ; write error flag. jmp recov ; go set error, return from write. endif ; poll for last activity completed. waitio: call fdelay ; wait for valid status. push dx ; save dx. mov dx,fdisk ; get floppy status port. waitil: in al,dx ; read status. test al,1 ; is it busy doing something? jnz waitil ; loop back if so. pop dx ; restore dx. w_exit: ret ; return from waitio. ; Provide a delay after commands for status to become valid. fdelay: push cx ; save cx. mov cx,128 ; 128 x 1.875 us = 240 us. fdloop: loop fdloop ; count down till cx=0. pop cx ; restore cx. ret ; poll for current dma activity completed. poldma: push dx ; save dx. mov dx,dmatc0 ; get transfer count port. poldml: in ax,dx ; read count register. test ax,ax ; is it zero yet? jnz poldml ; loop back if not. pop dx ; restore dx. ret ; return from poldma. ; ; deblocked read and write routines. ; ; writeb: if not loader ;write the selected CP/M sector mov readop,0 ;write operation mov cl,wrtype cmp cl,wrual ;write unallocated? jnz chkuna ;check for unalloc ; ; write to unallocated, set parameters ; call setsi ; si = sekdsk. cmp sekdsk,8 ; is it a hard disk? jnc blkset ; hop if so. test dens[si],02h ;test for double sided jnz blkset mov ax,16 ; 2048-byte blocks. jmp blkset1 blkset: mov ax,32 ; 4096-byte blocks. blkset1: test dens[si],08h ; is it DR/ibm 5-inch? jz blkset2 ; hop if not. shr ax,1 ; divide by 2 if so. blkset2: mov unacnt,ax ; save unallocated count. mov al,sekdsk ;disk to seek mov unadsk,al ;unadsk = sekdsk mov ax,sektrk mov unatrk,ax ;unatrk = sektrk mov ax,seksec mov unasec,ax ;unasec = seksec ; chkuna: ;check for write to unallocated sector ; mov bx,offset unacnt ;point "UNA" at UNACNT mov ax,[bx] ; get unallocated count. test ax,ax ;any unalloc remain? jz alloc ;skip if not ; ; more unallocated records remain dec ax ;unacnt = unacnt-1 mov [bx],ax ; set new unacnt. mov al,sekdsk ;same disk? mov BX,offset unadsk cmp al,byte ptr [bx] jnz alloc ;skip if not ; ; disks are the same mov AX,unatrk cmp AX,sektrk jnz alloc ;skip if not ; ; tracks are the same mov ax,seksec ;same sector? ; mov BX,offset unasec ;point una at unasec ; cmp ax,[bx] ; seksec = unasec? jnz alloc ;skip if not ; ; match, move to next sector for future ref inc word ptr [bx] ; unasec = unasec+1. mov ax,[bx] ; end of track? cmp ax,curspc ; count CP/M sectors. jb noovf ;skip if below ; ; overflow to next track mov word ptr [bx],0 ; unasec = 0. inc word ptr unatrk ; unatrk = unatrk+1. ; noovf: ;match found, mark as unnecessary read mov rsflag,0 ;rsflag = 0 jmps rwoper ;to perform the write endif ; alloc: ;not an unallocated record, requires pre-read mov word ptr unacnt,0 ; unacnt = 0. mov rsflag,1 ;rsflag = 1 ;drop through to rwoper ; ;***************************************************** ;* * ;* Common code for READ and WRITE follows * ;* * ;***************************************************** rwoper: ;enter here to perform the read/write mov erflag,0 ;no errors (yet) mov ax,seksec ;compute host sector mov cl,secshf shr ax,cl mov sekhst,ax ;host sector to seek ; ; active host sector? mov al,1 xchg al,hstact ;always becomes 1 test al,al ;was it already? jz filhst ;fill host if not ; ; host buffer active, same as seek buffer? mov al,sekdsk cmp al,hstdsk ;sekdsk = hstdsk? jnz nomatch ; ; same disk, same track? mov ax,hsttrk cmp ax,sektrk ;host track same as seek track jnz nomatch ; ; same disk, same track, same buffer? mov ax,sekhst cmp ax,hstsec ;sekhst = hstsec? jz match ;skip if match nomatch: ;proper disk, but not correct sector mov al,hstwrt test al,al ;"dirty" buffer ? jz filhst ;no, don't need to write call writehst ;yes, clear host buff mov al,erflag ;get error flag or al,al ;test error flag jnz return_rw ;exit on error ; filhst: ;may have to fill the host buffer mov al,sekdsk mov hstdsk,al mov ax,sektrk mov hsttrk,ax mov ax,sekhst mov hstsec,ax mov al,rsflag test al,al ;need to read? jz filhst1 ; call readhst ;yes, if 1 mov al,erflag ;get error flag or al,al ;test for error jnz return_rw ;exit on error ; filhst1: mov hstwrt,0 ;no pending write ; match: ;copy data to or from buffer depending on "readop" mov ax,seksec ;mask buffer number and ax,secmsk ;least signif bits are masked mov cl,7 shl ax,cl ;shift left 7 (* 128 = 2**7) ; ; ax has relative host buffer offset ; add ax,offset hstbuf ;ax has buffer address mov si,ax ;put in source index register mov di,dma_off ;user buffer is dest if readop ; push DS push ES ;save segment registers ; mov ES,dma_seg ;set destseg to the users seg ;SI/DI and DS/ES is swapped ;if write op mov cx,128/2 ;length of move in words mov al,readop test al,al ;which way? jnz rwmove ;skip if read ; ; write operation, mark and switch direction mov hstwrt,1 ;hstwrt = 1 (dirty buffer now) xchg si,di ;source/dest index swap mov ax,DS mov ES,ax mov DS,dma_seg ;setup DS,ES for write ; rwmove: cld rep movs AX,AX ;move as 16 bit words pop ES pop DS ;restore segment registers ; ; data has been moved to/from host buffer cmp wrtype,wrdir ;write type to directory? mov al,erflag ;in case of errors jnz return_rw ;no further processing ; ; clear host buffer for directory write test al,al ;errors? jnz return_rw ;skip if so mov hstwrt,0 ;buffer written call writehst mov al,erflag return_rw: ret ; ;***************************************************** ;* * ;* WRITEHST performs the physical write to the host * ;* disk, while READHST reads the physical disk. * ;* * ;***************************************************** ; ; write host routine - writes hsttrk,hstsec from hstbuf writehst: if not loader cmp hstdsk,8 ; is it a hard disk drive? jnc writeh ; hop if so. mov cx,hsttrk ; get track # mov dl,hstdsk ; get drive # call seekls ; seek disk to proper track call precmp ; set or clear pre-comp bit. mov dx,offset hstbuf ; get source offset. mov ax,cs ; get source segment. call comdma ; compute physical dma address. mov ercnt,rtcnt ; reset write retry error counter. wrthstrty: mov ax,hstsec ; get sector to write. inc ax ; make sectors start at 1. mov cx,0a0d0h ; floppy write, force interrupt cmds. mov dx,08200h ; dma write, dma count byte cmds. call dmarw ; go write the sector. call fdelay ; let it finish writing crc. mov ercode,al ; save status bits. and al,0fdh ; look at error bits. jz wrtret ; none set, return from write. dec ercnt ; decrement retry counter. jnz wrthstrty ; if not zero retry write. mov al,2 ; write error flag. mov erflag,01h ; set error flag jmp recov ; go set error, return from write. ; set or clear write precompensation. precmp: push dx ; save dx and ax. push ax mov dx,ftrk ; get track register port. in al,dx ; read track register. cmp al,pctrk ; do we need pre-compensation? mov al,clatch ; get current latch value. jc precno ; hop if not. or al,20h ; set bit 5. jmps precex ; write it out and exit. precno: and al,0dfh ; clear bit 5. precex: mov dx,fcont ; get latch port adr. out dx,al ; set the latch. mov clatch,al ; remember what's there. pop ax ; restore ax and dx. pop dx wrtret: ret ; Call Hard disk write routine. writeh: if nhard gt 0 ; if 1 or more hard disks. mov al,dmawrit ; set write operation. jmp hrdrw ; hard disk read/write. endif endif ; ; read host routine - reads hsttrk,hstsec to hstbuf ; readhst: cmp hstdsk,8 ; is it a hard disk drive? jnc readh2 ; hop if so. mov cx,hsttrk ; get track # mov dl,hstdsk ; get drive # call seekls ; seek disk to proper track mov dx,offset hstbuf ; get destination offset. mov ax,cs ; get destination segment. call comdma ; compute physical dma address. mov ercnt,rtcnt ; reset read retry error counter. rdhstrty: mov ax,hstsec ; get sector to read inc ax ; make sectors start at 1. mov cx,088d0h ; floppy read, force interupt cmds. mov dx,04200h ; dma read, dma count 512 bytes. call dmarw ; go read the sector. mov ercode,al ; save status bits. and al,09dh ; look at error bits. jz return_hst ; none set, return from read. dec ercnt ; decrement retry counter. jnz rdhstrty ; if not zero retry read. mov al,1 ; read error flag. mov erflag,01h ; set error flag jmp recov ; go to read recovery routine return_hst: ret ; Call hard disk read routine. readh2: if nhard gt 0 ; if 1 or more hard disks. mov al,dmaread ; set read operation. hrdrw: mov byte ptr mwop,al mov cl,hstdsk ; get disk number. sub cl,8 ; make it hard disk drive no. jmp findalt ; do common read/write. endif ;************ HARD DISK DRIVER AREA ************************ if nhard gt 0 if mrms12 ; if Morrow and RMS-12. include mw12r endif if mcmi19 ; if Morrow and CMI-19. include mw19 endif if mrod20 ; if Mowrrow and Rodime-20. include mw20 endif if mq540 ; if Morrow and Quantum Q540. include mwq540 endif endif ;*********** END OF HARD DISK DRIVER AREA ****************** ; bios data area. data_offset equ (offset $) dseg org data_offset ; start of data segment area. ; loader & system messages. if loader ; start condition (loader_true). signon db cr,lf,'LDBIOS of 4-9-85',cr,lf,0 endif ; end condition (loader_true). if not loader ; start condition (loader_false). signon db cr,lf,'Duplex 816 BIOS of 4-9-85',cr,lf db '(c) 1984 Tarbell Electronics',cr,lf db 'Support for:',cr,lf if nflop5 gt 0 db ' 5-inch diskettes',cr,lf endif if nflop8 gt 0 db ' 8-inch diskettes',cr,lf endif if nhard gt 0 if mrms12 ; if morrow and RMS-12. db ' RMS-12 hard disk',cr,lf endif if mcmi19 ; if morrow and CMI-19. db ' CMI-19 hard disk',cr,lf endif if mrod20 ; if morrow and Rodime-20. db ' Rodime-20 hard disk',cr,lf endif if mq540 ; if morrow and Quantum Q540. db ' Quantum Q-540 hard disk',cr,lf endif endif db cr,lf,'CP/M-86 vs 1.1',cr,lf db '(c) 1983 Digital Research',cr,lf,0 trpmsg db cr,lf,7 db 'BIOS detected undefined interrupt' db cr,lf,0 endif ; end conditions. errmsg db cr,lf db 'error during ',0 db 'seek: ',0 ; error 0. db 'read: ',0 ; error 1. db 'write:',0 ; error 2. drvmsg db ' drive ',0 db ', track ',0 db ', sector ',0 db ', status ',0 ; disk control storage. drvflg db 0,0,0,0,0,0,0,0 ; density info for 8 floppies. dens db 0,0,0,0,0,0,0,0 ; density bits for 8 floppies. diskno dw 0 ; current disk number and zero byte. sect db 0 ; current real sector #. trk db 0 ; head position for selected drive. trtab db 0,0,0,0,0,0,0,0 ; head position info for 8 floppies. ercnt db 0 ; counter for r/w retrys. sercnt db 0 ; counter for seek retrys. drvltr db 0 ; letter code for error printout. latch db 0 ; new code for latch. clatch db 0 ; current code in latch. iobyte db 0 ; system i/o redefinition byte. ercode db 0 ; last error result bits. msb20 db 0 ; dma abs bits a16-a19. lsb20 dw 0 ; dma abs bits a00-a15. ; Logical (letter) to physical (number) drive map. ; These should always stay in this order. To change ; the map, change the EQU's at the beginning of BIOS. drvmap db drivea ; drive a number. db driveb ; drive b number. db drivec ; drive c number. db drived ; drive d number. db drivee ; drive e number. db drivef ; drive f number. db driveg ; drive g number. db driveh ; drive h number. db drivei ; drive i number. db drivej ; drive j number. db drivek ; drive k number. db drivel ; drive l number. db drivem ; drive m number. db driven ; drive n number. db driveo ; drive o number. db drivep ; drive p number. ; sek_dsk rb 1 ;seek disk number sek_trk rw 1 ;seek track number sek_sec rw 1 ;seek sector number ; hst_dsk rb 1 ;host disk number hst_trk rw 1 ;host track number hst_sec rw 1 ;host sector number ; sek_hst rw 1 ;seek shr secshf hst_act rb 1 ;host active flag hst_wrt rb 1 ;host written flag ; una_cnt rw 1 ;unalloc rec cnt una_dsk rb 1 ;last unalloc disk una_trk rw 1 ;last unalloc track una_sec rw 1 ;last unalloc sector ; curspc rw 1 ; current cpm sectors/cylinder. erflag rb 1 ;error reporting rsflag rb 1 ;read sector flag readop rb 1 ;1 if read operation wrtype rb 1 ;write operation type dma_seg rw 1 ;last dma segment dma_off rw 1 ;last dma offset ; system memory segment discriptor table. segtab db 1 ; 1 segments. tpabas dw tpaseg ; 1st segment starts after bios. memlen dw tpalen ; and extends to 08000. ; Disk Parameter Header (DPH) address table. ; these tables allow bdos to index the drive attrib info tables. dphtab dw (offset dph0) ; 5-inch floppy 0. dw (offset dph1) ; 5-inch floppy 1. dw (offset dph2) ; 5-inch floppy 2. dw (offset dph3) ; 5-inch floppy 3. dw (offset dph4) ; 8-inch floppy 0. dw (offset dph5) ; 8-inch floppy 1. dw (offset dph6) ; 8-inch floppy 2. dw (offset dph7) ; 8-inch floppy 3. if nhard gt 0 ; if 1 or more hard disks. dw (offset dph8) ; hard disk 0. endif if nhard gt 1 ; if 2 or more hard disks. dw (offset dph9) ; hard disk 1. endif if nhard gt 2 ; if 3 or more hard disks. dw (offset dph10) ; hard disk 2. endif if nhard gt 3 ; if 4 or more hard disks. dw (offset dph11) ; hard disk 3. endif if nhard gt 4 ; if 5 or more hard disks. dw (offset dph12) ; hard disk 4. endif if nhard gt 5 ; if 6 or more hard disks. dw (offset dph13) ; hard disk 5. endif if nhard gt 6 ; if 7 or more hard disks. dw (offset dph14) ; hard disk 6. endif if nhard gt 7 ; if 8 hard disks. dw (offset dph15) ; hard disk 7. endif ; - 5-inch floppy diskette - unit 0. dph0 equ (offset $) if nflop5 gt 0 dw (offset xlt5),0 dw 0,0 dw (offset dirbuf),0 dw (offset csv0),(offset alv0) endif ; 5-inch floppy unit 1. dph1 equ (offset $) if nflop5 gt 1 dw (offset xlt5),0 dw 0,0 dw (offset dirbuf),0 dw (offset csv1),(offset alv1) endif ; 5-inch floppy unit 2. dph2 equ (offset $) if nflop5 gt 2 dw (offset xlt5),0 dw 0,0 dw (offset dirbuf),0 dw (offset csv2),(offset alv2) endif ; 5-inch floppy unit 3. dph3 equ (offset $) if nflop5 gt 3 dw (offset xlt5),0 dw 0,0 dw (offset dirbuf),0 dw (offset csv3),(offset alv3) endif ; - 8-inch floppy diskette - unit 0. dph4 equ (offset $) if nflop8 gt 0 dw (offset xlt8),0000h ; translate table. dw 0000h,0000h ; scratch area. dw (offset dirbuf),0 ; dir buff, parm block. dw (offset csv4),(offset alv4) ; check, alloc vectors. endif ; - 8-inch floppy diskette - unit 1. dph5 equ (offset $) if nflop8 gt 1 ; start condition (nflop>1_true). dw (offset xlt8),0000h ; translate table. dw 0000h,0000h ; scratch area. dw (offset dirbuf),0 ; dir buff, parm block. dw (offset csv5),(offset alv5) ; check, alloc vectors. endif ; end condition (nflop>1_true). ; - 8-inch floppy diskette - unit 2. dph6 equ (offset $) if nflop8 gt 2 ; start condition (nflop>2_true). dw (offset xlt8),0000h ; translate table. dw 0000h,0000h ; scratch area. dw (offset dirbuf),0 ; dir buff, parm block. dw (offset csv6),(offset alv6) ; check, alloc vectors. endif ; end condition (nflop>2_true). ; - 8-inch floppy diskette - unit 3. dph7 equ (offset $) if nflop8 gt 3 ; start condition (nflop>3_true). dw (offset xlt8),0000h ; translate table. dw 0000h,0000h ; scratch area. dw (offset dirbuf),0 ; dir buff, parm block. dw (offset csv7),(offset alv7) ; check, alloc vectors. endif ; end condition (nflop>3_true). ; Disk Parameter Blocks (DPB's). ; these tables define the drive physical attributes. ; 5-inch table of disk parameter block addresses. dpbt5 equ (offset $) if nflop5 gt 0 db 0feh ; ibm code for ss 8-sector. dw offset f5i8ss db 0ffh ; ibm code for ds 8-sector. dw offset f5i8ds db 0deh ; 512 deblocked single sided. dw (offset f5dbss) db 0dch ; 512 deblocked double sided. dw (offset f5dbds) db 00h ; default to sd ss. dw (offset f5sdss) endif ; 8-inch table of disk parameter block addresses. dpbt8 equ (offset $) if nflop8 gt 0 db 0e7h ; single density double sided. dw (offset f8sdds) db 0ddh ; double density single sided. dw (offset f8ddss) db 0dfh ; double density double sided. dw (offset f8ddds) db 0deh ; 512 deblocked single sided. dw (offset f8dbss) db 0dch ; 512 deblocked double sided. dw (offset f8dbds) db 00h ; default to sd ss. dw (offset f8sdss) endif if nflop5 gt 0 ; 5-inch disk parameter blocks. ; 5-inch IBM Format 512 x 8 double density single sided floppy. f5i8ss db 00001101b ; format code. dw 0 ; no translate table. dw 32 ; 128-byte sectors per track. db 3 ; block shift factor. db 7 ; block mask. db 0 ; null mask. dw 155 ; disk size - 1. dw 63 ; directory max. db 11000000b ; alloc 0. db 0 ; alloc 1. dw 16 ; check size. dw 1 ; track offset. ; 5-inch IBM Format 512 x 8 double density double sided floppy. f5i8ds db 00001111b ; our internal format code. dw 0 ; no translate table. dw 32 ; 128-byte sectors per cylinder. db 4 ; block shift factor for 2k blocks. db 15 ; block mask for 2k blocks. db 1 ; null mask. dw 009dh ; disk size - 1. dw 63 ; directory max. db 10000000b ; alloc 0. db 0 ; alloc 1. dw 16 ; check size. dw 1 ; track offset. ; 5-inch 512 x 10 double density single sided floppy. f5dbss db 5 ; format code. dw 0 ; no translate table. dw 40 ; sectors per track. db 4 ; block shift factor. db 15 ; block mask. db 0 ; null mask. dw 94 ; disk size-1. dw 81 ; directory max. db 11000000b ; alloc 0. db 0 ; alloc 1. dw 32 ; check size. dw 2 ; track offset. ; 5-inch 512 x 10 double density, double sided floppy. f5dbds db 7 ; format code. dw 0 ; no translate table. dw 40 ; sectors per track. db 5 ; block shift factor. db 31 ; block mask. db 0 ; extent mask. dw 94 ; disk size - 1. dw 81 ; directory max. db 11000000b ; alloc 0. db 0 ; alloc 1. dw 32 ; check size. dw 2 ; track offset. ; 5-inch 128 x 18 single density, single sided floppy. f5sdss db 0 ; format code. dw offset xlt5 ; translate table. dw 18 ; sectors per track. db 3 ; block shift factor. db 7 ; block mask. db 0 ; null mask. dw 71 ; disk size - 1. dw 63 ; directory max. db 11000000b ; alloc 0. db 0 ; alloc 1. dw 16 ; check size. dw 3 ; track offset. endif ; end of 5-inch disk parameter blocks. if nflop8 gt 0 ; 8-inch disk parameter blocks. ; 8-inch single density, double sided floppy diskette. f8sdds db 2 ; log byte - single density/double sided. dw (offset xlt8) ; use single density translate table. dw 0026 ; sectors/track. db 0004 ; block shift. db 0015 ; block mask. db 0000 ; extnt mask. dw 0242 ; disk size - 1. dw 0095 ; directory max. db 0192 ; alloc0. db 0000 ; alloc1. dw 0024 ; check size. dw 0002 ; number of system tracks. ; 8-inch double density, single sided floppy diskette. f8ddss db 1 ; log byte - double density/single sided. dw 0000 ; no sector translate table. dw 0051 ; 51 sectors. db 0004 ; block shift. db 0015 ; block mask. db 0000 ; extnt mask. dw 0237 ; disk size - 1. dw 0127 ; directory max. db 0192 ; alloc0. db 0000 ; alloc1. dw 0032 ; check size. dw 0002 ; number of system tracks. ; 8-inch double density, double sided floppy diskette. f8ddds db 3 ; log byte - double density/sided sided. dw 0000 ; no sector translate table. dw 0051 ; 51 sectors. db 0005 ; block shift. db 0031 ; block mask. db 0000 ; extnt mask. dw 0237 ; disk size - 1. dw 0095 ; directory max. db 0192 ; alloc0. db 0000 ; alloc1. dw 0024 ; check size. dw 0002 ; number of system tracks. ; 8-inch 512 x 16 single sided diskette. f8dbss db 5 ; log byte - 512 x 16 single sided dw 0000 ; no sector translate table. dw 0064 ; 64 - 128 byte sectors. db 0004 ; block shift. db 0015 ; block mask. db 0000 ; extnt mask. dw 0299 ; disk size - 1. dw 0127 ; directory max. db 0192 ; alloc0. db 0000 ; alloc1. dw 0032 ; check size. dw 0002 ; number of system tracks. ; 8-inch 512 x 16 double sided diskette. f8dbds db 7 ; log byte - 512 x 16 double sided dw 0000 ; no sector translate table. dw 0064 ; 64 - 128 byte sectors. db 0005 ; block shift. db 0031 ; block mask. db 0000 ; extnt mask. dw 0303 ; disk size - 1. dw 0169 ; directory max. db 0192 ; alloc0. db 0000 ; alloc1. dw 0042 ; check size. dw 0002 ; number of system tracks. ; 8-inch single density, single sided floppy diskette. f8sdss db 0 ; log byte - single density/single sided. dw (offset xlt8) ; use single density translate table. dw 0026 ; sectors/track. db 0003 ; block shift. db 0007 ; block mask. db 0000 ; extnt mask. dw 0242 ; disk size - 1. dw 0063 ; directory max. db 0192 ; alloc0. db 0000 ; alloc1. dw 0016 ; check size. dw 0002 ; number of system tracks. endif ; end of 8-inch disk parameter blocks. ; provide sector translation for single density access. ; 5-inch if nflop5 gt 0 xlt5 db 1,4,7,10,13,16 db 2,5,8,11,14,17 db 3,6,9,12,15,18 endif ; 8-inch if nflop8 gt 0 xlt8 db 01,07,13,19,25,05 db 11,17,23,03,09,15 db 21,02,08,14,20,26 db 06,12,18,24,04,10 db 16,22 endif als5 equ 39 ; 5-inch allocation vector size. css5 equ 42 ; 5-inch check vector size. als8 equ 39 ; 8-inch allocation vector size. css8 equ 42 ; 8-inch check vector size. ; Buffers. dirbuf rs hstsiz ; (128) directory buffer. hstbuf rb hstsiz ; host buffer chkbuf rb chksiz ; buffer to check disk density code. if nflop5 gt 0 alv0 rs als5 csv0 rs css5 endif if nflop5 gt 1 alv1 rs als5 csv1 rs css5 endif if nflop5 gt 2 alv2 rs als5 csv2 rs css5 endif if nflop5 gt 3 alv3 rs als5 csv3 rs css5 endif if nflop8 gt 0 alv4 rs als8 csv4 rs css8 endif if nflop8 gt 1 alv5 rs als8 csv5 rs css8 endif if nflop8 gt 2 alv6 rs als8 csv6 rs css8 endif if nflop8 gt 3 alv7 rs als8 csv7 rs css8 endif locstk rw 32 ; local stack for ini. stkbase equ (offset $) ; define stack base address. lastoff equ (offset $) ; last used area address. tpaseg equ (lastoff+0400h+15) / 16 tpalen equ 0800h - tpaseg ; compute start and length of main tpa. tpaoff equ tpaseg ; offset in paragraphs to end of cp/m-86. db 0 ; fill to last for gencmd. ; assign external address locations. dseg 0 ; obtain absolute low memory. org 0 ; for interrupt vector ini info. int0_offset rw 1 ; interrupt offset address. int0_segment rw 1 ; interrupt segment address. rw 2*(bdos_int-1) ; pad to the system entry vector. bdos_offset rw 1 ; bdos offset address. bdos_segment rw 1 ; bdos segment address. ; end