contlr_mstr.v 10.9 KB
//**************************************************************************************
//
//	Model Name	: contlr_mstr.v
//	Revision	: $Revision: 1.6 $
//	Date		: $Date: 2003/01/13 18:38:14 $
//	Author		: Bill Saperstein
//	Description	: controller master simulation model
//
//**************************************************************************************


//**************************************************************************************
// Module Definition
//**************************************************************************************
module contlr_mstr
		(
	// Outputs
		jchan			// joy channel serial data line 
		) ;

//**************************************************************************************
// Define Parameters (optional)
//**************************************************************************************

// joy channel timing specifications
parameter	TRANSFER_SEP = 1000 ;
parameter	SMALL_PULSE = 8 ;
parameter	LARGE_PULSE = 30 ;
parameter	PULSE_DIFF_MIN = 16 ;
parameter	TRANSFER_TERM = 10 ;
parameter	TRANSFER_TERM_MAX = 250 ;
parameter	TRANSFER_CONT = 10 ;
parameter	RESET_PULSE = 1500 ;
parameter	TRANSFER_CYCLE = 60 ;
parameter	MAX_SMALL_PULSE = 304 ;
parameter	MIN_LARGE_PULSE = 23 ;
parameter	MAX_LARGE_PULSE = 634 ;
parameter	divisor = 1 ; 

// joy channel command encodings
parameter	CMD0 =			8'h00 ;
parameter	CMD1 =			8'h01 ;
parameter	CMD255 =		8'hff ;

// state machine state definitions
parameter	idle =			3'b000 ;
parameter	tran_strt = 		3'b001 ;
parameter	shft_cmd =		3'b010 ;
parameter	trans_term =		3'b011 ;
parameter	rcv_data =		3'b100 ;
parameter	reset =			3'b101 ;
parameter	bus_wait_cont =		3'b110 ;
parameter	bus_wait_term =		3'b111 ;

// clock and reset parameters
parameter	PERIOD =		50 ;
parameter	DIV =			4'h1 ;
parameter	RST_DLY =		0 ;
parameter	RST_PULSE =		1 ;


//**************************************************************************************
// Port Declarations
//**************************************************************************************

inout	jchan ;

//**************************************************************************************
// Net Assignments and Declarations
//**************************************************************************************

	reg[7:0]	cmd_reg ;
	reg[7:0]	ctl_reg ;
	reg[7:0]	data_reg[3:0] ;
	reg[7:0]	byte_reg ;
	reg[2:0] 	st_reg ;
	wire[1:0]	data_cnt ;
	reg		data_en ;
	reg		jchan_mstr_mon ;
	wire		data_in ;

	reg[3:0]	divider ;
	reg[3:0]	count ;
	reg		clock ;
	reg		sysclk ;
	reg		enable ;
	reg		rst_l ;
	wire		max_cnt ;

initial
begin
	cmd_reg = 8'h00 ;
	ctl_reg = 8'h00 ;
	byte_reg = 8'hxx;
	data_en = 1'b0 ; 
	jchan_mstr_mon = 1'b0 ;

	divider = DIV ;
	count = 4'h0 ;
	clock = 1'b0 ;
	sysclk = 1'b0 ;
	enable = 1'b0 ;
	rst_l = 1'b0 ;

end

//**************************************************************************************
// Pre-Defined Module Instantiations
//**************************************************************************************


//**************************************************************************************
// Gate and Structural Declarations
//**************************************************************************************

     assign

// ***  command register decoder is function byte_cnt
//	the command determines the number of data bytes

	data_cnt = byte_cnt(cmd_reg) ,

// *** define the i/o interface
//	the i/o is a bi-directional with output as an open collector (with the 
//	output enable controlled by the state machine

	data_in = jchan ,
	jchan = data_en ? 1'b0 : 1'bz ; 

//**************************************************************************************
// Procedural Assignments
//**************************************************************************************

// *** initialize and test for monitor
	initial
	begin
	   $display("%M: joy channel master controller model") ;
	   jchan_mstr_mon = $test$plusargs("jchan_mstr_mon") ;
	end

