I'm building a counter that counts rising edges from an input channel. I've simplified my design to include two states, one and two, where counting is done. For some reason, whenever I try to add 1 to counter_reg, or try to assign any number at all to it, the signal becomes red with an X in ModelSim. The code and picture of what happens to the signal are provided below.
I have included the IEEE.NUMERIC_STD.ALL, so I should be able to do unsigned addition. I am not sure what is wrong with counter_reg. Is there anything I'm doing wrong with the counter?
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity photon_counter is
Port ( clk,reset : in STD_LOGIC;
arm,shifter,channel : in STD_LOGIC;
start : in STD_LOGIC);
end photon_counter;
architecture fsm_arch of photon_counter is
type state_type is (idle,zero,one);
type array_type is array (1 downto 0) of UNSIGNED (15 downto 0);
signal state_reg,state_next : state_type;
signal arm_prev,shifter_prev,channel_prev : STD_LOGIC;
signal counter : array_type;
signal counter_reg,counter_next : UNSIGNED (15 downto 0);
begin
--------------------------------------
--State Register
--------------------------------------
process(clk,reset)
begin
if reset='1' then
state_reg <= zero;
counter_reg <= (others => '0');
counter <= (others => (others => '0'));
elsif rising_edge(clk) then
state_reg <= state_next;
counter_reg <= counter_next;
arm_prev <= arm;
shifter_prev <= shifter;
channel_prev <= channel;
end if;
end process;
--------------------------------------
--Next-State Logic/Output Logic
--------------------------------------
process(clk,reset,state_reg,start,counter_reg,shifter_prev,shifter,arm,channel_prev,channel)
begin
--default actions
state_next <= state_reg;
counter_next <= counter_reg;
counter_reg <= counter_reg;
case state_reg is
when idle =>
counter_reg <= (others => '0');
counter <= (others => (others => '0'));
if start = '1' then
state_next <= zero;
end if;
when zero =>
if (shifter = '1') and (shifter_prev = '0') then
state_next <= one;
counter(0) <= counter_reg;
end if;
if (channel = '1') and (channel_prev = '0') then
counter_next <= counter_reg + 1;
end if;
when one =>
if arm = '1' then
state_next <= zero;
counter(1) <= counter_reg;
end if;
if (channel = '1') and (channel_prev = '0') then
counter_reg <= counter_reg + 1;
end if;
end case;
end process;
end fsm_arch;
As shown below, counter_reg and counter_next start off with a value of 0 until I try to add 1 to counter_next. The moment channel_prev rises, both counter_reg and counter_next become X (error) and turn red.
Your counter_reg signal is assigned in two different processes. This is what we call a "multiple drive" situation. It is usually undesirable, just like any short circuit, because when the two processes disagree about the value to assign things are getting very bad.
Solution: drive your counter from one single process.
A bit more about this: if this is bad, why didn't you get an error when compiling or when launching your simulation? Because most people do not know or care about unresolved/resolved types in VHDL. By default, a VHDL type is unresolved. This means that, if you try to drive a signal of this type from more than one process you will get an error at compilation or elaboration time that basically says "I cannot decide what value to assign if your processes disagree, this is forbidden". And this is a very nice feature because such accidental short circuits can have serious consequences. You can try this and see the errors by replacing your unsigned (resolved) counter by a natural (unresolved) one:
signal counter_reg,counter_next : natural 0 to 2**16 - 1;
adapt the rest of your code, and see what happens when compiling.
Sometimes, rarely, it is useful to drive a signal from more than one process (high impedance shared bus, bi-directional RAM data bus...) So VHDL allows to define a resolution function that computes the resulting value of several drivers. This function can be used to define the resolved subtype of a unresolved parent type. If you can find the source code of ieee.std_logic_1164 you will see the declaration of the unresolved, 9-valued std_ulogic type (u for unresolved), the resolution function, and the declaration of the resolved subtype std_logic (see? no u).
But when using resolved types you must yourself take care of not creating short-circuits. There is no compiler error any more, no seatbelt. When one of your driving processes drives a strong value ('0' or '1'), all the others must drive a weak value ('Z' for high impedance). Else, you will get unknown resulting values, represented in red by Modelsim, as you saw.
Unfortunately, most people do not really know what the U stands for in std_Ulogic. So, in order to simplify they always use std_logic instead of what they should use: std_ulogic. Moreover, vendors of logic synthesisers push in the same direction because they frequently favour std_logic (when they do not simply force you to use it). And the people who standardized the ieee.numeric_std package did the same: they declared the unsigned and signed types as resolved types (if fact, they have the same declaration as std_logic_vector). This is as unfortunate as driving full speed, at night, wearing sunglasses, without light and without your seatbelt fasten.
Finally, someone realized how unfortunate this was and the current version of ieee.numeric_std now also declares UNRESOLVED_UNSIGNED (alias U_UNSIGNED) and UNRESOLVED_SIGNED (alias U_SIGNED). Alas, this is a bit too late, most designers will never change their existing code or habits, and I wonder how many bugs could have been avoided if the first choice had been different.
My advices:
never drive a signal from several processes if you do not really intend to have multiple physical drivers, manually avoid short circuits, and so on,
never use a resolved type if you do not need it, so that the tools will raise an error if you accidentally create a multiple drive situation,
in your case, drive counter_reg from one single process, declare it as U_UNSIGNED or NATURAL, and declare all your other signals as STD_ULOGIC, not STD_LOGIC.
Related
i pretty new of vhdl and i'm trying to learn how to do a FSM with vhdl.
At moment i need a code that after a fixed count value, it give me back a pulse, in order to start a second FSM block. (I have a recurring signal every 100 kHz, i need to count it and release this signal after a fixed number of counts).
Actually it work as free run, every time that it see this signal, it start to count, but realy i want to add a "start" signal, so it must start to count this signal after it see this start signal.
at moment my working code is:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
entity counter is
Port (
signal_in : in STD_LOGIC := '0'; --segnale di start
clk : in STD_LOGIC; --clock di ingresso
reset : in STD_LOGIC; --ff reset
signal_out: out STD_LOGIC; --gate in uscita
count_val: in std_logic_vector (7 downto 0);
start : in STD_LOGIC := '0'
);
end counter;
architecture behavioral of counter is
type state_type is (idle, count_up);
signal state : state_type;
begin
process (reset, clk, signal_in, start)
variable index : integer :=0;
variable countlen: integer;
variable count_v: std_logic;
variable countlen2 : std_logic;
begin
countlen := to_integer(unsigned(count_val))-1;
if reset = '1' then
count_v := '0';
index := 0;
state <= idle;
else
--if start = '1' and
--if rising_edge(clk) then
if rising_edge(signal_in) then
case state is
when idle =>
count_v :='0';
index := 0;
if (signal_in = '1') then
state <= count_up;
else
state <= idle;
end if;
when count_up =>
if(index < countlen) then
state <=count_up;
index := index + 1;
elsif
index = countlen then
count_v := '1';
state <=idle;
end if;
when others => null;
end case;
end if;
end if;
signal_out <= count_v;
end process;
end Behavioral;
Any attempt to work with cose with "start = 1" will stop the count.
Please some one have some suggestion?
Kind REgards
Fulvio
Welcome om StackOverflow. Your specification is not 100% clear. What difference do you make between signal_in and start? According to your code and to your explanations, they both seem to act as a starter.
Moreover, there are several strange things with your code:
your process seems to be a synchronous one, with asynchronous reset. Its sensitivity list should contain only the clock and the reset. And its body should be:
process(clk, reset)
<variable declarations>
begin
<NOTHING HERE>
if reset = '1' then
<reset code>
elsif rising_edge(clk) then
<regular code>
end if;
<NOTHING HERE>
end process;
you are using signal_in as a clock and as a logic signal. This is extremely strange. Moreover, your if (signal_in = '1') then is always true (in the synthesis semantics) and thus useless.
You are initializing variables at declaration (index). This is not supported by some synthesizers and hardware targets. Moreover, even when supported, it works only at power up. If:
you intend to synthesize your code,
you want it to be portable across synthesizers and hardware targets,
you want to re-initialize signal and variables not only at power up but also when a reset input is asserted,
prefer a real explicit reset, instead, and guarantee that it is always asserted after power up (or at the beginning of a simulation) for proper first initialization.
you declare variable index with a full integer range, that is, 32 bits minimum, while 8 bits would suffice. This is a potential waste of hardware resources.
It is difficult to propose a solution without a clear and complete specification but assuming you want to count only after start has been asserted and only when signal_in is asserted, the following may be a starting point:
process (clk, reset)
variable index: natural range 0 to 255;
begin
if reset = '1' then
state <= idle;
signal_out <= '0';
index := 0;
elsif rising_edge(clk) then
case state is
when idle =>
signal_out <= '0';
index := 0;
if start = '1' then
state <= count_up;
end if;
when others =>
if signal_in = '1' then
if index = to_integer(unsigned(count_val)) - 1 then
state <= idle;
signal_out <= '1';
else
index := index + 1;
end if;
end if;
end case;
end if;
end process;
Note that this is really synchronous of your clock clk. I suspect that you made a very common mistake: as you wanted to increment your counter when signal_in is asserted you decided more or less to use signal_in as a clock. This is not a real synchronous and safe design. In a real safe synchronous design you do not use logic signals as clocks. You have well identified clocks and you use only these as clocks. In your case there is one single clock: clk. If you want to do something synchronously when a logic signal is asserted, wait for the rising edge of your clock and then test the logic signal and take appropriate actions.
thanks for your support.
Yes the point is that i need to "decimate" (or count) a signal.
This signal had a width of 50-100ns and it repeat itself with a frequency of 100 kHz.
so in my mind, this signal will go in to "signal in". My FPGA is an Actel proasic3 with a clock of 40 MHz.
In my setup this signal will be always on, but i don't want that my FSM will start to count as it see the first "signal in" but only when i send a "start" signal for the number of count that i indicate. (Realy they ask to me the possibility to decimate this signal up to 65000 count, so for sure i need to use a 16bit vector instead of 8bit).
The async reset is here "just in case" i need to reset the whole fsm in the middle of some data record.
Hope to be more clear now what this code should do.
For Old fart, yes indeed all my signal coming outside the fpga will be first synchronized with a simple 2 ff synchronizer with the FPGA clock
This is a branch off of a separate question I asked. I am going to explain more in depth on what I am trying to do and what it is not liking. This is a school project and doesn't need to follow standards.
I am attempting to make the SIMON game. Right now, what I am trying to do is use a switch case for levels and each level is supposed to be faster (hence different frequency dividers). The first level is supposed to be the first frequency and a pattern of LEDs is supposed to light up and disappear. Before I put in a switch case, the first level was by itself (no second level stuff) and it lit up and disappeared like it should. I also used compare = 0 in order to compare in output to an input. (The user is supposed to flip up the switches in the light pattern they saw). This worked when the first level was by itself but now that it is in a switch case, it doesn't like compare. I'm not sure how to get around that in order to compare an output to an input.
The errors I am getting are similar to before:
Error (10821): HDL error at FP.vhd(75): can't infer register for "compare" because its behavior does not match any supported register model
Error (10821): HDL error at FP.vhd(75): can't infer register for "count[0]" because its behavior does not match any supported register model
Error (10821): HDL error at FP.vhd(75): can't infer register for "count[1]" because its behavior does not match any supported register model
Error (10821): HDL error at FP.vhd(75): can't infer register for "count[2]" because its behavior does not match any supported register model
Error (10822): HDL error at FP.vhd(80): couldn't implement registers for assignments on this clock edge
Error (10822): HDL error at FP.vhd(102): couldn't implement registers for assignments on this clock edge
Error (12153): Can't elaborate top-level user hierarchy
I also understand that it doesn't like the rising_edge(toggle) but I need that in order to make the LED pattern light up and disappear.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity FP is
port(
clk, reset : in std_logic;
QF : out std_logic_vector (3 downto 0);
checkbtn : in std_logic;
Switch : in std_logic_vector(3 downto 0);
sel : in std_logic_vector (1 downto 0);
score : out std_logic_vector (6 downto 0)
);
end FP;
architecture behavior of FP is
signal time_count: integer:=0;
signal toggle : std_logic;
signal toggle1 : std_logic;
signal count : std_logic_vector (2 downto 0);
signal seg : std_logic_vector (3 downto 0);
signal compare : integer range 0 to 1:=0;
type STATE_TYPE is (level1, level2);
signal level : STATE_TYPE;
--signal input : std_logic_vector (3 downto 0);
--signal sev : std_logic_vector (6 downto 0);
begin
process (clk, reset, sel)
begin
if (reset = '0') then
time_count <= 0;
toggle <= '0';
elsif rising_edge (clk) then
case sel is
when "00" =>
if (time_count = 1249999) then
toggle <= not toggle;
time_count <= 0;
else
time_count <= time_count+1;
end if;
when "01" =>
if (time_count = 2499999) then
toggle1 <= not toggle1;
time_count <= 0;
else
time_count <= time_count+1;
end if;
when "10" =>
if (time_count = 4999999) then
toggle <= not toggle;
time_count <= 0;
else
time_count <= time_count+1;
end if;
when "11" =>
if (time_count = 12499999) then
toggle <= not toggle;
time_count <= 0;
else
time_count <= time_count+1;
end if;
end case;
end if;
end process;
Process (toggle, compare, switch)
begin
case level is
when level1 =>
if sel = "00" then
count <= "001";
seg <= "1000";
elsif (rising_edge (toggle)) then
count <= "001";
compare <= 0;
if (count = "001") then
count <= "000";
else
count <= "000";
end if;
end if;
if (switch = "1000") and (compare = 0) and (checkbtn <= '0') then
score <= "1111001";
level <= level2;
else
score <= "1000000";
level <= level1;
end if;
when level2 =>
if sel = "01" then
count <= "010";
seg <= "0100";
elsif (rising_edge (toggle1)) then
count <= "010";
compare <= 1;
if (count = "010") then
count <= "000";
else
count <= "000";
end if;
end if;
if (switch = "0100") and (compare = 1) and (checkbtn <= '0') then
score <= "0100100";
else
score <= "1000000";
level <= level1;
end if;
end case;
case count is
when "000"=>seg<="0000";
when "001"=>seg<="1000";
when "010"=>seg<="0100";
when "011"=>seg<="0110";
when "100"=>seg<="0011";
when others=>seg<="0000";
end case;
end process;
QF <= seg;
end behavior;
Thanks again in advance!
Well... it is hard to tell what is wrong, because this state machine is written in wrong way. You should look for references about proper modeling of FSM in VHDL. One good example is here.
If you use Quartus, you could also look for Altera's description on how to model FSM specifically for their compiler.
I will now give you just two advices. First is that you shouldn't (or mabye even you can't) use is two
if rising_edge (clk)
checks in one process. If your process is supposed to be sensitive on clock edge, write it once at the beginning.
Second thing is that if you want to model FSM with one process with synchronous reset, then put just clk on sensitivity list.
EDIT after question and code edit:
Ok, much better now. But another few things:
Your FSM is still not like it should. Look again at the example in the source I gave you above and edit it to be like there, or make it one process FSM like in example in this link.
Intends! Very important. I couldn't spot some of obvious errors, before I made proper intendation in your code. This leads me to...
Look at the places, there you assign values to count, in particular the if statements. No mater what, you assign the same value of "000".
Similar story with another signal - seg. You assign to it some value in the process, and then at the end of this process there is case statement in which you assign to it some other value, making this previous assignments irrelevant.
Use rising_edge only once in the process, only to clock, and only at the very beginning of the process, or in the way you did in the first process, that has asynchronous reset. In second process you did all this three things.
In sequential process with rising_edge, like the first one, you don't have to put to sensitivity list anything more than clock, and reset if it is asynchronous, like in your case.
Sensitivity list in second process. It is parallel process, so you should put there signals, that you check in a process, and can change outside of it. It is not the case for compare. But there should be signals: level, sel and toggle1.
As I'm still not sure what are you trying to achieve, I will not tell you what exactly to do. Fix your code according to points above, then maybe it will just work.
I have the below code in VHDL that I use in a project. I have been using a Process within the architecture and wanted to know if there were any other means which I'm sure there are of accomplishing the same goal.. in essence to take one number compare it to another and if there is a difference of +/- 2 reflect this in the output. I am using the following:
LIBRARY IEEE;
USE IEEE.std_logic_1164.all, IEEE.std_logic_arith.all, IEEE.std_logic_signed;
ENTITY thermo IS
PORT (
CLK : in std_logic;
Tset, Tact : in std_logic_vector (6 DOWNTO 0);
Heaton : out std_logic
);
END ENTITY thermo;
ARCHITECTURE behavioral OF thermo IS
SIGNAL TsetINT, TactINT : integer RANGE 63 Downto -64; --INT range so no 32bit usage
BEGIN
Heat_on_off: PROCESS
VARIABLE ONOFF: std_logic;
BEGIN
TsetINT <= conv_integer (signed (Tset));--converts vector to Int
TactINT <= conv_integer (signed (Tact));--converts vector to Int
--If you read this why is it conv_integer not to_integer?? thx
ONOFF := '0'; --so variable does not hang on start
WAIT UNTIL CLK'EVENT and CLK = '1';
IF TactINT <= (TsetINT - 2) then
ONOFF := '1';
ELSIF TactINT >= (TsetINT + 2) then
ONOFF := '0';
END IF;
Heaton <= ONOFF;
END PROCESS;
END ARCHITECTURE behavioral;
I'm just after a comparison really and to know if there are any better ways of doing what I have already done.
Why convert Tact and Tset to an integer?
Why have the variable ONOFF? The variable initialization appears to remove any sense of hysteresis, is that what you intended? Based on your other code, I bet not. I recommend that you assign directly to the signal Heaton instead of using the variable ONOFF.
If I were to create TsetINT and TactINt, these would be good candidates to be variables. However, there is no need to do the integer conversion as you can simply do the following:
if signed(Tact) <= signed(Tset) - 2 then
...
elsif signed(Tact) >= signed(Tset) + 2 then
Please use numeric_std. Please ask your professor why they are teaching you old methodologies that are not current industry practice. Numeric_std is an IEEE standard and is updated with the standard, std_logic_arith is not an IEEE standard.
use ieee.numeric_std.all ;
In response to Jim's comment I wrote a simple thermal model test bench to test your design.
I only changed your design to use package numeric_std instead of the Synopsys packages. The rest is just prettifying and eliminating comments not germane to the question of whether or not Tact ever reaches Tset.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity thermo is
port (
CLK: in std_logic;
Tset, Tact: in std_logic_vector (6 downto 0);
Heaton: out std_logic
);
end entity thermo;
architecture behavioral of thermo is
signal TsetINT, TactINT: integer range 63 downto -64;
begin
HEAT_ON_OFF:
process
variable ONOFF: std_logic;
begin
TsetINT <= to_integer (signed (Tset)); -- package numeric_std
TactINT <= to_integer (signed (Tact)); -- instead of conv_integer
ONOFF := '0'; -- AT ISSUE -- so variable does not hang on start
wait until CLK'event and CLK = '1';
if TactINT <= TsetINT - 2 then -- operator precedence needs no parens
ONOFF := '1';
elsif TactINT >= TsetINT + 2 then
ONOFF := '0';
end if;
Heaton <= ONOFF;
end process;
end architecture behavioral;
You have a comment in your process asking why conv_integer was required instead of to_integer. That prompted the change.
I removed superfluous parentheses based on operator order precedence (adding operators being higher precedence than relational operators), notice Jim's answer did the same.
So the simple model thermal model runs with a clock set to a 1 second period, and has two coefficients, relating to the temperature increase when Heaton is '1' or not. I arbitrarily set the heating up coefficient to 1 every 4 clocks, and the temperature decay coefficient to 1 every 10 clocks. Also set the ambient temperature (tout) to 10 and tset to 22. The numbers selected are severe to keep the model run time short enhancing portability without relying on setting a simulator resolution limit.
The thermal model was implemented using fixed signed arithmetic without using fixed_generic_pkg, allowing portability to -1993 tools without math packages and includes a fractional part, responsible for the different widths of Heaton true after reaching normal operating temperature. The model could just as easily have been implemented with two different precursor counters used to tell when to increment or decrement Tact.
Using REAL types is possible, not desirable because converting REAL to INTEGER (then to SIGNED) isn't portable (IEEE Std 1076-2008 Annex D).
The idea here is to demonstrate the lack of hysteresis and demonstrate the model doesn't reach Tset:
The lack of hitting Tset (22 + 2) is based on the lack of hysteresis. Hysteresis is desirable for reducing the number of heat on and off cycles The idea is once you start the heater you leave in on for a while, and once you stop it you want to leave it off for a while too.
Using Jim's modification:
-- signal TsetINT, TactINT: integer range 63 downto -64;
begin
HEAT_ON_OFF:
process (CLK)
begin
if rising_edge(CLK) then
if signed(Tact) <= signed(Tset) - 2 then
Heaton <= '1';
elsif signed(Tact) >= signed(Tset) + 2 then
Heaton <= '0';
end if;
end if;
end process;
gives us longer Heaton on and off cycles, decreasing how many times the heater starts and stops:
And actually allows us to see the temperature reach Tset + 2 as well as Tset - 2. where these thresholds provide the hysteresis which is characterized as a minimum on or minimum off time, depending on the efficiency of the heater and heat loss rate when the heater is off.
So what changed in the execution of the thermo model process? Look at the difference in the synthesis results for the two versions.
I'm working on a final project for school and this is my first time working with VHDL in Quartus and ModelSIM. It's supposed to be a control for an elevator that services three floors. I have these strange spikes in a few signals, and I can't seem to find their source.
The one problem I have is a spike in a signal that feeds to an up/down counter that shows the current floor. When it stops at a floor, it ends up counting one additional time and going either one floor too high or one floor too low, while the next floor display seems to show the same floor just fine until another floor is called. The next floor display comes from an FSM, while the current floor display is from an up/down counter.
It's a bit complex to post everything here, so I'm just going to post the waveform for now in case someone's come across this signal spike thing and it ends up being a minor error/easy fix.!
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
entity FSM_Elevador is
port (Up_Down, Igual, Reset, Clock: in std_logic;
Andar_Dif: out std_logic
);
end FSM_Elevador;
architecture FSM_beh of FSM_Elevador is
type Elev_States is (Start, Wait_State, Pulse_State);
signal Current_State, Next_State: Elev_States;
signal RST, CLK, Sig_Andar_Dif, Cont_Mesmo_Andar: std_logic;
begin
RST <= Reset;
CLK <= Clock;
process(RST, CLK)
begin
if RST = '0' then
Current_State <= Start;
elsif CLK'event and CLK = '1' then
Current_State <= Next_State;
end if;
end process;
process(Current_State, Igual)
begin
case Current_State is
when Start =>
Next_State <= Wait_State;
when Wait_State =>
if Igual = '1' then
Next_State <= Wait_State;
Sig_Andar_Dif <= '0';
else
Next_State <= Pulse_State;
Sig_Andar_Dif <= '1';
end if;
when Pulse_State =>
if Igual = '1' then
Sig_Andar_Dif <= '0';
Next_State <= Wait_State;
else
Sig_Andar_Dif <= '0';
Next_State <= Pulse_State;
end if;
end case;
end process;
Andar_Dif <= Sig_Andar_Dif;
end FSM_beh;
fru1tbat: I use the Elev_pulse to make the counter go up or down once, and yes it enters the counter as a clock. It was suggested by the professor.
Edit: sorry that was the wrong code earlier. Andar_Dif is what sends out the signal that ends up going to the component that has Elev_Pulse
Get rid of the reassignment of Clock and Reset to CLK and RST and just use the signals from the port directly. That is creating a delta cycle delay which is the cause of these kind of spikes. It looks like you have resets with different delays in the design which can also complicate matters. If the removal of the indirection doesn't clear things up you need to scrutinize the ordering of when events are generated on signals and when they are processed.
The outputs from your state machine are unregistered which is also potentially involved. Consider reworking the FSM so that all outputs are registered. This is a better design practice in general as it ensures that you don't have unknown combinational delays affecting downstream logic.
I am writing a RS232 module for my Nexys2 board. I am currently having issues with my baud rate controller which I want to set to 19200.
For this I am using a Mod-M counter, after many ISim simulations the problem with my code is in the mod-m counter as it is not producing any ticks.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity baud_rate is
generic (
N: integer := 8;
M: integer :=163);
Port (clk, reset : in STD_LOGIC;
tick : out STD_LOGIC;
q : out STD_LOGIC_VECTOR(N-1 downto 0));
end baud_rate;
architecture Behavioral of baud_rate is
signal r_reg : unsigned(N-1 downto 0);
signal r_next : unsigned(N-1 downto 0);
begin
process(clk,reset)
begin
if (reset ='1') then
r_reg <= (others=>'0');
elsif(clk'event and clk='1') then
r_reg <= r_next;
end if;
end process;
r_next <= (others =>'0') when r_reg=(M-1) else r_reg+1;
tick <='1' when r_reg=(M-1) else '0';
q <= std_logic_vector(r_reg);
end Behavioral;
I have tested and all the clk inputs and run fine and the issue seems to be with the r_reg and r_next registers. In ISim when outputing either of these on q I get UUUUUUUU, so it seems they are not generating signal. From this i can infer that the two r_reg and r_next registers aren't being created or storing values, is there an issue when using unsigned?
To make triple sure I have even copied the mod-m counter from the book FPGA Prototyping with VHDL (which is the code shown) BUT still this does not work and q output is UUUUUUUU.
If there are any better ways of creating a baud rate from the nexys2 50mz clock that would also be appreciated!
Cheers
Frankly I am horrified if people are expected to learn VHDL from a book where examples like this are presented. I know the author has a similar book on Verilog : do people end up thinking VHDL is just a more verbose Verilog?
Specific criticisms (actually 7,8 are more observations):
1) Spurious type conversions.
Q represents an unsigned number. So make it unsigned!
The baud generator isn't the only thing in your FPGA so Q isn't likely to be an off-chip port. There are good arguments for making top level, off-chip ports std_logic_vector but even that isn't compulsory. However, if your customer's specification or coding style insists on spurious type conversions on ports; follow it.
2) the DRY principle:
package CPU_types is
subtype baud_count is unsigned(7 downto 0);
end CPU_types;
Spot the simplification in maintenance.
If you are using a subtype in several places, put it in a package; the universal code reuse tool.
3) Indentation, formatting. (I recognise that may have become garbled by editor settings). It adds to the brain load reading it. What I've done here isn't The One Way though.
4) Spurious brackets round logical expressions. Harmless, but look like crutches for C programmers.
5) Antique clk'event style. Next year, the rising_edge function will be old enough to drink (in America. In Britain it's been getting plastered every Saturday night for a couple of years now...)
6) The "two process" style with r_reg and r_next. Does he also write state machines with a separate combinational process on next_state? Given this, I'm guessing so. Single process state machines are easier, smaller (to write : they don't generate smaller hardware) and safer.
7) I cheated and my tick is one cycle later than in the original. If that is critical, restore the external "tick" assignment. I also made it synchronous vhich will help performance. Some people would prefer tick <= '0' in an else clause; however the default assignment I used is safe, and prevents a lot of mistakes (and unnecessary else clauses) in larger designs.
8) The assignment to Q can be brought into the process too; if you made r_reg a process variable you'd have to. There is room for other variations and preferences.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use CPU_types.all;
entity baud_rate is
generic (
M: integer := 163);
Port (
clk, reset : in STD_LOGIC;
tick : out STD_LOGIC;
q : out baud_count);
end baud_rate;
architecture Behavioral of baud_rate is
signal r_reg : baud_count;
begin
process(clk,reset)
begin
if reset ='1' then
r_reg <= (others=>'0');
elsif rising_edge(clk) then
tick <= 0;
r_reg <= r_reg+1;
if r_reg = M then
tick <= '1';
r_reg <= (others=>'0');
end if;
end if;
end process;
-- tick <='1' when r_reg = M-1 else '0';
-- or simpler, when r_reg = 0
q <= r_reg;
end Behavioral;