// DiskProms.bcpl
// last modified January 18, 1982  11:22 AM by Taft

external DiskProms
get "DoradoProms.defs"

external [ Min ]

static addr

manifest
	[
	Pin1 = #200; Pin2 = #100; Pin3 = #40; Pin4 = #20
	Pin5 = #10; Pin6 = 4; Pin7 = 2; Pin9 = 1
	]

let DiskProms(mem) be
	[
	let buff = vec 300
	if StEq(mem,"DskEth") then mem!0 = DoAll
	if StEq(mem,"DiskWrite") & ICtype eq MC10139 then  // define the write Prom
		[
		MakeCont(buff,false)
		Header("DiskWrite",8,buff,32,8)
		PromCommand("Disk-a20")
		]
	if StEq(mem,"DiskRead") & ICtype eq MC10139 then  // define the read Prom
		[
		MakeCont(buff,true)
		Header("DiskRead",8,buff,32,8)
		PromCommand("Disk-a21")
		]
	if StEq(mem,"DiskTag") & ICtype eq MC10149 then  // define the Tag Timing Prom
		[
		MakeTagTiming(buff)
		Header("DiskTag",4,buff,32,12)
		PromCommand("Disk-d21")
		]
	if StEq(mem,"DiskFifo") & ICtype eq MC10149 then  // define the Fifo Pointers Prom
		[
		MakeFifoPointers(buff)
		Header("DiskFifo",4,buff,256,12)
		PromCommand("Disk-b14")
		]

if StEq(mem,"DiskUnits") & ICtype eq N74288 then  //now define the Drive Select Prom
		[
		MakeDriveSelect(buff)
		Header("DiskUnits",8,buff,32,8)
		PromCommand("Disk-d05")
		]

]


and MakeCont(buff,ReadFlag) be
	[
//first define a bunch of constants
	manifest
		[
		LoadSR = Pin1; ReadSR = Pin1
		CompECC = Pin2//configure ECC generator for genoration
		NewBlock = Pin3//shift command reginster AT START OF THIS INSTRUCTIOM
		Tag = Pin4//Load value addressed by RAM into Tag register
					//otherwose load value addressed by RAM into the count register
		]

	manifest 
		[  //These define the LOCATION of parameters within the RAM register
		Count0 = 0			//Number of words in block 0.
		Count1 = 1			//Number of words in block 1.
		Count2 = 2			//Number of words in block 2.
		Count3 = 3			//Number of words in block 3.
		ReadComm=4+Tag	//Tag Command to cause a Read operation.
		WriteComm =5+Tag	//Tag Command to cause a Write operation.
		InitComm =6+Tag	//Tag Command leading to a read or write.
		ResetComm =7+Tag	//Tag Command to zero all bits of TAG register.
		WrDlyFirst=8 		//Number of "0 words" to Write before the data of 1st block.
		WrDlyNext=9 		//Number of "0 words" to Write before the data of other blocks.
		RdDlyFirst=10		//Number of words to wait before reading the 1st block.
		RdDlyNext=11		//Number of words to wait before other reads.
		Delay3=12				//used for ECC count plus 1
		Delay2 = 13			//used for ECC count and Head select delay.
		Delay1=14				//Minimum count time.
		]


//~~~~~~~~~~~~
//now "Program" the READ/WRITE proms


	test ReadFlag
		ifso  //define all the commands necessary to read all blocks of the disk
			[  //NOTE: the controller may sitch from Read to Write after executing "NewBlock"

		//Initialization
			buff!00 = InitComm  							// enable the heads
			buff!01 = Delay2  								// wait for disk to settle

		//Commands for Reading the first Block
			buff!02 = RdDlyFirst							//wait for heads over zeros 
			buff!03 = ReadComm 							//waits for the "sync" pattern 
			buff!04 = Count0 + CompECC + ReadSR   	//read in the "block" words 
			buff!05 = Delay2 + CompECC + ReadSR		//read the ECC words 
			buff!06 = InitComm + ReadSR  				//read one word of ECC,turn off read 
			buff!07 = Delay1 + ReadSR  					//read last word of ECC 
			buff!08 = Delay1 + NewBlock					//get the next block 

		//Commands for Reading the second Block
			buff!09 = RdDlyNext 							//wait for heads over zeros 
			buff!10 = ReadComm 							//waits for the "sync" pattern 
			buff!11 = Count1 + CompECC + ReadSR   	//read in the "block" words 
			buff!12 = Delay2 + CompECC + ReadSR		//read the ECC words 
			buff!13 = InitComm + ReadSR   				//read one word of ECC,turn off read 
			buff!14 = Delay1 + ReadSR  					//read last word of ECC 
			buff!15 = Delay1 + NewBlock					//get the next block 

		//Commands for Reading the third Block
			buff!16 = RdDlyNext 							//wait for heads over zeros 
			buff!17 = ReadComm 							//waits for the "sync" pattern 
			buff!18 = Count2 + CompECC + ReadSR   	//read in the "block" words 
			buff!19 = Delay2 + CompECC + ReadSR		//read the ECC words 
			buff!20 = InitComm + ReadSR  				//read one word of ECC,turn off read 
			buff!21 = Delay1 + ReadSR  					//read last word of ECC 
			buff!22 = Delay1 + NewBlock					//get the next block 

		//Commands for Reading the fourth Block
			buff!23 = RdDlyNext 							//wait for heads over zeros 
			buff!24 = ReadComm 							//waits for the "sync" pattern 
			buff!25 = Count3 + CompECC + ReadSR   	//read in the "block" words 
			buff!26 = Delay2 + CompECC + ReadSR		//read the ECC words 
			buff!27 = InitComm + ReadSR  				//read one word of ECC,turn off read 
			buff!28 = Delay1 + ReadSR  					//read last word of ECC 
			buff!29 = Delay1 + NewBlock					//get the next block 

		//Reset the Tag register and clear out commands
			buff!30 = ResetComm+NewBlock
			buff!31 = ResetComm+NewBlock
			]

		ifnot  //define all the commands necessary to write all blocks of the disk
			[  //NOTE: the controller may sitch from Read to Write after executing "NewBlock"

		//Initialization
			buff!00 = InitComm  							// enable the heads
			buff!01 = Delay2 								// wait for disk to settle

		//Commands for Writing the first Block
			buff!02 = WriteComm							//send a tag with write bit on 
			buff!03 = WrDlyFirst							//now wait for disk to settle 
			buff!04 = Delay1 + CompECC+ LoadSR		//send the "sync" word 
			buff!05 = Count0 + CompECC+ LoadSR		//send the "block" words 
			buff!06 = Delay1 + CompECC					//compute ECC on last word 
			buff!07 = Delay3  								//shift out ECC plus word of zero's 
			buff!08 = Delay1 + NewBlock					//get the next block 

		//Commands for Writing the second Block
			buff!09 = WriteComm 							//send a tag with write bit on 
			buff!10 = WrDlyNext							//now wait for disk to settle 
			buff!11 = Delay1 + CompECC+ LoadSR 		//send the "sync" word 
			buff!12 = Count1 + CompECC+ LoadSR		//send the "block" words 
			buff!13 = Delay1 + CompECC					//compute ECC on last word 
			buff!14 = Delay3 								//shift out ECC plus word of zero's 
			buff!15 = Delay1 + NewBlock					//get the next block 

		//Commands for Writing the third Block
			buff!16 = WriteComm							//send a tag with write bit on 
			buff!17 = WrDlyNext							//now wait for disk to settle 
			buff!18 = Delay1 + CompECC+ LoadSR		//send the "sync" word 
			buff!19 = Count2 + CompECC+ LoadSR		//send the "block" words 
			buff!20 = Delay1 + CompECC					//compute ECC on last word 
			buff!21 = Delay3  								//shift out ECC plus word of zero's 
			buff!22 = Delay1 + NewBlock					//get the next block 

		//Commands for Writing the fourth Block
			buff!23 = WriteComm							//send a tag with write bit on 
			buff!24 = WrDlyNext							//now wait for disk to settle 
			buff!25 = Delay1 + CompECC+ LoadSR		//send the "sync" word 
			buff!26 = Count3 + CompECC+ LoadSR		//send the "block" words 
			buff!27 = Delay1 + CompECC					//compute ECC on last word 
			buff!28 = Delay3 								//shift out ECC plus word of zero's 
			buff!29 = Delay1 + NewBlock					//get the next block 

		//Reset the Tag register and clear out commands
			buff!30 = ResetComm+NewBlock
			buff!31 = ResetComm+NewBlock
			]
			
	]


