
***************************************************************
*		CP/M-68K LDRBIOS
*	Basic Input/Output Subsystem for system loader
*	For VMEs10 Emulator with CPM Disk Controller 
***************************************************************
* >as68 -L -T booter.s (occupies $800) 2K
* >as68 -L -T ldrbios.s (occupies $2000) 8k
* >LO68 -s -tb00 -uldr -o cpmldr.sys booter.o ldrlib ldrbios.o 
*     $b00 + $800 = $1300 (which is load address of CPMLDR.sys)
* >putboot cpmldr.sys a:
* >as68 -L -T bios.s 
* >lo68 -r -o cpm.rel -ucpm -um68010 cpmlib bios.o (for mc68010)
* >lo68 -r -o cpm.rel -ucpm cpmlib bios.o (for mc68000)

	.globl	_bios		* declare external entry point
	.globl	_bootdsk	* boot disk passed from Ten Bug

memrS	equ	$400		* starts at memrS
memrL	equ	$2fc00	* goes until memrS + memrL-1
* NOTE - memtab never gets initialized in original Loader
*   defined as 400-2ffff (400 + 2fc00 = 30000)-1
	.text

_bios:
	cmpi		#nfuncs,d0
	bcc		nogood
	lsl		#2,d0		* multiply bios function by 4
	lea		biosbase,a0
	add.w		d0,a0		* get handler address
	move.l	(a0),a0
	jsr		(a0)		* call handler
nogood:
	rts

biosbase:
	dc.l  nogood
	dc.l  nogood
	dc.l  conStat
	dc.l  conIn
	dc.l  conOut
	dc.l  nogood
	dc.l  nogood
	dc.l  nogood
	dc.l  home
	dc.l  seldsk
	dc.l  settrk
	dc.l  setsec
	dc.l  setdma
	dc.l  read
	dc.l  nogood
	dc.l  nogood
	dc.l  sectran
	dc.l  setdma
	dc.l  getseg
	dc.l  nogood
	dc.l  nogood
	dc.l  nogood
	dc.l  setexc

tvalue	equ		*-biosbase
nfuncs	equ		tvalue/4


ConDR 		equ		$f1c1c9
ConSR			equ		$f1c1cd
ConRxRDY		equ		$1
ConTxRDY		equ		$4

conStat:
	move.b	ConSR,d0		* get status byte
	andi.b	#ConRxRDY,d0	* data available bit on?
	beq		noton			* branch if not
	move.w	#$00FF,d0		* set result to true
	rts

noton:
	clr.w		d0			* set result to false
	rts

conIn:
	bsr		conStat		* see if key pressed
	tst.w		d0
	beq		conIn			* wait until key pressed
	move.b	ConDR,d0		* get key
	and.w		#$7f,d0		* clear all but low 7 bits
	rts

conOut:
	move.b	ConSR,d0		* get status
	and.b		#ConTxRDY,d0	* check for transmitter buffer empty
	beq		conOut		* wait until data can go...
	move.b	d1,ConDR 		* and output it
	rts					* and exit


*
* Disk Handlers for CPM disk controller
*

cdcCMDr	equ	1		* read command
cdcCMDw	equ	2		* write command

cdcIOB	equ 	$00f1a200	* CPM disk port base address
cdcCMD	equ	cdcIOB		* output port for command
cdcSTS	equ 	cdcIOB		* input status port
cdcDRV	equ	cdcIOB+2	* drive select port
cdcCYL	equ 	cdcIOB+4	* disk cylinder port
cdcHD	 	equ	cdcIOB+6	* disk head port
cdcSCT	equ 	cdcIOB+8	* disk sector port
cdcDMA	equ	cdcIOB+$a	* disk dma port
cdcTRK	equ	cdcIOB+$e	* CPM track port

cdcCYLS equ	cdcIOB+$14
cdcHDS  equ	cdcIOB+$16
cdcSPT equ	cdcIOB+$18
cdcSSZ equ	cdcIOB+$1a

