*****************************************************************************
;
; CP/M 2.2 BIOS for iCOM FD3712 drive cabinet with Altair serial I/O.
;
;   Full IOBYTE support is provided to allow use with a variety of Altair
;   I/O ports. The send-null flag bytes forces the BIOS to send a NULL
;   after CR to support a Teletype as the console. The MODE byte allows
;   selection of auto-run commands at cold start and/or warm start. Writes
;   can be optionally verified based on the fWRTVFY bit in the MODE byte.
;
;   MODE byte, default IOBYTE, send-null flag locations for patching:
;	33h, 34h, 35h from start of BIOS
;	1FB3h, 1FB4h, 1FB5h in memory after MOVCPM
;
;   The available IOBYTE assignments are shown below. The default assign-
;   ments are indicated by *
;
;   CON device (bits 1,0):                PUN device (bits 5,4):
;     00 - TTY on 88-SIO at 0/1             00 - TTY on 88-SIO at 0/1
;     01 - CRT on 88-2SIO at 10h/11h*       01 - PTP on 88-2SIO at 10h/11h*
;     10 - BAT (indirect through RDR,LST)   10 - UP1 on cassette (SIO at 6/7)
;     11 - UC1 on 88-2SIO at 12h/13h        11 - UP2 on 88-2SIO at 12h/13h
;
;
;   RDR device (bits 3,2):                LST device (bits 7,6):
;     00 - TTY on 88-SIO at 0/1             00 - TTY on 88-SIO at 0/1
;     01 - PTR on 88-2SIO at 10h/11h*       01 - CRT on 88-2SIO at 10h/11h
;     10 - UR1 on cassette (SIO at 6/7)     10 - LPT on 88-2SIO at 12h/13h*
;     11 - UR2 on 88-2SIO at 12h/13h        11 - UL1 on 88-LPC at 2/3
; 
;   *Default IOBYTE
;
;   To patch an update to this BIOS into a CP/M image created and saved
;   by running MOVCPM, use the following commands:
;
;	A>DDT CPM56.COM    (specify the saved CP/M image file)
;	-IBIOS.HEX
;	-Rxxxx      	   (xxxx = the value of the BIAS equate below)
;	-G0		   (Go zero, not "oh")
;
;	Ver	  Date		     Description
;	---	----------	------------------------------------------
;	1.0 	02/10/2021	Mike Douglas, Original
;
;****************************************************************************

;  Assembly options

MEMSIZE	equ	48		;memory size in K bytes
BIOSLEN	equ	400h		;length of this BIOS

;  CP/M location equates

CCPLEN	equ	0800h		;CPM 2.2 fixed length
BDOSLEN	equ	0E00h		;CPM 2.2 fixed length
BIOSBAS	equ	MEMSIZE*1024 - BIOSLEN
BDOSBAS	equ	BIOSBAS-BDOSLEN
CCPBASE	equ	BDOSBAS-CCPLEN

BIAS	equ	0980h-CCPBASE

; CP/M page zero equates

WBOOTV	equ	00h		;warm boot vector location
BDOSV	equ	05h		;BDOS entry vector location
CDISK	equ	04h		;CPM current disk
DEFDMA	equ	80h		;default dma address
IOBYTE	equ	03h		;location of IOBYTE on page 0

; CP/M (logical) disk information

NUMDISK	equ	4		;four drives supported
NUMTRK	equ	77		;number of tracks on the disk
NUMSEC	equ	26		;logical (128 byte) sectors per track
SECLEN	equ	128		;CP/M sector length

; IOBYTE shift values

SHFTCON	equ	1		;left rotate count to align CON in bits 2,1
SHFTRDR	equ	7		;left rotate count to align RDR in bits 2,1
SHFTPUN	equ	5		;left rotate count to align PUN in bits 2,1
SHFTLST	equ	3		;left rotate count to align LST in bits 2,1

; 2SIO Serial Board 

