"$Id: pld1.src,v 1.14 2001/02/23 17:07:57 warren Exp $
"==============================================================================================
#TITLE    'HELIX DRIVER PLD1: VME INTERFACE, DECODE, TRIGGER COUNTER & FEEDBACK';
#ENGINEER 'Gil Nixon / John Lane / Dominic A Hayes / Matt Warren';
#COMPANY  'University College London';
#COMMENT  'Mach5 256/120-15YC';
"==============================================================================================
"
"                                 D32:A24 VME SLAVE interface.
"
"                    ***   USES EXTERNAL VME DATA LATCHES (74ALS543)  ***
"==============================================================================================
"$Log: pld1.src,v $
"Revision 1.14  2001/02/23 17:07:57  warren
"Added delay unbit readback code
"
"Revision 1.13  2001/02/23 15:44:23  warren
"Removed soft_test
"
"Revision 1.12  2001/02/20 19:46:31  warren
"Files for the new command line fit and prog system
"
"Revision 1.11  2001/02/19 17:47:36  warren
"Added version control
"



"MODS
"----
"
"28Nov00 Added addr_valid checking - MRMW
"29Nov00 Remove vme lword checking - we don't seem to need it ......(?) - MRMW
"        Added testreg - 8bit rw for vme rw testing on pld1 - MRMW
"30Nov00 Changed latch control lines to be like TIM -  MRMW
"        removed testreg - it wouldn't fit, but replaced it with:
"        cmdstatreg - psuedo reg - used to read the values of [output_busy, hsd_mode] - MRMW
" 4Dec00	new input 'trigger' replaces function of 'trig' - pin no longer needed - MRMW
"			This makes use of 2 spare bus lines ...
"			Added wr = reset to Trig_Count_Reg (14h)
"        DLEN found to stay high - added clocking and reset to this 'reg' - MP/MRMW
"           This may explain why the bus was driven in SER=0 mode.
" 2Jan01	Removed cmdstatreg - not needed any more.
" 4Jan01 Added 'wr_all_delay_units' concurrently as addr:7Ch
"			zero'd unused db lines for small reg reads
"        Changed addr_valid to include command r/wr's - proved not to fix the wr/r delay descrepancy.
"23Feb01 Added delay unit read_back code.
"			Mod'd VME timing to use dl3 - easier for serial read back timing.
"24feb01 Added code to reset the delay units to 0 at reset




"==============================================================================================





"==============================================================================================
"                                  PLD MAIN CODE AND DECLARATIONS
"==============================================================================================

"----------------------------------------------------------------------------------------------
" CLOCKS etc
"----------------------------------------------------------------------------------------------





	"FROM PLD2
	"---------
		INPUT	 trig_sd,
				 output_busy;  " high when serial shifting out

	"FROM BOARD/FP
	"-------------
		INPUT	 pld_ck,
				 trigger;






"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
" VME interface
"----------------------------------------------------------------------------------------------

"  - determines that the board is being addressed by way of
"    1. address (a[23..20] compared 4bit dip input.
"    2. address modifier.  two a24 data access modes used (ssda, snda).
"    3. lword, iack.
"    and generates a bdsel signal.
"  - handles timing of data transfers (using an external delay line)
"    and outputs a (high_true) (dt)ack signal (but not open collector!)
"  - handles output enables for VME databus two-way buffer.
"  - this version does not register the VME address lines as previous designs have)
"----------------------------------------------------------------------------------------------

         INPUT  base_addr[23..16];	"selected base address from DIP switch (8 bit address)
         INPUT  ab[23..1];				"buffered VME address lines
         									" 23..16 for board select, 6..1 for cmd/data addr.

LOW_TRUE INPUT  lwordb;					"Buffered VME signal.

LOW_TRUE INPUT  writeb;					"ACTIVE LOW.  Buffered VME Data Write.

LOW_TRUE INPUT  berrb;					"Buffered VME Bus ERRor.
LOW_TRUE INPUT  ds0b, ds1b;			"Buffered VME Data Strobes.


