Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
15 years ago

Unsafe Latch behavior and inferred latches

Hey Everyone,

I am a little confused on how Quartus decides if something is an actual latch or an inferred latch. For example in the following code, latch_counter and control_word_register are treated as inferred latches, but counter seems to be treated as a register.

module prog_counter (reset, ceb, write, data_in, clk, load, data_out,trigger);
input trigger;
input reset;
input ceb, write, load;
input  data_in;
input clk;
output data_out;
//declare the control word
reg  control_word_register;
reg disable_CWR; //Used to disable the CWR
//declare the counter with 8 bits
reg  counter;
reg  latch_counter;
//flag for first clk pulse after loading in value of counter
reg flag_counter;
//flag for half count cycle
reg flag_half_counter;
//to write control word into counter
//for control_word, bit 2 reprsents enable,
//bits 1 and 0 represent counter mode
//this also latches in the counter value.
always @(ceb or write or reset or load or data_in or disable_CWR)
begin
	//Load control word
	//Pin Config: ceb:low, write:high, load:low, reset:low
	if (~ceb & write & ~load & ~reset) 
		control_word_register = data_in ;
	//Load Counter Value
	//Pin Config: ceb:low, write:low, load:high: reset:low
	else if (~ceb & ~write & load & ~reset)
		latch_counter = data_in;
	//Timer Enable - Prepare timer for loading control word and latch
	//Pin Config: ceb:high, reset:low
	else if (ceb & ~reset)
		begin
			//reset the control word counter
			control_word_register = 3'd0;
			//reset the latch
			latch_counter = 8'd0;
		end
	else if (disable_CWR)
			control_word_register = 1'd0;
end
	
	//to counter for counter
	