SIO1CTL	equ	10h		;1st port on 2SIO board - control register
SIO1DAT	equ	11h		;1st port on 2SIO board - data register

SIO2CTL	equ	12h		;2nd port on 2SIO board - control register
SIO2DAT	equ	13h		;2nd port on 2SIO board - data register

SIORDRF	equ	01h		;read data register full flag
SIOTDRE	equ	02h		;transmit data register empty flag

; SIO Serial Board 

SIOCTL	equ	00h		;SIO board at 0 - control register
SIODAT	equ	01h		;SIO board at 0 - data register

ACRCTL	equ	06h		;SIO board at 6 - control register (cassette)
ACRDAT	equ	07h		;SIO board at 6 - data register (cassette)

SIORCV	equ	01h		;data received bit (inverted)
SIOXMT	equ	80h		;read to transmit (inverted)

; LPC Line Printer Controller

LPCCTL	equ	02h		;line printer control port
LPCDAT	equ	03h		;line printer data port

LPCBSY	equ	02h		;mask to test printer busy flag

; Miscellaneous equates

CR	equ	13		;ascii for carriage return
LF	equ	10		;ascii for line feed

;-----------------------------------------------------------------------------
; Interface board PROM jump table 
;-----------------------------------------------------------------------------
	org	0F010h		;interface board PROM vector base

pCOLD	ds	3		;cold start
pWARM	ds	3		;warm start
pCONST	ds	3		;console status
pCONIN	ds	3		;console character in (and disk flush)
pCONOUT	ds	3		;console character out
pLIST	ds	3		;list character out
pPUNCH	ds	3		;punch character out
pREADER	ds	3		;reader character in
pHOME	ds	3		;move head to home position
pSELDSK	ds	3		;select disk
pSETTRK	ds	3		;set track number
pSETSEC	ds	3		;set sector number
pSETDMA	ds	3		;set dma address
pREAD	ds	3		;read sector
pWRITE	ds	3		;write sector

pMODE	equ	0F42Fh		;mode byte in interface board RAM

;-----------------------------------------------------------------------------
;  BIOS jump table
;-----------------------------------------------------------------------------
	org	BIOSBAS

	jmp	cBoot		;cold start
wbAddr	jmp	wBoot		;warm start
	jmp	conSt		;console status
	jmp	conIn		;console character in 
	jmp	conOut		;console character out
	jmp	list		;list character out
	jmp	punch		;punch character out
	jmp	reader		;reader character in
	jmp	home		;move head to home position
	jmp	selDsk		;select disk
	jmp	pSETTRK		;set track number
	jmp	pSETSEC		;set sector number
	jmp	pSETDMA		;set dma address
	jmp	pREAD		;read disk
	jmp	pWRITE		;write disk
	jmp	listSt		;return list status
	jmp	secTran		;sector translate

;---------------------------------------------------------------------------
; MODE byte - At offset 33h from start of BIOS
;---------------------------------------------------------------------------
fCLDCMD	equ	01h		;true = CCP process cmd on cold start
fWRMCMD	equ	02h		;true = CCP process cmd on warm start
fWRTVFY	equ	40h		;true = verify writes

mode	db	00h		;default value of mode byte

;---------------------------------------------------------------------------
; IOBYTE - At offset 34h from start of BIOS. See IOBYTE information
;    in the header of this source file
;---------------------------------------------------------------------------
defIob	db	95h		;default value of IOBYTE

;----------------------------------------------------------------------------
; sndNull flag - At offset 35h from start of BIOS.
;    Determines if a NULL should be transmitted following a CR when
;    writing to the console device. The end user can patch this byte
;    to nonzero for Teletype support
;----------------------------------------------------------------------------
sndNull	db	0		;non-zero if null should be sent after CR