LOW_TRUE INPUT  iackb;					"Buffered VME Interupt ACKnowledge.
			INPUT  amb[5..0];				"Buffered VME Address Modifier.

			NODE	 bdsel;

			OUTPUT ack;						"Data Transfer ACK (to external Open Collecter gate).
			OUTPUT errorled;				"Bus ERRor when board addressed.

			OUTPUT dl0;						"OR'd ds0/1b, Data Strobe, sent to delay line.

			INPUT	 dl1;						"used to clock am_OK and addr_OK.
			INPUT	 dl2;						"used by oeout and ack (/dl2 used by db_le and db_clk).
			INPUT	 dl3;
			INPUT	 dl4;	" *** added

			OUTPUT oein, oeout;	"ACTIVE LOW.  Output Enables for vme data bus '543 latches.
			OUTPUT wr,   rd;		"ACTIVE LOW

			OUTPUT db_le;			"ACTIVE LOW.  latches the vme data (on the '543) onto the board. [le1]

			OUTPUT db_clk;			"             VME databus register clock.


			BIPUT	 db[7..0]            "bi-directional i/o pins.
						ENABLED_BY	dboe
						DEFAULT_TO  0;
					
			NODE  dboe;                "db output enable.

			NODE	addr_valid;				"zero if an invalid address is decoded



		   NODE	  ds;                       " - "OR'ed" ds0/1b.
	   	NODE   ssda, snda                "Address modifier codes.
	             DEFAULT_TO 0;
	             
		   NODE   am_OK                     "Correct Address Modifier for bread.
      		       CLOCKED_BY dl1
            		 RESET_BY /ds;          "Falling edge of ds (cycle finished).
		   NODE   addr_OK                   "VME address = base address.
      		       CLOCKED_BY dl1
            		 RESET_BY /ds
		             DEFAULT_TO 0;



   ds = ds0b OR ds1b;             " - OR'ed  Data Strobes
   dl0  = ds;
							" **** this is 16bit mode  still ...
   "IF (/iackb AND /lwordb) THEN        "ADDRESS MODIFIER DECODE *** check the D32 stuff
   " lword removed to provide both 16 and 32 bit data access

   IF (/iackb) THEN        "ADDRESS MODIFIER DECODE *** check the D32 stuff
      CASE amb                         "=======================
         WHEN 3Dh => ssda = 1;         "Standard supervisory data access.
         WHEN 39h => snda = 1;         "Standard non-privileged data access.
      END CASE;
   END IF;

   am_OK.D = ssda OR snda;                      "Either of the A24 data access codes.

   IF (ab[23..16] = base_addr[23..16]) THEN     "VME address matches board address.
      addr_OK.D = 1;
   END IF;

   bdsel = am_OK AND addr_OK;                   "BoarD SELected when both asserted.


" VME CONTROL SIGNALS
"=====================

	NODE	readb;			"Not actually needed, will disappear when optimised.
	readb	=  /writeb;		"for easier code readability only


	db_le	= /(            bdsel AND /dl3);		"ACTIVE LOW. latch vme data (on the '543) in [le1]
	db_clk=  ( writeb AND bdsel AND  dl3);		"clock db data into register (pld). [le2].

	wr		= /( writeb							);		"ACTIVE LOW direction(CE) for latches		B->A
	rd		= /( readb							);		"ACTIVE LOW direction(CE) for latches		A->B


	ack	=  (				 bdsel AND dl3 );		"=> DTACK*, end of VME access cycle.
															" *** changed to dl3 ..... was dl2

	errorled = (berrb AND addr_OK);				"signal to LED when bus error AND board is addressed.


	oein	= /( writeb AND bdsel			);	"ACTIVE LOW. OE for VME master WRITEs		B->A.
	oeout	= /( readb	AND bdsel AND dl3 AND addr_valid);		"ACTIVE LOW. OE for VME master READs		A->B.
												" *** changed to dl3






"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
" REG/CMD LINES & ADDRESS DECODER
"----------------------------------------------------------------------------------------------