and MakeTagTiming(buff) be
	[
	manifest [ TagStrobe = 4; TagDone = 2; CntOff = 1 ]
	Zero(buff,256) 
	for adr = 0 to 31 do
		[
		let Active = adr&#20
		let Cnt = adr&#17
		let output = 0

		if (Cnt ge 3) & (Cnt le 13) then buff!adr = TagStrobe
		if (Cnt eq 12) & (Active ne 0) then buff!adr = buff!adr % CntOff
		if Cnt eq 15 then buff!adr = TagDone
		]
	]


and MakeFifoPointers(buff) be
	[
	manifest [ Full = #10; WriteEn = 4; ReadEn = 2; Empty = 1 ]
	Zero(buff,256)
	let InvertBits = WriteEn % ReadEn
	for adr = 0 to 255 do
		[
		let Waddr = adr rshift 4
		let Raddr = adr & #17
		let Delta = (Waddr-Raddr)&#17
		if Delta eq 0 then buff!adr = Empty
		if Delta eq 15 then buff!adr =Full	// 14B. change to accommodate lost fix
		if Delta ge 2 then buff!adr = buff!adr % ReadEn
		if Delta ls 12 then buff!adr = buff!adr % WriteEn
		buff!adr = buff!adr xor InvertBits
		]

	]



and MakeDriveSelect(buff) be
	[
	structure Input:
		[
		blank bit 11
		select bit 1	// 1 => select addressed drive
		driveNum bit 4	// drive number
		]
	structure Output:
		[
		blank bit 8
		select0 bit 1	// select drive 0 (unary encoded)
		select1 bit 1	// select drive 1
		select2 bit 1	// select drive 2
		select3 bit 1	// select drive 3
		driveNum bit 2	// addressed drive (binary encoded)
		blank bit 2
		]
	for adr = 0 to 31 do
		[
		let output = 0
		// drive numbers greater than 3 address drive 3
		output<<Output.driveNum = Min(adr<<Input.driveNum, 3)
		if adr<<Input.select then
			switchon adr<<Input.driveNum into
				[
				case 0: output<<Output.select0 = 1; endcase
				case 1: output<<Output.select1 = 1; endcase
				case 2: output<<Output.select2 = 1; endcase
				default: output<<Output.select3 = 1; endcase
				]
		buff!adr = output
		]
	]