;----------------------------------------------------------------------------
; cBoot - Cold boot BIOS entry. CPM is already loaded in memory. Hand
;    control to the CCP.
;----------------------------------------------------------------------------
cBoot	lxi	sp,0100h	;init stack pointer

	xra	a
	sta	CDISK		;current CPM disk is drive zero

	mvi	a,03h		;reset 2SIO ports
	out	SIO1CTL
	out	SIO2CTL
	mvi	a,11h		;select 8N2
	out	SIO1CTL
	out	SIO2CTL

	lda	defIob		;initialize IOBYTE on page 0
	sta	IOBYTE

	lda	mode		;initialize mode byte in interface
	sta	pMODE		;   board RAM		

	call	dispMsg		;display welcome message
	db	CR,LF,LF
	db	MEMSIZE/10 + '0',MEMSIZE mod 10 + '0'
	db	'K CP/M 2.2 v1.0',CR,LF
	db	'for iCOM FD3712 and Altair',CR,LF,0

; Determine whether or not execution of a cold start command line is
;    requested, then enter CP/M.

	lda	mode		;see if cold start command line requested
	ani	fCLDCMD
	push	psw		;save result

	jmp	coldCpm		;enter CP/M

;--------------------------------------------------------------------------
; wBoot - Warm boot BIOS entry. Reload CPM from disk up to, but
;    not including the BIOS. Re-enter CPM after loading.
;--------------------------------------------------------------------------
wBoot	lxi	sp,0100h	;init stack pointer
	mvi	c,0		;select drive 0
	call	pSELDSK
	mvi	c,0		;set track 0
	call	pSETTRK
	
	lxi	h,CCPBASE+SECLEN   ;HL=address for trk 0, sec 3
	mvi	a,3		;start on sector 3
	call	loadTrk		;load track 0

	mvi	c,1		;step to track 1
	call	pSETTRK
	
	lxi	h,CCPBASE+SECLEN*(NUMSEC-1)  ;HL=address for trk 1, sec 1
	mvi	a,1		;start on sector 1
	call	loadTrk		;load track 1

; Enter CPM. Set page zero variables, enter CPM with or without a command
;   line based on MODE flags.

	lda	mode		;see if warm start command line requested
	ani	fWRMCMD
	push	psw		;save result

coldCpm	lxi	b,DEFDMA	;set the default dma address (080h)
	call	pSETDMA

	mvi	a,JMP		;8080 "jump" opcode
	sta	WBOOTV		;store in 1st byte of warm boot vector
	sta	BDOSV		;and 1st byte of bdos entry vector

	lxi	h,wbAddr	;get the warm boot address
	shld	WBOOTV+1	;and put it after the jump

	lxi	h,BDOSBAS+6	;BDOS entry address
	shld	BDOSV+1		;put it after the jump opcode

	lda	CDISK		;get current disk number
	mov	c,a		;pass it to CPM in register c

	pop	psw		;restore command line test
	jz	CCPBASE+3	;enter CCP and don't run command line
	jmp	CCPBASE		;enter CCP with possible cmd line

;--------------------------------------------------------------------------
; loadTrk - Load the current track starting on the sector passed 
;   in C. The starting sector should be odd. Every other sector is
;   read (e.g., 3,5,7...25,2,4,6...24,26).
;--------------------------------------------------------------------------
loadTrk	mov	c,a		;C=sector		

	mov	a,h		;A=MSB of next address to read
	cpi	BIOSBAS shr 8	;compare to BIOS address
	jnc	ltSkip		;within BIOS, skip read

	push	h		;preserve HL and BC
	push	b	
	call	pSETSEC		;set sector
	
	mov	b,h		;set DMA address 
	mov	c,l
	call	pSETDMA		;set address
	
	call	pREAD		;read sector
	pop	b		;restore BC and HL
	pop	h
	jnz	wBoot		;start over if read error

ltSkip	lxi	d,2*SECLEN	;interleave of 2
	dad	d		;HL->address for next sector
	
	mvi	a,2		;interleave of 2
	add	c
	cpi	NUMSEC+1	;past last sector?
	jc	loadTrk		;no, read next sector

	sui	NUMSEC-1	;wrap around last sector
	lxi	d,-(SECLEN*(NUMSEC-1))
	dad	d		;compute address after wrap
	cpi	2		;first wrap?
	jz	loadTrk		;yes, keep going
	
	ret

