// PrintDiskTrident.bcpl - handle queued I/O for Trident disk

// errors 2500

get "PDInternals.d"
get "altofilesys.d"
get "disks.d"
get "tfs.d"

//outgoing procedures
external
	[
	PrintInitTrident
	PrintReadTrident
	PrintCheckTrident
	PrintStopTrident
	SetDA	//also used by PrintSlot
	]

//incoming procedures
external
	[
	Zero
	FileVDA
	PDError
	]

//incoming statics
external
	[
	BitsFile
	tridentVec
	tridentUsed	

	dcbOffset
	nDCBPerBuffer
	dataOffset
	lenDCB
	nextReadPage
	nBufsToRead
	nextReadBuf
	nBufsToCheck
	nextCheckBuf
	]

let PrintInitTrident(buf) be
[
	if lenDCB ls lKCB then PDError(2500)
	let disk=BitsFile>>F.Device
	let drive=NTridentDrives-(disk-2)/NPartitions
	let labelBuff= table [ 0;0;0;0;0;0;0;0;0;0 ]
	let dcb=buf+dcbOffset
	let dataAddr=buf+dataOffset
	for i=1 to nDCBPerBuffer do
		[
		Zero(dcb, lKCB)
		dcb>>KCB.drive=drive
		dcb>>KCB.nextKCB = dcb + lKCB
		dcb>>KCB.CommH = diskCheck
		dcb>>KCB.CountH = 2
		dcb>>KCB.AddrH = lv dcb>>KCB.diskAddress
		dcb>>KCB.CommL = diskRead
		dcb>>KCB.AddrL = labelBuff
		dcb>>KCB.CountL = 10
		dcb>>KCB.CommD = diskRead
		dcb>>KCB.CountD = TFSwordsPerPage
		dcb>>KCB.AddrD = dataAddr
		//dcb>>KCB.StatusD assigned in PrintReadTrident
		dataAddr=dataAddr+TFSwordsPerPage
		dcb = dcb>>KCB.nextKCB
		]
	(dcb-lKCB)>>KCB.nextKCB=0	//end of the line
]
 
//PrintReadTrident pushes new dcbs onto KBLK for buffer read

and PrintReadTrident() = valof
[
	if nBufsToRead eq 0 then resultis 0
	if nextReadBuf!-2 ne 0 then resultis nBufsToRead

	let vDA=FileVDA(BitsFile, nextReadPage)
	let dcb=nextReadBuf+dcbOffset
	let xdcb=dcb
	for i=1 to nDCBPerBuffer do
		[
		SetDA(xdcb, vDA); vDA=vDA+1
		xdcb>>KCB.StatusD=0
		xdcb>>KCB.ID=dcbID
		xdcb>>KCB.nextKCB=xdcb+lKCB
		xdcb=xdcb+lKCB
		]
	(xdcb-lKCB)>>KCB.nextKCB=0 //end of the line
	nextReadPage=nextReadPage+nDCBPerBuffer

//QueueDiskCommand
	let np=@KBLK
	test np eq 0 then @KBLK=dcb or
	[
	until np>>KCB.nextKCB eq 0 do np=np>>KCB.nextKCB
	np>>KCB.nextKCB=dcb
	if @KBLK eq 0 then @KBLK=dcb	//race condition
	]

	nextReadBuf!-2=1
	nextReadBuf=nextReadBuf!-1
	nBufsToRead=nBufsToRead-1
	resultis nBufsToRead
]

//PrintCheckTrident checks that a buffer read has completed

and PrintCheckTrident() = valof
[
	if nBufsToCheck eq 0 then resultis 0
	if nextCheckBuf!-2 ne 1 then resultis nBufsToCheck

	let dcb=nextCheckBuf+dcbOffset
	for i=1 to nDCBPerBuffer do
		[
		if dcb>>KCB.StatusD eq 0 then resultis nBufsToCheck
		dcb=dcb+lKCB
		]

	nextCheckBuf!-2=0		//checked
	nextCheckBuf=nextCheckBuf!-1
	nBufsToCheck=nBufsToCheck-1
	resultis nBufsToCheck
]

and PrintStopTrident() be
[
	let np=@KBLK
	until np eq 0 do
		[ let n=np>>KCB.nextKCB;np>>KCB.nextKCB=0;np=n]
	until @KBLK eq 0 do [ ]
]

and SetDA(p, DA) be
	[
	SetDA= table [		//SetDA(p, DA)
		#55001;		//0: sta 3 1,2
		#155000;	//1: mov 2 3
		#41402;		//2: sta 0 2,3
		#30424;		//3: lda 2 sectors
		#102400;	//4: sub 0 0
		#61021;		//5: div				
		#77400;		//6
		#41403;		//7: sta 0 3,3		sector = DA rem sectors
		#30420;		//8: lda 2 heads
		#102400;	//9: sub 0 0
		#61021;		//10: div
		#77400;		//11
		#30415		//12: lda 2,firstVTrack
		#147000	//13: add 2 1		track=firstVtrack+(DA/sectors)/heads
		#31402;		//14: lda 2 2,3	dcb
		#45000;		//15: sta 1 0,2	store track
		#101300;	//16: movs 0 0	head = (DA/sectors) rem heads
		#25403;		//17: lda 1 3,3
		#123000;	//18: add 1 0		head,,sector
		#41001;		//19: sta 0 1,2
		#171000;	//20: mov 3 2
		#35001;		//21: lda 3 1,2
		#1401;		//22: jmp 1,3
		9;		//23: Sectors
		5		//24: Heads
		0		//25: firstVTrack
		]
	let disk=BitsFile>>F.Device-2
	let firstVTrack=(tridentVec!disk)>>TFSDSK.firstVTrack
	SetDA!24=tridentUsed	//nHeads
	SetDA!25=firstVTrack	//for T-300, additional file systems
	SetDA(p, DA)
]