*   CmdSts-H     CmdSts-L     +00
*   Drive-H      Drive-L      +02
*   Cylinder-H   Cylinder-L   +04
*   Head-H       Head-L       +06
*   Sector-H     Sector-L     +08
*   DMA-hh       DMA-hl       +0a
*   DMA-lh       DMA-ll       +0c
*   Track-h	     Track-l      +0e
* Must access as words (except DMA can be long)

* 15 14 13 12 11 10 9  8  7   6   5   4   3   2   1   0
*                        R/W  WP DMA  C   H   S  DRV CMD

home:
	clr.w		track
	rts

seldsk:	
*	select disk given by _bootdsk
	move.w	_bootdsk,d1
	move.w	d1,d0
	and.w		#$f,d0	* make sure 0-15
	lsl.w		#2,d0		* mult by 4 to make longword pointer
	lea		dphtbl,a0	* address of 16 pointers to DPHs
	move.l	0(a0,d0.w),d0
	tst.l		d0		* check for invalid drive
	beq.b		selrtn	* drive is invalid
	btst.l	#0,d2		* check for disk already logged in
	bne.b		loggedin
	bsr.b		dologin
loggedin:
	move.b	d1,seldrv	* save drive number
selrtn:
	rts

dologin:
* spectbl format $hds16 spt16,  ssz16  cyls16 , DPB32 ,XLT32
* d4 = hds16 spt16 
* d5 = ssz16 cyls16

	move.w	cdcSTS,d4	* clear errors
	move.b	d1,d4		* get drive number 0-f
	and.w		#$f,d4	* make sure 0-15
	move.w	d4,cdcDRV	* Select Disk to get specs
	move.w	#2,cdcTRK	* Select data track
	move.w	cdcSTS,d4	* see if good drive
	beq.b		OK
	clr.l		d0		*set bad select
	rts
OK:
	move.w	cdcHDS,d4
	swap		d4
	move.w	cdcSPT,d4
	move.w	cdcSSZ,d5
	swap		d5
	move.w	cdcCYLS,d5
* search SpecTble for Match of D4 and D5 to SpecTlb +0 and +4
	move.w	#MaxSTE,d6
	bra.b		NEXT
AGAIN:
	lea		SpecTbl,a1
	move.w	d6,d7
	lsl.w		#4,d7		* mult by 16
	cmp.l		0(a1,d7.w),d4
	bne.b		NEXT
	cmp.l		4(a1,d7.w),d5
	bne.b		NEXT

	move.l	d0,a0			* move pointer to dph in d0 to a0
	move.l	8(a1,d7.w),14(a0) * to DPB in DPH
	move.l	12(a1,d7.w),0(a0) * to XLT in DPH
	rts
NEXT:
	dbf		d6,AGAIN
	clr.l		d0 	* make select invalid
	rts

* end of doLogin


settrk:
	move.w	d1,track
	rts

setsec:
	move.w	d1,sector
	rts

sectran:
*	translate sector in d1 with translate table pointed to by d2
*	result in d0
	tst.l		d2
	beq.b		zerobased
	cmpi.l	#1,d2
	bne.b		trans
onebased:
	move.w	d1,d0
	addq.w	#1,d0
	rts
zerobased:
	move.w	d1,d0
	rts
trans:
	movea.l	d2,a0
*	ext.l	d1
	move.b	0(a0,d1.w),d0
	ext.w		d0
*	ext.l		d0
	rts

setdma:
	move.l	d1,dma
	rts

read:
* Read one sector from requested disk, track, sector to dma address
*  return in d0 00 if ok, else non-zero
	
	move.w	cdcSTS,d7	*read to clear previous errors
	move.l 	dma,cdcDMA
	move.b	seldrv,d7
	ext.w		d7
	move.w	d7,cdcDRV
	move.w	track,cdcTRK
	move.w	sector,cdcSCT
	move.w	#cdcCMDr,cdcCMD

	
rdone:
	move.w	cdcSTS,d7
	andi.w	#$ff,d7		* set condition codes
	bne		rerror
	clr.w		d0
	rts
rerror:
	move.w	#1,d0
	rts

getseg:
	move.l	#memrgn,d0	* return address of mem region table
	rts