;----------------------------------------------------------------------------
; seldsk - Select Disk BIOS entry. C contains the disk number to select.
;    Validate the disk number and return a pointer to the disk parameter
;    header in HL. Zero is returned in HL for invalid drive number. The
;    disk number is stored in drvNum. No drive activity takes place.
;----------------------------------------------------------------------------
seldsk	lxi	h,0		;hl of zero is error flag
	mov	a,c		;A=drive number
	cpi	NUMDISK		;verify drive number less than number of disks
	rnc			;invalid drive number, return with HL=0=error
	
	call	pSELDSK		;give drive to the PROM select routine
	
	mov	a,c		;compute disk parameter header address
	rlc			;   as (16*drvNum) + dpHead
	rlc
	rlc
	rlc
	lxi	h,dpHead  	;HL->start of disk parameter headers
	mov	e,a
	mvi	d,0
	dad	d		;HL->DPH for the passed drive number
	ret

;----------------------------------------------------------------------------
; home - Home BIOS entry. Set trkNum to zero. No drive activity takes place.
;----------------------------------------------------------------------------
home	mvi	c,0
	jmp	pSETTRK		;set track to zero and exit

;----------------------------------------------------------------------------
; sectran - Sector translation BIOS entry. Convert zero-indexed logical 
;    sector number in BC to a sector number in HL based on the translate
;    table passed in DE.
;----------------------------------------------------------------------------
sectran	xchg			;HL->translate table
	mvi	b,0		;make sure msb of sector is zero
	dad	b		;HL->translated sector num
	mov	l,m		;L=lsb of sector
	mov	h,b		;H=0=msb of sector
	ret

;---------------------------------------------------------------------------
;  CON device I/O
;---------------------------------------------------------------------------

; conSt - Console status BIOS entry point. Return FFh if character ready,
;    return zero otherwise. 

conSt	mvi	b,SHFTCON	;B=console IOBYTE alignment shift count
	call	doIo		;call the proper I/O routine below

	dw	sioSt		;TTY use SIO at I/O address 0
	dw	sio1St		;CRT use 2SIO port 1
	dw	batchSt		;BAT indirect through RDR logical device
	dw	sio2St		;UC1 use 2SIO port 2

; conIn - Console input BIOS entry point. Wait for console input and
;    return character in A.

conIn	mvi	b,SHFTCON	;B=console IOBYTE alignment shift count
	mvi	c,07Fh		;C=AND mask for input byte
	call	doIo		;call the proper I/O routine below

	dw	sioIn		;TTY use SIO at I/O address 0
	dw	sio1In		;CRT use 2SIO port 1
	dw	reader		;BAT indirect through RDR logical device
	dw	sio2In		;UC1 use 2SIO port 2

; conOut - Console output BIOS entry point. Output the character in C.
;   If the sndNull flags is true, then follow CR with a null for Teletype.

conOut	call	doConO		;send the character passed in C

	lda	sndNull		;sending null for CR?
	ora	a
	rz			;no, exit
	
	mov	a,c		;was character a CR?
	sui	CR
	rnz			;no, exit

	mov	c,a		;else, send a null
				;fall into doConO

doConO	mvi	b,SHFTCON	;B=console IOBYTE alignment shift count
	call	doIo		;call the proper I/O routine below

	dw	sioOut		;TTY use SIO at I/O address 0
	dw	sio1Out		;CRT use 2SIO port 1
	dw	list		;BAT indirect through LST logical device
	dw	sio2Out		;UC1 use 2SIO port 2