// *** Define the master state machine

	always @(st_reg or ctl_reg[0] or ctl_reg[1] or negedge rst_l)
	   begin
	// handle asynchronous reset
	   	if (!rst_l)
		   st_reg <= idle ;
		else
		   begin :	master_sm
			case (st_reg)
			   (idle) :	
			      begin : 		idle_state
				if(ctl_reg[1])
				   st_reg <= reset ;
				else if(ctl_reg[0])
				begin
				   ctl_reg[0] <= 1'b0 ;
				   st_reg <= tran_strt ;
				end
				
				else
				   st_reg <= idle ;
			      end

			   (tran_strt) :	
			      begin :		transfer_start
				wait(data_in) ;
				repeat (TRANSFER_SEP/divisor)
				   @(posedge sysclk) ;
				st_reg <= shft_cmd ;
			      end

			   (shft_cmd) :	
			      begin :		shift_command
				integer i ;
				if(jchan_mstr_mon)
				$display("%t: %M: shift out command 0x%h",$time,cmd_reg) ;
				for(i=7 ; i>=0 ; i=i-1)
				   begin
				      if (cmd_reg[i])
					pm1 ;
				      else
					pm0 ;
				   end
				st_reg <= trans_term ;
			      end

			   (trans_term) :	
			      begin :		transfer_termination
				data_en <= 1'b1 ;
				repeat (TRANSFER_TERM/(divisor))
				   @(posedge sysclk) ;
				data_en <= 1'b0 ;
				st_reg <= bus_wait_cont ;
			      end

			   (bus_wait_cont) :	
				begin :		transfer_continuous
				   integer tc_cnt ;
				   tc_cnt = 0 ;
				   wait(data_in) ;
				   while(data_in & (st_reg == bus_wait_cont))
				    begin
				      @(posedge sysclk)
					tc_cnt = tc_cnt + 1 ;
				      if (tc_cnt >= TRANSFER_SEP/(divisor))
				      begin
				        if(jchan_mstr_mon)
					$display("%t: %M: slave signalling disconnection \n",$time) ;
					st_reg <= idle ;
				      end
				    end
				   if(!data_in)
				     begin
				   	if (tc_cnt < TRANSFER_CONT/(divisor))
				     	begin
				      	 $display("%t: %M: ERROR: transfer continous duration violation \n",$time) ;
				      	 st_reg <= rcv_data ;
				     	end
				   	else
				      	 st_reg <= rcv_data ;
				    end
				end

			   (rcv_data) :		
			      begin :		receive_sl_data
				integer j ;
				integer low_cnt, hi_cnt ;
				reg[2:0] data_index ;
				if(jchan_mstr_mon)
				   $display("%t: %M: beginning to receive %d bytes of data from slave",$time,(data_cnt+1)) ;
				for (data_index=0 ; data_index<=data_cnt ; data_index=data_index+1)
				   begin
				      for (j=7 ; j>=0 ; j=j-1)
					begin
					   low_cnt = 0 ;
					   hi_cnt = 0 ;
					   while(!data_in)
					      @(posedge sysclk)
						low_cnt = low_cnt + 1 ;
					   while(data_in & (hi_cnt <= MAX_LARGE_PULSE/(divisor)))
					      @(posedge sysclk)
						hi_cnt = hi_cnt + 1 ;
					   if (hi_cnt > MAX_LARGE_PULSE/(divisor))
						$display("%t: %M: ERROR: high pulse width greater than max or no termination,width=%d",$time,hi_cnt) ;
					   if (low_cnt < hi_cnt)
					      begin
						byte_reg[j] = 1'b1 ;
						if ((hi_cnt - low_cnt) < PULSE_DIFF_MIN/(divisor))
						   $display("%t: %M: ERROR : min pulse difference violation",$time) ;
						if(hi_cnt < MIN_LARGE_PULSE/(divisor))
						   $display("%t: %M: ERROR: min large pulse width violation for 1'b1 ,width=%d",$time,hi_cnt) ;
						if(low_cnt > MAX_SMALL_PULSE/(divisor))
						   $display("%t: %M: ERROR : max small pulse width violation for 1'b1, width=%d",$time,low_cnt) ;
					      end
					  else
					      begin
						byte_reg[j] = 1'b0 ;
						if (low_cnt > MAX_LARGE_PULSE/(divisor))
						  $display("%t: %M: ERROR: max large pulse width violation for 1'b0,width=%d",$time,low_cnt) ;
						if ((low_cnt - hi_cnt) < PULSE_DIFF_MIN/(divisor))
						   $display("t: %M: ERROR : min pulse difference violation", $time) ;
						if(low_cnt < MIN_LARGE_PULSE/(divisor))
						   $display("%t: %M: ERROR: min large pulse width violation for 1'b0 ,width=%d",$time,low_cnt) ;
						if (hi_cnt > MAX_SMALL_PULSE/(divisor))
						   $display("%t: %M: ERROR : max small pulse width violation for 1'b0, width=%d",$time,hi_cnt) ;
					      end
					end
				      data_reg[data_index] =  byte_reg ;
				      if(jchan_mstr_mon)
				      $display("%t: %M: value in data_reg[%d]=0x%h",$time,data_index,data_reg[data_index]) ;
				   end
			       st_reg <= bus_wait_term ;
			      end

			   (bus_wait_term) :		
			      begin :			bus_wait_termination
				integer te_cnt ;
				te_cnt = 0 ;
				while(!data_in & (te_cnt <= TRANSFER_TERM_MAX/divisor))
				   @(posedge sysclk)
				      te_cnt = te_cnt + 1 ;
				if (te_cnt > TRANSFER_TERM_MAX/(divisor))
				   $display("%t: %M: ERROR: transfer termination too long or stuck low \n",$time) ;
				if (te_cnt < TRANSFER_TERM/(divisor))
				   $display("%t: %M: ERROR: transfer termination duration violation \n",$time) ;
				if(jchan_mstr_mon)
				   $display("%t: %M: slave response completed",$time) ;
				st_reg <= idle ;
			      end
				
			   (reset) :		
			      begin :		reset_state
				if(jchan_mstr_mon)
				   $display("%t: %M: asserting joychannel reset",$time) ;
				ctl_reg[1] <= 1'b0 ;
				data_en <= 1'b1 ;
				repeat(RESET_PULSE/(divisor))
				   @(posedge sysclk) ;
				data_en <= 1'b0 ;
				st_reg <= idle ;
			      end

			   default :
				st_reg <= idle ;		   

			endcase
		   end
		end