setexc:
	andi.l	#$ff,d1	* do only for exceptions 0 - 255
	cmpi.w	#47,d1
	beq		noset		* this BIOS doesn't set Trap 15
	cmpi.w	#9,d1		* or Trace
	beq		noset
	lsl.l		#2,d1		* multiply exception nmbr by 4
	movec.l	vbr,a0	* this is a 68010
	adda.l	d1,a0
	move.l	(a0),d0	* return old vector value
	move.l	d2,(a0)	* insert new vector
noset:
	rts

	.data

* disk specs
*	size	hds	cyls	spt	ssz
*	.25	1	77	26	128	dpb3740	XLT=xlt3740
*	5	2	306	32	256	dpb5mb
*	10	4	306	32	256	dpb10mb
*	15	6	306	32	256	dpb15mb
*	40	6	830	32	256
*	70	8	1024	32	256
*	48tpi	2	40	8	512	dpb48tpi	data tracks
*     CPM86	2	40	8	512	dpb48tpi	data tracks
*	96tpi	2	80	8	512	dpb96tpi	data tracks
*    pc1440 2	80	9	512	dpbPC1440
*  CPMSIM16	1	512	256	128	dpbCS16

* spectbl format $hds16 spt16,  ssz16  cyls16 , DPB32 ,XLT32
* d4 = hds16 spt16 
* d5 = ssz16 cyls16
	even
SpecTbl:
	dc.l	$00020020,$01000132,dpb5mb,0		* 5mb
	dc.l	$00040020,$01000132,dpb10mb,0		*10mb
	dc.l	$00060020,$01000132,dpb15mb,0		*15mb
*	dc.l	$00060020,$0100033e,dpb40mb,0		*40mb
*	dc.l	$00080020,$01000400,dpb70mb,0		*70mb
	dc.l	$00020008,$02000028,dpb48TPI,1	*48tpi
*	dc.l	$00020008,$02000028,dpbCPM86,1	*48tpi
	dc.l	$00020008,$02000050,dpb96TPI,1	*96tpi
	dc.l	$0001001a,$0080004d,dpb3470,xlt3470	*.25
	dc.l	$00020012,$02000050,dpbPC1440,1	*PC1440
	dc.l	$00010100,$00800200,dpbCS16,0		*CPMSIM16MB
*MaxSTE equ (*-SpecTbl)\$10	* BUG divide wont work
MaxSTE equ 8


	even

seldrv:	dc.b	$ff	* drive requested by seldsk

track:	dc.w	0	* track requested by settrk

sector:	dc.w	0

dma:		dc.l	0

memrgn:	dc.w	1		* 1 memory region
		dc.l	memrS		* starts at memrS
		dc.l	memrL		* goes until memrS + memrL-1

_bootdsk	dc.w	2		* passed here form BOOTER, which got it from TENBUG

* DPH table
dphtbl:
	dc.l	dph0
	dc.l	dph1
	dc.l	dph2
	dc.l	dph3
	dc.l	0,0,0,0
	dc.l	0,0,0,0
	dc.l	0,0,0,0
* disk parameter headers

dph0:	dc.l	xlt3470	* standard IBM 34 translation skew=6
	dc.w	0		* dummy
	dc.w	0
	dc.w	0
	dc.l	dirbuf	* ptr to directory buffer
	dc.l	dpb3470	* ptr to disk parameter block
	dc.l	0	* ptr to check vector
	dc.l	0	* ptr to allocation vector

dph1:	dc.l	0	*zero based
	dc.w	0	* dummy
	dc.w	0
	dc.w	0
	dc.l	dirbuf	* ptr to directory buffer
	dc.l	dpb5mb	* ptr to disk parameter block
	dc.l	0	* ptr to check vector
	dc.l	0	* ptr to allocation vector

dph2:	dc.l	1	* one based
	dc.w	0	* dummy
	dc.w	0
	dc.w	0
	dc.l	dirbuf	* ptr to directory buffer
	dc.l	dpb96TPI * ptr to disk parameter block
	dc.l	0	* ptr to check vector
	dc.l	0	* ptr to allocation vector