;---------------------------------------------------------------------------
; RDR device - Reader input character BIOS entry point. Return in A
;---------------------------------------------------------------------------
reader	mvi	b,SHFTRDR	;B=reader IOBYTE alignment shift count
	mvi	c,0FFh		;C=AND mask for input byte
	call	doIo		;call the proper I/O routine below

	dw	sioIn		;TTY SIO at I/O address 0
	dw	sio1In		;PTR use 2SIO port 1
	dw	acrIn		;UR1 use cassette port (SIO 6/7)
	dw	sio2In		;UR2 use 2SIO port 2 

;---------------------------------------------------------------------------
; PUN device - Punch output character BIOS entry point. Byte to send in C.
;---------------------------------------------------------------------------
punch	mvi	b,SHFTPUN	;B=punch IOBYTE alignment shift count
	call	doIo		;call the proper I/O routine below

	dw	sioOut		;TTY SIO at I/O address 0
	dw	sio1Out		;PTP use 2SIO port 1
	dw	acrOut		;UP1 use cassette port (SIO 6/7)
	dw	sio2Out		;UP2 use 2SIO port 2

;---------------------------------------------------------------------------
;  LST device I/O
;---------------------------------------------------------------------------

; listSt - List output test BIOS entry point. Return 0FFh if list device
;    is ready, 0 if not ready

listSt	mvi	b,SHFTLST	;B=list IOBYTE alignment shift count
	call	doIo		;call the proper I/O routine below

	dw	sioOSt		;TTY use SIO at I/O address 0
	dw	sio1OSt		;CRT use 2SIO port 1
	dw	sio2OSt		;LPT use 2SIO port 2
	dw	lpcOSt		;UL1 use LPC board

; list - List output character BIOS entry point. Send the character
;    passed in C out the list port

list	mvi	b,SHFTLST	;B=list IOBYTE alignment shift count
	call	doIo		;call the proper I/O routine below

	dw	sioOut		;TTY use SIO at I/O address 0
	dw	sio1Out		;CRT use 2SIO port 1
	dw	sio2Out		;LPT use 2SIO port 2
	dw	lpcOut		;UL1 use LPC board

;---------------------------------------------------------------------------
;  BAT device I/O - The BAT device is assigned as a physical device
;     for CON. However, BAT is actually a logical device that uses
;     whatever RDR is assigned to for input and whatever LST is assigned
;     to for output. The only jump table that does not already exist
;     is the input test routine for the reader devices
;---------------------------------------------------------------------------

; batchSt - BAT device input status

batchSt	mvi	b,SHFTRDR	;BAT in uses RDR device
	call	doIo		;call the proper I/O routine below

	dw	siost		;TTY test SIO at I/O address 0	
	dw	sio1St		;RDR test 2SIO port 1
	dw	acrSt		;UR1 test cassette port (SIO 6/7)
	dw	sio2St		;UR2 test 2SIO port 2

;---------------------------------------------------------------------------
; doIo - Perform physical I/O device based on the IOBYTE. The value passed
;    in B contains the left-shift count to align the calling device's IOBYTE
;    field into bits 2 and 1 (not 1 and 0). Preserves H,L
;--------------------------------------------------------------------------- 
doIo	lda	IOBYTE		;A=CP/M IO BYTE

ioAlign	rlc			;rotate into bits 2 and 1
	dcr	b
	jnz	ioAlign

	ani	6		;get the 2 bit field alone

; 2 bit field aligned in bits 2 and 1. Index into jump table of caller.

	xthl			;HL->jump table, save original HL

	mov	e,a		;form DE=table offset
	mvi	d,0
	dad	d		;HL->address in table based on IOBYTE

	mov	e,m		;E=lsb of where to jump
	inx	h
	mov	d,m		;D=msb of where to jump
	xchg			;HL->where to jump

	xthl			;jump address on stack, restore HL
	ret			;jump to address specified in table

;---------------------------------------------------------------------------
; Input status routines
;---------------------------------------------------------------------------

; sio1St - Console status routine for 2SIO port 1. Return FFh 
;    if character ready, return zero otherwise. 