always @(posedge clk or posedge reset)
	begin
		if(reset)
		begin
			disable_CWR <= 0;
			flag_counter <= 0;
			counter <= 0;
			flag_half_counter<=0;
		end
		else
		begin
			if(control_word_register) //counter is enabled
			begin
				if(control_word_register == 2'b00)	//this if for one shot mode
				begin
					if(~flag_counter)
						begin
						counter <= latch_counter;
						flag_counter <=1;
						end
					else
						begin
						if(counter == 8'hff)
							begin
							//to stop counter for one shot mode
							disable_CWR <= 1;
							flag_counter <=0;
							end
						else
							counter <= counter + 1;
						end
				end
				else if (control_word_register == 2'b01) //waveform generator mode
				begin
					if(~flag_counter)
						begin
							counter <= latch_counter;
							flag_counter <= 1;
						end
					else
						begin
							if(counter == 8'hff)
								flag_counter <= 0;
							counter <= counter + 1;
						end
				end
				else if(control_word_register == 2'b10) //this if for the 50% duty cycle waveform generator
				begin
					if(~flag_counter)
					begin
						counter <= latch_counter;
						flag_counter <= 1;
					end
					else
					 begin
						  if (counter == {1'b0,latch_counter})
							 begin
								  flag_half_counter <= ~flag_half_counter;
								  counter <= counter - 1;
							 end
						  else
							 if (counter == 0)
								flag_counter <= 0;
							 else
								counter <= counter - 1;
					 end
				end
			else if(control_word_register == 2'b11)//this is for triggered pulse generator mode
			  begin
			    if(~flag_counter)
			      begin
					//If we aren't currently sending out a pulse, then keep the counter loaded and ready
					//this also resets the counter after a successful pulse is generated so that we will be ready for the next trigger
					counter <= latch_counter; 
			        if(trigger)
			           flag_counter <= 1;
			        else
			           flag_counter <= 0;
			      end
			    else
			      if(counter == 8'hff)
			        begin //stop counter for triggered pulse mode
			         flag_counter <= 0;
			        end
			       else
			         counter <= counter + 1;
			   end
			  
		end
	end
end
	
assign data_out = (
	((counter == 8'hff) & (control_word_register == 2'b00) & flag_counter) |
	((counter == 8'hff) & (control_word_register  == 2'b01)) |
	(flag_half_counter & (control_word_register  == 2'b10))|
	((counter != 8'hff) & (control_word_register == 2'b11) & flag_counter)
	);
	
endmodule 

I get warnings about the former two being inferred, and then get warnings like:

Warning: Latch prog_counter:inst|control_word_register has unsafe behavior
	Warning: Ports D and ENA on the latch are fed by the same signal rst
Warning: Latch prog_counter:inst|control_word_register has unsafe behavior
	Warning: Ports D and ENA on the latch are fed by the same signal rst
Warning: Latch prog_counter:inst|latch_counter has unsafe behavior
	Warning: Ports D and ENA on the latch are fed by the same signal rst
Warning: Latch prog_counter:inst|latch_counter has unsafe behavior
	Warning: Ports D and ENA on the latch are fed by the same signal rst
Warning: Latch prog_counter:inst|latch_counter has unsafe behavior
	Warning: Ports D and ENA on the latch are fed by the same signal rst
Warning: Latch prog_counter:inst|latch_counter has unsafe behavior
	Warning: Ports D and ENA on the latch are fed by the same signal rst
Warning: Latch prog_counter:inst|latch_counter has unsafe behavior
	Warning: Ports D and ENA on the latch are fed by the same signal rst
Warning: Latch prog_counter:inst|latch_counter has unsafe behavior
	Warning: Ports D and ENA on the latch are fed by the same signal rst
Warning: Latch prog_counter:inst|latch_counter has unsafe behavior
	Warning: Ports D and ENA on the latch are fed by the same signal rst
Warning: Latch prog_counter:inst|control_word_register has unsafe behavior
	Warning: Ports D and ENA on the latch are fed by the same signal rst
Warning: Latch prog_counter:inst|latch_counter has unsafe behavior
	Warning: Ports D and ENA on the latch are fed by the same signal rst

the thing is I want to treat latch_counter and control_word_register as storage anyway, so why are they being inferred? is there way a way to force quartus to treat them as registers?

If I run a simulation of the circuit, after the latch_counter is loaded correctly and the load pin is pulled low, the latch resets to 0, but I haven't a clue why.

Any input is greatly appreciated. Thanks

8 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Look at what is in your process sensitivity list. If you write a function that responds to reset and posedge clk then it will most likely be a register. If it responds to other stuff and has incomplete in/then statements it may fold it into a latch.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    Look at what is in your process sensitivity list.

    --- Quote End ---

    In synthesized code, it's almost meaningless what's in the sensitívity list of a combinational process, although the compiler issues warnings about missing signals to keep compatibilty with simulation results.

    It's the pure logic equations that actually matter. control_word_register and latch_counter are assigned in a combinational (or "level sensitive") process, so latches are created. The behaviour is unsafe, because logical combinations of the same signals are generating different latch states. Unavoidable glitches in the generated logic make the latch state possibly unpredictable.

    flag_counter and counter are in contrast assigned in a synchronous (edge-sensitive) process and thus synthesized as clockes DFFs.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Thank you both for the replies, I can see now why the latches are created.

    FvM:

    --- Quote Start ---

    It's the pure logic equations that actually matter. control_word_register and latch_counter are assigned in a combinational (or "level sensitive") process, so latches are created. The behaviour is unsafe, because logical combinations of the same signals are generating different latch states. Unavoidable glitches in the generated logic make the latch state possibly unpredictable.

    --- Quote End ---

    is there a way fix the unsafe behavior in the above code?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    is there a way fix the unsafe behavior in the above code?

    --- Quote End ---

    You should find an alternative way to achieve the intended behaviour. Actually I don't undertstand the meaning of the present code, e.g. three different cases of reset. Finding a synchronous solution would be preferable, of course.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    As always, I should probably just wait for FvM to answer questions. You are correct, but I do find that sensitivity lists do shed light into what the original coder was trying to accomplish. If they have just edges of reset and clocks in the list is shows they intended to write a ff, if they have other stuff in there it shows they are trying to write combinational logic. Although now I am just writing stuff to cover up my incorrect first post...

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I didn't suggest to ignore sensitivity lists, I'm mostly filling them up as required by the VHDL standard. I just wanted to prevent jumping into conclusion about the present problem.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hello.

    I forgot to assign all the cases in a case control in a always @(*), so latches are inferred.

    OK, I understand that, no problem.

    But, with the inferred latches present I get both LE count and fmax 10% better than with the inferred latches eliminated.

    Is the TimeQuest timing analyzer to believe in this case?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Yes and no. Timequest is only able to analyse registers, not latches. So latches could present all sorts of problems.