"
"  IF the board is addressed this procedure:
"  - decodes 4 VME address lines to determine the current command.
"  - decoded "v_output_data" signal is sync'd to the board clock.
"  - it does NOT register the VME address lines.
"  - all decoded commands are clocked by bdsel to eliminate spikes.


			OUTPUT	access_data,			"VME access to the sequence Data Register
						access_status,			"VME access to the Status Register
						access_tp_mask,		"VME access to the Test Pulse Mask Register
						access_sl_sent,		"VME access to the SD_sent Register
						read_trig_count,		"VME read of the Trigger Counter Register
						read_feedback0,		"VME read of the Register Data
						read_feedback1,		"VME read of the Register Data
						read_feedback2,		"VME read of the Register Data
						reset_cmd,
						soft_trig,
						output_data_set		"VME addr/cmd start outputing serial data to helix.
		         		CLOCKED_BY bdsel
							RESET_BY /ds
							DEFAULT_TO 0;

			NODE		hsd_mode_set,			"VME set serial download mode
		       		hsd_mode_reset,		"VME set normal trigger mode
		       		read_cmdstatreg
		       			CLOCKED_BY bdsel
							RESET_BY /ds
							DEFAULT_TO 0;



		"--------------------------------------------------------------
		"RESET
		"--------------------------------------------------------------

		INPUT	 onres;		" power-on reset signal
		

		OUTPUT reset;
					
		OUTPUT	hsd_mode					"helix driver Mode - 1=serial download/0=normal trig
							CLOCKED_BY	hsd_mode_set
							RESET_BY		(hsd_mode_reset OR reset);
		hsd_mode.D = 1;

		reset = (reset_cmd OR onres);
			



      "--------------------------------------------------------------
      "DELAY UNITS
      "--------------------------------------------------------------

			OUTPUT	dlread,		" read clock for serial delay unit read
					 	ser;			" mode select for delayunits 1=par/0=serial
					 
			NODE		du_access;

         ser = (du_access AND writeb) OR reset;   " 1 = parallel prog, 0 = serial read-back
         dlread = (du_access AND readb) AND dl2;

			OUTPUT dlen[14..0]
        		CLOCKED_BY	bdsel
				PRESET_BY	reset		"*** was	RESET_BY /ds
            DEFAULT_TO 0;

			
		
	"--------------------------
	"actual decoder
	"--------------------------
	
	NODE	writeb_x15[14..0]; 	" *** not really needed, but makes WHEN 7C code look better.
	
	writeb_x15 = [	writeb, writeb, writeb, writeb, writeb,
						writeb, writeb, writeb, writeb, writeb,
						writeb, writeb, writeb, writeb, writeb	];
						
	

	NODE	vme_address[6..0]; " not needed, but helps ledgibilty

	vme_address[6..0] = [ab[6..2],0,0];

	CASE	(vme_address)

	"Registers										 -- id -- attr -----
		WHEN 00h  => access_data.D   	 = 1;	addr_valid = 1;		" 0 - 24bit	rw reg
		WHEN 04h  => read_feedback0.D	 = 1;	addr_valid = 1;		" 1 -  8bit ro reg
		WHEN 08h  => read_feedback1.D	 = 1;	addr_valid = 1;		" 2 -  8bit ro reg
		WHEN 0Ch  => read_feedback2.D	 = 1;	addr_valid = 1;		" 3 -  8bit ro reg
		WHEN 10h  => access_status.D	 = 1;	addr_valid = 1;		" 4 -  3bit ro reg, wr=reset
		WHEN 14h  => read_trig_count.D = 1;	addr_valid = 1;		" 5 -  8bit ro reg
		WHEN 18h  => access_tp_mask.D	 = 1;	addr_valid = 1;		" 6 - 15bit rw reg
		WHEN 1Ch  => access_sl_sent.D  = 1;	addr_valid = 1;		" 7 - 15bit ro reg, wr=reset

	"Commands
		WHEN 20h  => hsd_mode_set.D	 = 1;	addr_valid = 1;		" 8 - r/wr = command
		WHEN 24h  => output_data_set.D = 1;	addr_valid = 1;		" 9 - r/wr = command
		WHEN 28h  => soft_trig.D       = 1;	addr_valid = 1;		"10 - r/wr = command
		WHEN 2Ch  => hsd_mode_reset.D  = 1;	addr_valid = 1;		"11 - r/wr = command
		"WHEN 30h  => ;														"12 - unused
		"WHEN 34h  => ;														"13 - unused
		"WHEN 38h  => ;														"14 - unused
		WHEN 3Ch  => reset_cmd.D       = 1; addr_valid = 1;		"15 - r/wr = command
		
	"Delays
		WHEN 40h  => dlen[ 0] = 1;	addr_valid = 1; du_access = 1;	"16 - wo
	   WHEN 44h  => dlen[ 1] = 1;	addr_valid = 1; du_access = 1;	"17 - wo
	   WHEN 48h  => dlen[ 2] = 1;	addr_valid = 1; du_access = 1;	"18 - wo
	   WHEN 4Ch  => dlen[ 3] = 1;	addr_valid = 1; du_access = 1;	"19 - wo
	   WHEN 50h  => dlen[ 4] = 1;	addr_valid = 1; du_access = 1;	"20 - wo
	   WHEN 54h  => dlen[ 5] = 1;	addr_valid = 1; du_access = 1;	"21 - wo
	   WHEN 58h  => dlen[ 6] = 1;	addr_valid = 1; du_access = 1;	"22 - wo
	   WHEN 5Ch  => dlen[ 7] = 1;	addr_valid = 1; du_access = 1;   "23 - wo
	   WHEN 60h  => dlen[ 8] = 1;	addr_valid = 1; du_access = 1;	"24 - wo
	   WHEN 64h  => dlen[ 9] = 1;	addr_valid = 1; du_access = 1;	"25 - wo
	   WHEN 68h  => dlen[10] = 1;	addr_valid = 1; du_access = 1;	"26 - wo
	   WHEN 6Ch  => dlen[11] = 1;	addr_valid = 1; du_access = 1;	"27 - wo
	   WHEN 70h  => dlen[12] = 1;	addr_valid = 1; du_access = 1;	"28 - wo
	   WHEN 74h  => dlen[13] = 1;	addr_valid = 1; du_access = 1;   "29 - wo
	   WHEN 78h  => dlen[14] = 1;	addr_valid = 1; du_access = 1;	"30 - wo
	   WHEN 7Ch  => dlen = (7FFFh AND writeb_x15); addr_valid = 1; "31 - wo - all del_unit wr
	   
	   ELSE	addr_valid = 0; 
	   		dlen[14..0] = 0;
	   		du_access = 0;

	END CASE;