sio1St	in	SIO1CTL		;read 2SIO #1 status/control register
	ani	SIORDRF		;data present?
	rz			;no, return zero
	mvi	a,0FFh		;else, return FF
	ret

; sio2St - Console status routine for 2SIO port 2. Return 0ff 
;    if character ready, return zero otherwise. 

sio2St	in	SIO2CTL		;read 2SIO #2 status/control register
	ani	SIORDRF		;data present?
	rz			;no, return zero
	mvi	a,0FFh		;else, return FF
	ret

; sioSt - Console status routine for SIO at I/O address 0. Return FFh 
;    if character ready, return zero otherwise. 

sioSt	in	SIOCTL		;read SIO status/control register
	xri	0FFh		;convert to positive logic
	ani	SIORCV		;data present?
	rz			;no, return zero
	mvi	a,0FFh		;else, return FF
	ret

; acrSt - Console status routine for ACR status (could get called through BAT)

acrSt	in	ACRCTL		;read ACR (SIO) control register
	xri	0FFh		;convert to positive logic
	ani	SIORCV		;data present?
	rz			;no, return zero
	mvi	a,0FFh		;else, return FF
	ret

;---------------------------------------------------------------------------
; Character input routines
;---------------------------------------------------------------------------

; sio1In - input character from 1st port on a 2SIO board and return in A.
;    C contains AND mask.

sio1In	call	sio1St		;wait for character
	jz	sio1In		;no, loop until data available

	in	SIO1DAT		;read the character
	ana	c		;possibly clear msbit
	ret

; sio2In - input character from 2nd port on a 2SIO board and return in A
;    C contains AND mask.

sio2In	call	sio2St		;wait for character
	jz	sio2In		;no, loop until data available
	
	in	SIO2DAT		;read the character
	ana	c		;possibly clear msbit
	ret

; sioIn - input character from SIO board at address 0/1
;    C contains AND mask.

sioIn	call	sioSt		;wait for character
	jz	sioIn		;no, loop until data available
	
	in	SIODAT		;read the character
	ana	c		;possibly clear msbit
	ret

; acrIn - input character from ACR SIO board at address 6/7

acrIn	call	acrSt		;wait for character
	jz	acrIn		;no, loop until data available
	
	in	ACRDAT		;read the character
	ret

;----------------------------------------------------------------------------
; Output status routines
;----------------------------------------------------------------------------

; sio1OSt - Return FFh if 2SIO Port #1 is ready, 0 if not ready

sio1OSt	in	SIO1CTL		;read 2SIO #1 status/control register
	ani	SIOTDRE		;0=busy
	rz			;not ready, return 0
	mvi	a,0FFh		;else, return FF
	ret

; sio2OSt - Return FFh if 2SIO Port #1 is ready, 0 if not ready

sio2OSt	in	SIO2CTL		;read 2SIO #2 status/control register
	ani	SIOTDRE		;0=busy
	rz			;not ready, return 0
	mvi	a,0FFh		;else, return FF
	ret

; lpcOst - Return FFh if 88-LPC is ready, 0 if not ready

lpcOSt	in	LPCCTL		;88-LPC board at port 2,3
	ani	LPCBSY		;0=busy
	rz			;not ready, return 0
	mvi	a,0FFh		;else, return FF
	ret

; sioOSt - Return FFh if SIO at 0/1 is ready, 0 if not ready
 
sioOSt	in	SIOCTL		;read SIO status/control register
	xri	0FFh		;convert to positive logic
	ani	SIOXMT		;0=busy
	rz			;not ready, return 0
	mvi	a,0FFh		;else, return FF
	ret
	
;---------------------------------------------------------------------------
; Character output routines with byte to send in C
;---------------------------------------------------------------------------

; sio1Out - Transmit byte through 2SIO port 1

sio1Out	call	sio1OSt		;wait for OK to xmit
	jz	sio1Out

	mov	a,c		;get character to xmit
	out	SIO1DAT		;send it
	ret

