Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Need some quick help with VHDL

Status
Not open for further replies.
I made it another go. It compiles, but complains about some signals not being in the sensitivity list. If I don't need the process to be re-evaluated, there is no real need to put every signal that is read inside the sensitivity list, right? I tried uploading it to my DE-2-nano, but it doesn't work. LED(1 DOWNTO 0) are supposed to show me which state it's in, but both leds seem to glow quite dimly so I guess it's switching states with the same frequency as CLOCK_50 (which I don't understand).
.

Yes you do. Synthesis ignores sensitivity lists, so missing some out will only lead to a difference in behaviour between your simulation and real hardware.

You are also using the 'last_value attribute. I have no idea how this got through synthesis, as 'last_valud has no meaning in hardware. You need to explicitly build a register to check the "last value". It appears to have assumed you intended that signal to be a clock, and it's somehow put some clocking logic in your unclocked process.

The difference between a clock and a 'event is that a clock should toggle from '0' to '1' back to '0' in a periodicy frequency. Hence it should create 'events with a fixed period. Using the sensitivity list may mean the process remains inactive for a long period of time. 'events are also created on ANY change in signal, and std_logic has 9 states in simulation ('U', 'X', '0', '1', 'Z'. 'W', 'L', 'H' and '-'). So changing from any of these to any other of these causes a 'event, which is not a clock edge.

'events were implemented for simulation purposes. It means a process can sit and do nothing for a period of time giving CPU resources to another process. Remember VHDL was first standardised in 1987 (and used from inception in the early 80s) when computer power was rather poor, and any free CPU cycles would be a blessing.
 

I made it another go. It compiles, but complains about some signals not being in the sensitivity list. If I don't need the process to be re-evaluated, there is no real need to put every signal that is read inside the sensitivity list, right?

A previously mentioned by others, sensitivity lists are ignored for hardware synthesis. In so far all warnings about missing signals in sensitivity list can be ignored as longs as you don't perform functional simulation of the code, e.g. with Modelsim. Nevertheless, if you understand why the compiler expects some signals to appear in the sensitivity list but others not, you'll considerably improve your insights in the VHDL design principles. And won't have problems to make the sensitivity lists simulator compatible.

I don't get what the deal about clocks are. I've now limited myself to only using CLOCK_50 as a clock, but then the compiler complains and says "Warning (332060): Node: newClock was determined to be a clock but was found without an associated clock assignment.".

For sake of timing analysis, the compiler wants you to declare the design clocks and specify their frequency. If you are using a previous Quartus version, you can do this very simply with the "Classical Timing Analyzer" otherwise you need to learn a bit about Timequest usage.

What is really the difference between using rising_edge and having a signal in the sensitivity list? When a rising or falling edge of a signal represents some kind of change, it's called a clock, right? If a signal is present in the sensitivity list it means that something will happen when that signal changes value (rising or falling edge) so I don't understand the difference.

Only signals used as an edge sensitive trigger, e.g. rising_edge() are clocks. Nothing happens in FPGA hardware because a signal only appears in a sensitivity list, e.g. KEY(1) in your previous example.

It's very important to understand the difference between a process modelling edge-sensitive logic (Flip- flops) and level-sensitive processes, modelling combinational logic and (possibly unwanted) latches.

This leads to the most serious problem of your designs that will finally make it fail. You have placed some operations inside the combinational process that can only work in a edge-sensitive process like counting bits. I have cut out some compilation warnings that are related to relevant problems.

The nextstate latch can be rather easily overcome by writing nextstate <= state at the top of the combinational process. The other latches are indicating a more essential design problem, the bitnumber latches which are recognized as unsafe are finally killing the design.

Warning (10631): VHDL Process Statement warning at uart.vhd(53): inferring latch(es) for signal or variable "nextstate", which holds its previous value in one or more paths through the process

Warning (10631): VHDL Process Statement warning at uart.vhd(53): inferring latch(es) for signal or variable "UARTREG", which holds its previous value in one or more paths through the process

Warning (10631): VHDL Process Statement warning at uart.vhd(53): inferring latch(es) for signal or variable "bitnumber", which holds its previous value in one or more paths through the process

Warning: Latch bitnumber[0] has unsafe behavior
Warning: Ports D and ENA on the latch are fed by the same signal state.stop

Some problems are brought up by using the traditional two process FSM template. You can make your life much easier by implementing most of the design in a single process under rising_edge(CLOCK_50) control.
 

So there is some difference between real hardware and "simulation" that I'm missing? When you speak of a simulation, do you mean something like simulink? Are attributes like "last_value" nonsensical when uploading this to my FPGA? I thought the whole point of doing this was to upload it to an FPGA or to make some ASIC, can't it be a nuisance if I'm given a code riddled with lines that only make sense in a simulation software and not in real hardware?

The difference between a clock and a 'event is that a clock should toggle from '0' to '1' back to '0' in a periodicy frequency. Hence it should create 'events with a fixed period. Using the sensitivity list may mean the process remains inactive for a long period of time. 'events are also created on ANY change in signal, and std_logic has 9 states in simulation ('U', 'X', '0', '1', 'Z'. 'W', 'L', 'H' and '-'). So changing from any of these to any other of these causes a 'event, which is not a clock edge.

What about from a hardware perspective? I know a clock should have a constant frequency and duty cycle, but how can the hardware tell? It's not like it calculates the frequency and makes up it's own mind of whether it's a clock or not. I read online that std_logic can have 9 states, but I don't really know what this mean? Again from the hardware's perspective, a signal can only be 0 or 1 so I fail to see the difference between having a signal in the sensitivity list and using rising-or falling_edge.

About my use of "last_value", I have to find some other solution then. What I would like is to use rising_edge so that it executes the commands inside the if-statement only ONCE, but I guess that would be going back to using several clocks.
 

To emphasize some previous points, I have a sample Rx-UART design, cut from an exsiting application. It implements a single edge sensitive process.

Code:
library ieee;
use ieee.std_logic_1164.all;
--use ieee.numeric_std.all;
   
entity RxUnit is
  generic (
      OVSFAC      : INTEGER := 16; -- Oversample
      BAUDFAC     : INTEGER := 4
  );
  port (
      Clk      : in  Std_Logic;
      Reset    : in  Std_Logic := '0';  -- Reset input
      RxD      : in  Std_Logic;  -- UART data input
      RxAv     : out Std_Logic;  -- Received Data valid
      RcvErr   : out Std_Logic;  -- Error
      Frame    : out Std_Logic;
      DataO    : out Std_Logic_Vector(7 downto 0)); -- Received data
end entity;

architecture RTL of RxUnit is
  signal RReg     : Std_Logic_Vector(7 downto 0); -- Byte receive register  
  signal SampleCnt: INTEGER range 0 to OVSFAC-1;      
  signal BitPos   : INTEGER range 0 to 11;     -- Position of the bit in the byteframe
  signal clkcount : INTEGER range 0 to BAUDFAC-1;
  signal RxD_S1   : Std_Logic;
  signal RxD_S2   : Std_Logic;
begin
   
   process(Clk,Reset)
   begin
      if Reset = '1' then -- Reset
         BitPos <= 0;
         clkcount <= 0;         
         RxAv <= '0';
         RcvErr <= '0';
         RxD_S1 <= '1';
         RxD_S2 <= '1';
      elsif Rising_Edge(Clk) then
         -- Synchronizer chain
         RxD_S1 <= RxD;
         RxD_S2 <= RxD_S1;
         if BitPos = 0 then
            RxAv <= '0';
            RcvErr <= '0';
            SampleCnt <= 0;
         end if;     
         if clkcount < BAUDFAC-1 then
            clkcount <= clkcount + 1;
         else  
            clkcount <= 0;
            if BitPos = 0 then
               if RxD_S2 = '0'  then   -- Start Bit
                  BitPos <= 1;
                  SampleCnt <= 0;
               end if;
            else   
               sampleCnt <= SampleCnt + 1;
               if SampleCnt >= OVSFAC-1 then -- Increment BitPos
                  BitPos <= BitPos + 1;
               elsif SampleCnt = (OVSFAC - 1)/2 then
                  RReg <= RxD_S2 & RReg(7 downto 1); -- Deserialisation LSB first
                  CASE BitPos is
                     WHEN 1 =>
                        if RxD_S2 = '1' then -- Start Bit Error
                           BitPos <= 0;
                        end if;
                     WHEN 10 =>
                        BitPos <= 0;
                        if RxD_S2 = '0' then -- Stop Bit Error
                           RcvErr <= '1';
                        else  
                           DataO(7 downto 0) <= RReg; -- Store received byte
                           RxAv <= '1';
                        end if;
                     WHEN OTHERS => -- Data bits
                  END CASE;   
               end if;  -- Sample
            end if;     -- Bitpos /= 0
         end if;        -- clkcount
      end if;           -- RisindEdge(clk)
   end   process;
   Frame <= '1' WHEN BitPos > 0 ELSE
            '0';
end RTL;
 
Last edited:

About my use of "last_value", I have to find some other solution then. What I would like is to use rising_edge so that it executes the commands inside the if-statement only ONCE, but I guess that would be going back to using several clocks.

I think you need to stop looking for a solution via the VHDL. You need to work out the solution in terms of hardware first before you write any VHDL (usually on paper)

You need to remember that VHDL was origionally written to simulate digital circuits on a PCB, hence why we have the extra Weak unknown ('W'), weak Low('L'), weak high ('H'), 'Z' for high impedance. In an FPGA, only '1' and '0' have real meaning ('Z' for tri-state buffers on the pins too). 'U' and 'X' are used for debugging in simulation.

As for clocks, in an FPGA registers can only be clocked from a single clock, on a single edge, so you cannot have multiple clocks inside a process.

Forget about sensitvity lists in hardware. THey are IGNORED. it builds the logic from the connections you made and the templates it understands. It will try and build a circuit from behaviour but it has limitations on it's understanding and a limit on the hardware available. If you dont understand the hardware or the synthesis limitations, then you are going to be stuck in your VHDL for a long time.
 

I think you need to stop looking for a solution via the VHDL. You need to work out the solution in terms of hardware first before you write any VHDL (usually on paper)
As Tricky points out the solution isn't how to take advantage of all the VHDL language constructs. Many of them won't synthesize anyways.

What you need to do is stop thinking like a software programmer and start looking at your code as if it was a schematic.
* Properly written edge sensitive processes are flip-flops
* level sensitive processes are combinational logic
* signals are the wires that hook up the logic and the flip-flops
* ports are the pins on the ICs you solder to the PCB.

When you decide "I want to write a VHDL 'program' to count something"...you should be thinking of the hardware required...
I need an adder to add 1 to some value (combinational logic) I have in a bunch of flip-flops (edge-sensitive logic) and I'll stuff the result back into that same set of flip-flops. Anything you want to save for any reason has to be clocked into a flip-flop or RAM, unlike a software program which allocates storage when variables are declared.

As has been stated previously you have to know what hardware you want before you can write VHDL code that represents that hardware. Instead you're writing a VHDL 'program' and expecting it to be hardware.


Regards


program
— n
1. a sequence of coded instructions fed into a computer, enabling it to perform specified logical and arithmetical operations on data
 

So I've read the whole chapter in my book about HDL's, but I still don't understand the deal about the sensitivity list. TrickyDicky said the following:

Synthesis ignores sensitivity lists, so missing some out will only lead to a difference in behaviour between your simulation and real hardware.

Which means that it doesn't matter what I put in the sensitivity list, but no other guide that I've read says the same thing. My book gives a great example with a asynchronously triggered flip-flop and a synchronously triggered flip-flop where the only difference is whether RST is in the sensitivity list or not. If the sensitivity list is ignored in synthesis, it seems important to state so in these guides, no? Why don't they?

My question is still, what then makes the process re-evaluate if not the sensitivity list? Does it just look for a rising_edge somewhere inside the process? What if I have a process that doesn't have a rising_edge inside it?
 

What is your VHDL textbook? does it also deal with synthesis related problems? I think tools may now start to be looking at process behaviour rather than just pure logic, but I wouldnt count it as reliable as your code still has to map to LUTs and registers, and it will only do the best it can. It will also only synthesise from known templates, and anything outside of the norm can become uncompilable in synthesis (and to make life even more complicate, some tools may choke on code that others have no problem with).

A process is re-evaluated in simulation when a signal in the sensitivity list has a 'event ie a change. so for a std_logic this could be a change from 'U' to 'X', or 'Z' to '1'. Not just a rising edge (hence why you need to explicitly state "if rising_edge(clk) then" in your synchronous processes.)

Can you post this magic code that changes from being synchronous to asynchonous just based on the sensitivity list - Id like to see it.
 

Code:
architecture asynchronous of flopr is
begin	
	process(clk, reset) begin
		if reset then
			q <= "0000";
		elsif rising_edge(clk) then
			q <= d;
		end if;
	end process
end;

architecture synchronous of flopr is
begin
	process(clk) begin
		if rising_edge(clk) then
			if reset then q<="0000";
			else q <= d;
			end if;
		end if;
	end process;
end;

Multiple signals in a process sensitivity list are separated with a comma. Notice that reset is in the sensitivity list on the asynchronously resettable flop, but not on the synchronously resettable flop. Thus, the asynchronously resettable flop immediately responds to a rising edge on reset, but the synchronously resettable flop responds to reset only on the rising edge of the clock.

What about this though:

Code:
	signal UARTREG : STD_LOGIC_VECTOR(9 DOWNTO 0);
	signal counter2 : unsigned (4 DOWNTO 0);



begin

	RX <= KEY(0);
	LED(0) <= EN;
	LED(1) <= ((not RX) and (not EN));
	LED(3) <= newClock;
	LED(4) <= PreviousClock;
	
	test <= (newClock and (not previousClock));
	
	process(CLOCK_50)
	variable counter : integer := 0;
	begin	
		
		if (((not RX) and (not EN)) = '1') then
			EN <= '1';
		end if;

		if (EN = '1') then
			if rising_edge(CLOCK_50) then
				prescaler_counter <= prescaler_counter + 1;
				if(prescaler_counter > prescaler) then
					newClock <= not newClock;
					prescaler_counter <= (others => '0');
					counter := counter + 1;
					
					UARTREG( to_integer(counter) ) <= RX;
					
				end if;
			end if;
			
		end if;

It complains about the "UARTREG( to_integer(counter) ) <= RX;" by saying "Error (10405): VHDL error at UART.vhd(51): can't determine type of object at or near identifier "to_integer" -- found 0 possible types". I tried to use "unsigned" instead (as mentioned in the beginning of the thread", but that doesn't seem to work either. These error messages seems to pop up in a wide variety of different colors and I can rarely understand what it's complaining about. Why can't everything just be one type and even if there's a need for different "types", what can't they be connected together without using the "to_" command?

Also what I've been told about trying to think of this as a schematic, draw it on a piece of paper before writing it etc. How am I expected to write this down as a block diagram or as a number of gates? I find that almost impossible to visualize. I do my best to think in a parallel fashion, but I find it incredibly hard to look at a piece of VHDL code and to then try and visualize it as a schematic.
 
Last edited:

My book gives a great example with a asynchronously triggered flip-flop and a synchronously triggered flip-flop where the only difference is whether RST is in the sensitivity list or not.
The code shows that you are essentially misunderstanding the text book statement.
The difference is asynchronous versus synchronous reset of a synchronous flip-flop. It's not established by the sensitivity list but by a different placement of the reset clause. The sensitivity list just considers simulation requirements.

The problem with to_integer() is rather trivial. It's an error to apply it to an integer signal or variable, it's defined for signed or unsigned only.
 

the two codes are completly different, they are not just a difference in the sensitivity list. The first can occur regardless of the clock (async reset) the second requires the clock for it to activate (sync reset).

If you want less type control - I suggest verilog. VHDL has strong typing, so even if everything essentially translates into the base hardware, you're putting checks in the code from a behaviour perspective. It means it can be more self linting.

And I highly suggest trying to work out the architecture before writing the code. It is a description language after all, not a progamming language.

In your code, you are missing RX and EN from your sensitivity list btw.
 

The problem with to_integer() is rather trivial. It's an error to apply it to an integer signal or variable, it's defined for signed or unsigned only.

So how should I do it then?
 

Either change your code to use signed/unsigned or create a function to perform the conversion of a slv to integer.
 

So how should I do it then?
To fix the error, you can write
Code:
UARTREG(counter) <= RX;
instead of
Code:
UARTREG( to_integer(counter) ) <= RX;
But it's an incomplete snippet with counter only counted up which can't work as an index.
 

I'm getting a better understanding, I finally have a working UART that can both receive and transmit :) Another quick issue though:

Code:
library IEEE; 
use IEEE.STD_LOGIC_1164.all; 
use IEEE.STD_LOGIC_UNSIGNED.all;
use IEEE.NUMERIC_STD.all;

entity instr_mem is 
  port (addr, input_instruction : IN STD_LOGIC_VECTOR(31 downto 0);
			WE, word_ready : IN STD_LOGIC;
        instr: OUT STD_LOGIC_VECTOR(31 downto 0));
end; 

architecture instr_mem_beh of instr_mem is 

	
	type instruction_array is array (40 DOWNTO 0) of STD_LOGIC_VECTOR(31 DOWNTO 0);
   signal instruction_memory : instruction_array;
	
	signal counter2 : unsigned(31 DOWNTO 0);
	
  BEGIN 
	counter2 <= to_unsigned(addr);

  
    PROCESS (word_ready, addr)
	 variable counter : integer := 0;
		BEGIN 
			if (WE = '0') then
				if rising_edge(word_ready) then
					instruction_memory(counter) <= input_instruction;
					counter := counter + 1;
				end if;
			else 
				counter := 0;
				instr <= instruction_memory(to_integer(counter2));
				
			end if;
				
				
	end process;
end instr_mem_beh;

Error (10476): VHDL error at instr_mem.vhd(22): type of identifier "addr" does not agree with its usage as "natural" type

I don't care what it agrees to or doesn't agree to, it's supposed to do what it's told! I need to connect counter2 to addr, but addr is of type STD_LOGIC_VECTOR and counter2 is of type unsigned. Using "to_unsigned" didn't work :(
 

std_logic_vector and unsigned are closely related types. ie, they are both arrays of std_logic. So all you need is a type cast:

counter2 <= unsigned(addr);
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top