"----------------------------------------------------------------------------------------------






"----------------------------------------------------------------------------------------------
" TRIGGER COUNTER
"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

"  - counts the number of trigger pulses issued.
"  - the counter contents are output (for read access).
"------------------------------------------------------------------------------------------------



	NODE	rst_trig_cntr;
	rst_trig_cntr = (writeb AND read_trig_count);
	

	NODE  register_trig_count[7..0]
            CLOCKED_BY trigger
            RESET_BY (rst_trig_cntr OR reset);

   register_trig_count.D = register_trig_count .+. 1;       "defines counter FF inputs.
   


"----------------------------------------------------------------------------------------------
" FEEDBACK
"----------------------------------------------------------------------------------------------



         OUTPUT read_feedback;

         read_feedback = (		read_feedback0		" *** this output is for debug now, but
         						OR read_feedback1 	" but if this reg moves to pld2, it
         						OR read_feedback2 ); " will become the single-step read on the
         													" 24 bit db connected to pld2
			NODE	rst_feedback_reg;

			rst_feedback_reg = (writeb AND read_feedback);



"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
" Feedback
"
"  - receives the trig_sd bitstream sent to helix and clocks it into a shift register.
"  - the shift register contents are output (for read access).
"----------------------------------------------------------------------------------------------


			NODE  feedback_in;    
					feedback_in = trig_sd;


	NODE   register_feedback[19..0]
				CLOCKED_BY	/pld_ck			"NB /pld_ck
				CLOCK_ENABLED_BY output_busy
				RESET_BY	(rst_feedback_reg OR reset)
				DEFAULT_TO 0 ;

	"NODE   en_feedback
	"			CLOCKED_BY output_busy
	"			RESET_BY (/output_busy OR reset);

	"en_feedback.D = 1;						"FF clocked when feedback begins.

	"IF (en_feedback = 1 ) THEN
		register_feedback[19..0].D
			= [ register_feedback[18..0] , feedback_in ];	"defines feedback shift register FF inputs.
	"ELSE
	"	register_feedback.D = register_feedback;				"stationary data in feedback reg.
	"END IF;


"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++



"----------------------------------------------------------------------------------------------
" SPARES
"----------------------------------------------------------------------------------------------

         "INPUT spare[23..0];
         INPUT spare[21..0]; " *** used 2 spare lines for trig stuff-trigger(in),soft_trig(out)



"----------------------------------------------------------------------------------------------
" VME READ
"----------------------------------------------------------------------------------------------
	   

	   IF (readb) THEN  
	      IF	(read_trig_count) THEN							"VME reads trigger counter register.
	         db[7..0] = register_trig_count[7..0];
	      ELSIF (read_feedback0) THEN						"VME READs feedback register lsb.
	      	db[7..0] = register_feedback[7..0];
	      ELSIF (read_feedback1) THEN						"VME READs feedback register middle.
	      	db[7..0] = register_feedback[15..8];
	      ELSIF (read_feedback2) THEN						"VME READs feedback register msb.
	      	db[3..0] = register_feedback[19..16];
	      	db[7..4] = 0;			" *** added for easier manual reg read tests
	     
	      END IF;
	   END IF;


	   dboe =	readb AND (	   read_trig_count 			"databus output enables. 
		                     OR read_feedback0
		                     OR read_feedback1
		                     OR read_feedback2
		                     OR reset);

"==============================================================================================  