dph3:	dc.l	1	* one based
	dc.w	0	* dummy
	dc.w	0
	dc.w	0
	dc.l	dirbuf	* ptr to directory buffer
	dc.l	dpb96TPI * ptr to disk parameter block
	dc.l	0	* ptr to check vector
	dc.l	0	* ptr to allocation vector

* disk parameter block

dpb3470:
	dc.w	26	* sectors per track
	dc.b	3	* block shift
	dc.b	7	* block mask
	dc.b	0	* extent mask
	dc.b	0	* dummy fill
	dc.w	242	* disk size
	dc.w	63	* 64 directory entries
	dc.w	$c000	* directory mask
	dc.w	16	* directory check size
	dc.w	2	* track offset
dpb96TPI:
	dc.w	32	* sectors per track
	dc.b	4	* block shift
	dc.b	15	* block mask
	dc.b	0	* extent mask
	dc.b	0	* dummy fill
	dc.w	313	* disk size
	dc.w	127	* 128 directory entries
	dc.w	$c000	* directory mask
	dc.w	32	* directory check size
	dc.w	2	* track offset
dpb48TPI:
	dc.w	32	* sectors per track
	dc.b	4	* block shift
	dc.b	15	* block mask
	dc.b	1	* extent mask
	dc.b	0	* dummy fill
	dc.w	153	* disk size
	dc.w	127	* 128 directory entries
	dc.w	$c000	* directory mask
	dc.w	32	* directory check size
	dc.w	2	* track offset
*dpbCPM86:
*	dc.w	32	* sectors per track
*	dc.b	4	* block shift
*	dc.b	15	* block mask
*	dc.b	1	* extent mask
*	dc.b	0	* dummy fill
*	dc.w	157	* disk size
*	dc.w	63	* 128 directory entries
*	dc.w	$8000	* directory mask
*	dc.w	16	* directory check size
*	dc.w	1	* track offset
dpb5mb:
	dc.w	64	* sectors per track
	dc.b	5	* block shift
	dc.b	31	* block mask
	dc.b	1	* extent mask
	dc.b	0	* dummy fill
	dc.w	1215	* disk size
	dc.w	1023	* 1k directory entries
	dc.w	$ff00	* directory mask
	dc.w	$100	* directory check size
	dc.w	2	* track offset
dpb10mb:
	dc.w	64	* sectors per track
	dc.b	5	* block shift
	dc.b	31	* block mask
	dc.b	1	* extent mask
	dc.b	0	* dummy fill
	dc.w	2435	* disk size
	dc.w	2047	* 2k directory entries
	dc.w	$ffff	* directory mask
	dc.w	$200	* directory check size
	dc.w	2	* track offset
dpb15mb:
	dc.w	64	* sectors per track
	dc.b	5	* block shift
	dc.b	31	* block mask
	dc.b	1	* extent mask
	dc.b	0	* dummy fill
	dc.w	3655	* disk size
	dc.w	2047	* 2k directory entries
	dc.w	$ffff	* directory mask
	dc.w	$200	* directory check size
	dc.w	2	* track offset
dpbPC1440:
	dc.w	72	* sectors per track
	dc.b	4	* block shift
	dc.b	15	* block mask
	dc.b	0	* extent mask
	dc.b	0	* dummy fill
	dc.w	710	* disk size
	dc.w	255	* 256 directory entries
	dc.w	$f000	* directory mask
	dc.w	64	* directory check size
	dc.w	2	* track offset
dpbCS16:
	dc.w	256	* sectors per track
	dc.b	4	* block shift
	dc.b	15	* block mask
	dc.b	0	* extent mask
	dc.b	0	* dummy fill
	dc.w	8176	* disk size
	dc.w	4095	* 2k directory entries
	dc.w	0	* directory mask
	dc.w	$400	* directory check size
	dc.w	1	* track offset

* sector translate table

xlt3470:
	dc.b	 1, 7,13,19
	dc.b	25, 5,11,17
	dc.b	23, 3, 9,15
	dc.b	21, 2, 8,14
	dc.b	20,26, 6,12
	dc.b	18,24, 4,10
	dc.b	16,22


*	.bss

dirbuf:	ds.b	128	* directory buffer


	.end	