// *** Define clock and reset 
	 always
                #(PERIOD / 2) clock = ~clock ;
 
        assign  max_cnt = (count == divider) ;
        always @(posedge clock)
           begin
                count <= max_cnt ? 4'h0 : (count +1) ;
                sysclk <= max_cnt ;
           end   

//	controller reset
	initial
	 begin
		#(RST_DLY) ;
                rst_l = 1'b0 ;
		if(jchan_mstr_mon)
                $display ("%t: %M: force rst_l to zero for reset",$time) ;
	end

	always @(enable)
	   begin
	      if (enable)
		begin
                   repeat(RST_PULSE)
                      @(posedge sysclk) ;
                   rst_l = 1'b1 ;
		   if(jchan_mstr_mon)
                      $display ("%t: %M: jchan_mstr coming out of reset",$time) ;
		end
	      else
		begin
		   rst_l = 1'b0 ;
		   if (jchan_mstr_mon)
		      $display("%t: %M: jchan_mstr going into reset/idle",$time) ;
		end
           end               


//**************************************************************************************
// Task and Function Definitions
//**************************************************************************************

//	define the byte_cnt decoder
	function[1:0] byte_cnt ;
	   input[7:0] cmd_reg ;
	   begin
		case (cmd_reg)
		CMD0	: byte_cnt = 2'b10 ;
		CMD1	: byte_cnt = 2'b11 ;
		CMD255  : byte_cnt = 2'b10 ;
		default : byte_cnt = 2'b10 ;
		endcase
	   end
	endfunction

//	define the pulse modulation task for generating a zero bit
	task pm0 ;
	   begin
		data_en = 1'b1 ;
		repeat (LARGE_PULSE/(divisor))
		   @(posedge sysclk) ;
		data_en = 1'b0 ;
		repeat (SMALL_PULSE/(divisor))
		   @(posedge sysclk) ;
	   end
	endtask

//	define the pulse modulation task for generating a one bit
	task pm1 ;
	   begin
		data_en = 1'b1 ;
		repeat (SMALL_PULSE/(divisor))
		   @(posedge sysclk) ;
		data_en = 1'b0 ;
		repeat (LARGE_PULSE/(divisor))
		   @(posedge sysclk) ;
	   end
	endtask

//**************************************************************************************
// End of Model
//**************************************************************************************
endmodule // contrl_mstr