; sio2Out - Transmit byte through 2SIO port 2

sio2Out	call	sio2OSt		;wait for OK to xmit
	jz	sio2Out

	mov	a,c		;get character to xmit
	out	SIO2DAT		;send it
	ret

; sioOut - Transmit byte through SIO at address 0/1

sioOut	call	sioOSt		;wait for OK to xmit
	jz	sioOut

	mov	a,c		;get character to xmit
	out	SIODAT		;send it
	ret

; acrOut - Transmit byte through ACR SIO at address 6/7

acrOut	in	ACRCTL		;read ACR (SIO) control register
	ani	SIOXMT		;transmit data register empty?
	jnz	acrOut		;not yet, keep waiting

	mov	a,c		;get character to xmit
	out	ACRDAT		;send it
	ret

; lpcOut - Transmit byte through 88-LPC board.

lpcOut	call	lpcOSt		;wait for printer		
	jz	lpcOut

	mov	a,c
	ani	07Fh		;force bit 7 to zero
	out	LPCDAT		;output the character
	ret

;------------------------------------------------------------------------------
; dispMsg - display null terminated string. This
;    code assume conOut does not clobber HL in order to save two bytes.
; On Entry: HL->message
; On Exit:
; Clobbers C,H,L
;------------------------------------------------------------------------------
dispMsg	pop	h		;HL->message

dmLoop	mov	a,m		;null terminator?
	inx	h		;bump to next location
	ora	a
	jz	dmExit		;null, string is done

	mov	c,a		;C=character to display
	call	conOut		;display it
	jmp	dmLoop		;do next character

dmExit	pchl			;return past message string

;-----------------------------------------------------------------------------
; dpHead - disk parameter headers for each drive
;-----------------------------------------------------------------------------
dpHead	dw	tranTbl,0,0,0,dirBuf,dpb,csv0,alv0
	dw	tranTbl,0,0,0,dirBuf,dpb,csv1,alv1
	dw	tranTbl,0,0,0,dirBuf,dpb,csv2,alv2
	dw	tranTbl,0,0,0,dirBuf,dpb,csv3,alv3

;-----------------------------------------------------------------------------
; dpb - disk parameter block. This table gives a block size of 1024 bytes
;   and 64 directory entries. 
;-----------------------------------------------------------------------------
DSM	equ	242		;max block number (243 blocks of 1024 bytes)
DRM	equ	63		;max directory entry number (64 entries) 
CKS	equ	(DRM+1)/4	;directory check space

dpb	dw	NUMSEC		;sectors per track
	db	3		;allocation block shift factor (BSH)
	db	7		;data location block mask (BLM)
	db	0		;extent mask (EXM)
	dw	DSM		;maximum block number (DSM 242)	
	dw	DRM		;maximum directory entry number (DRM 63)
	db	0C0h,0		;AL0, AL1 
	dw	CKS		;CKS=(DRM+1)/4
	dw	2		;reserved tracks for CPM and bootloader

; tranTbl - convert zero-indexed logical sector to 1-indexed physical
;   sector number. Standard 8" SSSD interleave of 6.

tranTbl	db	01,07,13,19,25,05,11,17,23,03,09,15,21
	db	02,08,14,20,26,06,12,18,24,04,10,16,22

;-----------------------------------------------------------------------------
;  Disk scratchpad areas defined in the DPH table.
;-----------------------------------------------------------------------------
dirBuf	ds	128		;BDOS directory scratchpad
alv0	ds	(DSM/8 + 1)	;allocation vector storage
csv0	ds	CKS		;change disk scratchpad
alv1	ds	(DSM/8 + 1)
csv1	ds	CKS
alv2	ds	(DSM/8 + 1)
csv2	ds	CKS
alv3	ds	(DSM/8 + 1)
csv3	ds	CKS

ACTLEN	equ	$-BIOSBAS	;actual length of BIOS 

	end
