Ideas for a flexible/generic decoder in VHDL - vhdl

I want to create an address Decoder that is flexible enough for me to use when changing the number of bits of the selector and of the decoded output signals.
So, instead of having a static (fixed input/output size) Decoder that looks something like this :
entity Address_Decoder is
Generic
(
C_INPUT_SIZE: integer := 2
);
Port
(
input : in STD_LOGIC_VECTOR (C_INPUT_SIZE-1 downto 0);
output : out STD_LOGIC_VECTOR ((2**C_INPUT_SIZE)-1 downto 0);
clk : in STD_LOGIC;
rst : in STD_LOGIC
);
end Address_Decoder;
architecture Behavioral of Address_Decoder is
begin
process(clk)
begin
if rising_edge(clk) then
if (rst = '1') then
output <= "0000";
else
case <input> is
when "00" => <output> <= "0001";
when "01" => <output> <= "0010";
when "10" => <output> <= "0100";
when "11" => <output> <= "1000";
when others => <output> <= "0000";
end case;
end if;
end if;
end process;
end Behavioral;
Have something that is more flexible/general, that looks like this:
entity Address_Decoder is
Generic
(
C_INPUT_SIZE: integer := 2
);
Port
(
input : in STD_LOGIC_VECTOR (C_INPUT_SIZE-1 downto 0);
output : out STD_LOGIC_VECTOR ((2**C_INPUT_SIZE)-1 downto 0);
clk : in STD_LOGIC;
rst : in STD_LOGIC
);
end Address_Decoder;
architecture Behavioral of Address_Decoder is
begin
DECODE_PROC:
process (clk)
begin
if(rising_edge(clk)) then
if ( rst = '1') then
output <= conv_std_logic_vector(0, output'length);
else
case (input) is
for i in 0 to (2**C_INPUT_SIZE)-1 generate
begin
when (i = conv_integer(input)) => output <= conv_std_logic_vector((i*2), output'length);
end generate;
when others => output <= conv_std_logic_vector(0, output'length);
end case;
end if;
end if;
end process;
end Behavioral;
I know this code is not valid and that the "when" test cases must be constants and that I can't use the for-generate in between the case statement like that, but it shows what it is that I am after: an entity smart enough to grow to my needs.
I have been trying to find an elegant solution for this problem without much success, so, I'm open for any suggestions.
Thanks in advance,
Erick

Apparently you want the input to be the index of the output bit that should be set.
Write it like that. Something like (assuming types from numeric_std):
output <= (others => '0'); -- default
output(to_integer(input)) <= '1';

I have always found this sort of thing easier to follow when you just loop over each bit, so something like:
if ( rst = '1') then
output <= (others=>'0');
else
for i in 0 to (2**C_INPUT_SIZE)-1 generate
begin
if (i = conv_integer(input)) then
output(i) <= '1';
else
output(i) <= '0';
end if;
end generate;
end if;

Related

How can i reduce number of ALMs in my VHDL design?

I'm trying to implement an alarm module for the digital clock in VHDL. I have written architecture for it, but when I run Compilation I get too many Adaptive Logic Modules (around 2000), which I think is too much. I will post my code below.
I think division and modulus operation could be causing it, in this line of code.
alarm_hour1 <= std_logic_vector(to_unsigned(savedHours/10,alarm_hour1'length));
alarm_hour0 <= std_logic_vector(to_unsigned(savedHours mod 10,alarm_hour0'length));
alarm_minute1 <= std_logic_vector(to_unsigned(savedMinutes/10,alarm_minute1'length));
alarm_minute0 <= std_logic_vector(to_unsigned(savedMinutes mod 10,alarm_minute0'length));
Still, I'm not sure how can I work around this.
Also, I would be very grateful if You give more comments on my design, and point out some mistakes, and ways how I can improve my design. I'm fairly new to VHDL so any advice is appreciated.
Thanks a lot.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity alarm is
port(
--INPUTS
reset : in std_logic;
clock : in std_logic;
alarm_enable : in std_logic;
alarm_set : in std_logic;
alarm_increment : in std_logic;
alarm_decrement : in std_logic;
currentTime_hour1 : in std_logic_vector(3 downto 0);
currentTime_hour0 : in std_logic_vector(3 downto 0);
currentTime_minute1 : in std_logic_vector(3 downto 0);
currentTime_minute0 : in std_logic_vector(3 downto 0);
--OUTPUTS
alarm_buzzer : out std_logic;
alarm_hour1 : buffer std_logic_vector(3 downto 0) := "0000";
alarm_hour0 : buffer std_logic_vector(3 downto 0) := "0000";
alarm_minute1 : buffer std_logic_vector(3 downto 0) := "0000";
alarm_minute0 : buffer std_logic_vector(3 downto 0) := "0000"
);
end alarm;
architecture alarmBehaviour of alarm is
--ALARM TIME
signal savedHours : integer := 0;
signal savedMinutes : integer := 0;
signal incrementDecrementbuttonDetect : std_logic;
signal set_lastButtonState : std_logic := '0';
signal setButtonDetect : std_logic := '0';
--STATE MACHINE
type state_type is (idle, setHour, setMinute);
signal state_reg, state_next : state_type;
begin
incrementDecrementbuttonDetect <= alarm_increment or alarm_decrement;
--STATE REGISTER
process(clock, reset)
begin
if (reset = '1') then
state_reg <= idle;
elsif rising_edge(clock) then
state_reg <= state_next;
end if;
end process;
--SET BUTTON PRESSED
process(clock)
begin
if(rising_edge(clock)) then
if(alarm_set = '1' and set_lastButtonState = '0') then
setButtonDetect <= '1';
else
setButtonDetect <= '0';
end if;
set_lastButtonState <= alarm_set;
end if;
end process;
--NEXT STATE
process(state_reg, setButtonDetect)
begin
case state_reg is
when idle =>
if setButtonDetect = '1' then
state_next <= setHour;
else
state_next <= idle;
end if;
when setHour =>
if setButtonDetect = '1' then
state_next <= setMinute;
else
state_next <= setHour;
end if;
when setMinute =>
if setButtonDetect = '1' then
state_next <= idle;
else
state_next <= setMinute;
end if;
end case;
end process;
process (incrementDecrementbuttonDetect, state_reg)
begin
if rising_edge(incrementDecrementbuttonDetect) then
case state_reg is
when idle =>
when setHour =>
if alarm_increment = '1' then
if savedHours = 23 then
savedHours <= 0;
else
savedHours <= savedHours + 1;
end if;
else null;
end if;
if alarm_decrement = '1' then
if savedHours = 0 then
savedHours <= 23;
else
savedHours <= savedHours - 1;
end if;
else null;
end if;
when setMinute =>
if alarm_increment = '1' then
if savedMinutes = 59 then
savedMinutes <= 0;
else
savedMinutes <= savedMinutes + 1;
end if;
else null;
end if;
if alarm_decrement = '1' then
if savedMinutes = 0 then
savedMinutes <= 59;
else
savedMinutes <= savedMinutes - 1;
end if;
else null;
end if;
end case;
end if;
end process;
alarm_hour1 <= std_logic_vector(to_unsigned(savedHours/10,alarm_hour1'length));
alarm_hour0 <= std_logic_vector(to_unsigned(savedHours mod 10,alarm_hour0'length));
alarm_minute1 <= std_logic_vector(to_unsigned(savedMinutes/10,alarm_minute1'length));
alarm_minute0 <= std_logic_vector(to_unsigned(savedMinutes mod 10,alarm_minute0'length));
--ALARM BUZZER CONDITION
process (currentTime_hour1, currentTime_hour0, currentTime_minute1, currentTime_minute0,
alarm_enable, alarm_hour1, alarm_hour0, alarm_minute1, alarm_minute0)
begin
if((alarm_hour1 = currentTime_hour1) and (alarm_hour0 = currentTime_hour0)
and (alarm_minute1 = currentTime_minute1) and (alarm_minute0 = currentTime_minute0) and alarm_enable = '1') then
alarm_buzzer <= '1';
else
alarm_buzzer <= '0';
end if;
end process;
end alarmBehaviour;
Consider keeping the alarm time in Binary-Coded Decimal (BCD) format instead of binary format, whereby you can compare it directly with the current time, that is provided in BCD format.
This is a good example of how using the appropriate internal data format can reduce the computational problem significantly, since you can simply eliminate the costly division and modulo operations by keeping just one data format (BCD) instead of mixing BCD and binary data formats.
The range of signals savedHours and savedMinutes is not specified, so Quartus assumes they are 32 bits wide. Inference of a divider with one 32-bit operand results into a large tree of conditional subtractions.
Updating your code to something like
--ALARM TIME
signal savedHours : natural range 0 to 23 := 0;
signal savedMinutes : natural range 0 to 59 := 0;
will very likely result into less ALM usage.
Also, please note that rising_edge should be used for clock signals only (at VHDL starter level). Instead of connecting logic to the clock input of a register, what you probably want is some button debounce logic.

VHDL generic case statement

I am trying to instantiate a mux with a generic number of case statements. Currently my code looks like this:
In these examples data_array and selector are inputs, data is the output and the width of the mux is 4.
process(all)
begin
case? selector is
when "1---" => data <= data_array(3);
when "01--" => data <= data_array(2);
when "001-" => data <= data_array(1);
when "0001" => data <= data_array(0);
when others => data <= (others => '-');
end case?;
end process;
Is there a way to have a generic number of case statements? Or is there a similar feature that I could use?
I could solve this using code generation to generate the appropriate number of case statements but I was wondering if there is a VHDL(-2008) feature that I could use to solve this.
I have rewritten the mux to use a for loop but unfortunately my implementation tool is not handling this very well. The logic that is inferred is not optimal and quite bad in terms of timing.
In this example GENERIC_WIDTH is the width of the mux.
process(all)
begin
data_v := (others => '0');
for i in 0 to GENERIC_WIDTH-1 loop
if selector(i) then
data <= data_array(i);
end if;
end loop;
end process;
I am targeting a Xilinx device using Vivado 2017.3. Implementation results show that using the case statement yields more efficient logic (in terms of WNS and logic depth) than using the for loop.
It doesn't matter anymore: modern synthesis tools will correctly optimize all logic. I made a comparison between Vivado 2017.3 outputs. The base entity is
library ieee;
use ieee.std_logic_1164.all;
entity MyMux is
generic(
data_width : positive := 32;
data_depth : positive := 4
);
port(
clk : in std_logic;
data_in : in std_logic_vector(data_width-1 downto 0);
selector : in std_logic_vector(data_depth-1 downto 0);
data_out : out std_logic_vector(data_width-1 downto 0)
);
end entity;
Architecture 1:
architecture rtl of MyMux is
subtype data_type is std_logic_vector(data_width-1 downto 0);
type data_array_type is array (0 to data_depth-1) of data_type;
signal data_array : data_array_type := (others => (others => '0'));
begin
read_data : process(clk) begin
if rising_edge(clk) then
for i in data_depth-1 downto 1 loop
data_array(i) <= data_array(i-1);
end loop;
data_array(0) <= data_in;
end if;
end process;
select_output: process(all) begin
case? selector is
when "1---" => data_out <= data_array(3);
when "01--" => data_out <= data_array(2);
when "001-" => data_out <= data_array(1);
when "0001" => data_out <= data_array(0);
when others => data_out <= (others => '-');
end case?;
end process;
end architecture;
Architecture 2:
architecture rtl of MyMux is
subtype data_type is std_logic_vector(data_width-1 downto 0);
type data_array_type is array (0 to data_depth-1) of data_type;
signal data_array : data_array_type := (others => (others => '0'));
begin
read_data : process(clk) begin
if rising_edge(clk) then
for i in data_depth-1 downto 1 loop
data_array(i) <= data_array(i-1);
end loop;
data_array(0) <= data_in;
end if;
end process;
select_output: process(all) begin
data_out <= (others => '-');
for i in 0 to data_depth-1 loop
if selector(i) then
data_out <= data_array(i);
end if;
end loop;
end process;
end architecture;
Architecture 3:
architecture rtl of MyMux is
subtype data_type is std_logic_vector(data_width-1 downto 0);
type data_array_type is array (0 to data_depth-1) of data_type;
signal data_array : data_array_type := (others => (others => '0'));
function my_mux(
selector : std_logic_vector(data_depth-1 downto 0);
data_array : data_array_type) return data_type is
variable data : data_type;
begin
data := (others => '-');
for i in 0 to data_depth-1 loop
if selector(i)='1' then
data := data_array(i);
end if;
end loop;
return data;
end function;
begin
read_data : process(clk) begin
if rising_edge(clk) then
for i in data_depth-1 downto 1 loop
data_array(i) <= data_array(i-1);
end loop;
data_array(0) <= data_in;
end if;
end process;
data_out <= my_mux(selector, data_array);
end architecture;
Output:
Architecture 1: 32 LUT3, 32 LUT6, 128 FDRE
Architecture 2: 32 LUT3, 32 LUT5, 128 FDRE
Architecture 3: 32 LUT3, 32 LUT5, 128 FDRE
So they are all practically the same.
The problem is you case seems to be the non deterministic component: initial placement randomization. In my experience this initial placement is based on some randomizer seed extracted from the hash of the code. The same code will always give the same implementation. But make a very small change in the code, and timing and resource use might be completely different.
You should take note that the logic you describe in you code will implement as a chain of multiplexers. When the GENERIC_WIDTH increases, so will the delay. This is inevitable.

resetting values in a VHDL register and stop writing further

I have simple register and getting single bit values from 5 state machines (all at one time). These values are stored in a register as std_logic_vector and has to be given as an input to another module. Once the output of this register is being processed in another module, the index in the register where there was a change (e,g 0 to 1), the value at that index should reset (e,g 1 to 0) and it should take no further input for that particular index (but there is constant input coming from state machines). Any suggestion, how it should be done?
The register code is:
entity fault_reg is
port (
clk : in std_logic;
rst : in std_logic;
reg_in : in std_logic_vector(NUM_PORTS - 1 downto 0);
reg_out : out std_logic_vector(NUM_PORTS - 1 downto 0));
end fault_reg;
architecture Behavioral of fault_reg is
begin
reg_impl : process(clk, rst)
begin
if rst = '1' then
reg_out <= (others => '0');
elsif clk'event and clk='1' then
reg_out <= reg_in;
end if;
end process reg_impl;
end Behavioral;
I'm not entirely sure what you are asking, but it seems to me you want something like:
initialise your reg_out to all ones
then in the clocked process do a for loop to iterate over all the input bits and clear the bits which are set in the input
Like this:
reg_out <= reg_in;
for i in reg_in'range loop
if reg_in(i) = '1' then
masked_bits(i) := '1';
end if;
if masked_bits(i) = '1' then
reg_out(i) <= '0';
end if;
end loop;

Cannot Synthesize Signal

I am a newbie when it comes to VHDL, but i am working on a counter than can manually count up and down by the push of a button.. Somehow i am only getting this error, and i dunno what i am doing wrong, all other checks are good. any suggestion?
This is the error i get:
ERROR:Xst:827 - line 101: Signal s2 cannot be synthesized, bad synchronous description.
The description style you are using to describe a synchronous element (register, memory, etc.) is not supported in the current software release.
entity updown is Port (
rst : in STD_LOGIC;
plus , plusin: in STD_LOGIC;
minus, minusin : in STD_LOGIC;
clk : in STD_LOGIC;
ud_out, ud_out2 : out STD_LOGIC_VECTOR (3 downto 0)
);
end updown;
architecture Behavioral of updown is
signal s : unsigned (3 downto 0):= "0000";
signal s2 : unsigned (3 downto 0) := "0000";
begin
process(rst, plus, minus, clk, plusin, minusin)
begin
if rst='1' then
s <= "0000";
s2 <= "0000";
else
if rising_edge (clk) then
if plus ='1' or plusin = '1' then
if s = "1001" then
s <= "0000";
if s2 = "1001" then
s2 <= "0000";
else
s2 <= s2 + 1;
end if;
else
s <= s + 1;
end if;
end if;
else
if minus ='1' or minusin = '1' then
if s = "0000" then
s <= "1001";
if s2= "0000" then
s2 <= "1001";
else
s2 <= s2 - 1;
end if;
else
s <= s - 1;
end if;
end if;
end if;
end if;
end process;
ud_out <= std_logic_vector(s);
ud_out2 <= std_logic_vector(s2);
end Behavioral;
Your description of a synchronous process is flawed. A synchronous process has events that update only on the edge of a clock signal (although in this case there is an also an asynchronous reset behaviour )
Your sensitivity list contains more than it needs to describe a synchronous process.
Replace
process(rst, plus, minus, clk, plusin, minusin)
with
process(rst, clk )
signals will then only update when the clock transisitions, or rst changes.
Some compilers are even more picky, and might require you to change
else if rising_edge (clk)then
to
elsif rising_edge(clk) then
EDIT:
This should work. I've layed it out clearly so its actually easy to follow what's going on. I'd suggest you do the same in future. It make simple closure errors easy to spot
entity updown is
port (
signal clk : in std_logic;
signal rst : in std_logic;
signal plus : in std_logic;
signal plusin : in std_logic;
signal minus : in std_logic;
signal minusin : in std_logic;
signal ud_out : out std_logic_vector(3 downto 0);
signal ud_out2 : out std_logic_vector(3 downto 0)
);
end entity updown;
architecture behavioral of updown is
signal s : unsigned (3 downto 0);
signal s2 : unsigned (3 downto 0);
begin
p_counter_process: process(rst, clk)
begin
if rst ='1' then
s <= (others => '0');
s2 <= (others => '0');
elsif rising_edge(clk) then
if plus ='1' or plusin = '1' then
if s = "1001" then
s <= "0000";
if s2 = "1001" then
s2 <= "0000";
else
s2 <= s2 + 1;
end if;
else
s <= s +1;
end if;
end if;
-- you had a mismatched end if statement here. Removed
if minus ='1' or minusin = '1' then
if s = "0000" then
s <= "1001";
if s2= "0000" then
s2 <= "1001";
else
s2 <= s2 - 1;
end if;
else
s <= s - 1;
end if;
end if;
end if;
end process;
ud_out <= std_logic_vector(s);
ud_out2 <= std_logic_vector(s2);
end architecture;

1Hz clock for a D FlipFlop VHDL

I am trying to implement a 1hz clock for a D flipflop in VHDL.
Below is my code:
entity d_flip_flop is
Port ( clk : in STD_LOGIC;
D : in STD_LOGIC;
Q : out STD_LOGIC);
end d_flip_flop;
architecture Behavioral of d_flip_flop is
signal clk_div: std_logic; --divided clock
begin
--process to divide clock
clk_divider: process(clk) --clk is the clock port
variable clk_count: std_logic_vector(25 downto 0) := (others => '0');
begin
if clk'event and clk = '1' then
clk_count <= clk_count+1;
clk_div <= clk_count(25);
end if;
end process;
--main process
main:process(clk_div)
begin
if clk'event and clk = '1' then
Q <= D;
end if;
end process;
end Behavioral;
But when I tried to compile it, the following error is reported:
ERROR:HDLParsers:808 - "F:/EE4218/XQ/d_flip_flop.vhd" Line 47. + can
not have such operands in this context.
I have checked with several reference for the syntax and found nothing wrong with it. Can anyone point out the cause of the error ?
Thanks in advance!
clk_count is being used to represent a number, not a bag of bits.
So use the type system instead of fighting it, and declare it as a number or at least some numeric type.
The best tool for this purpose, since you need to extract a bit from it, is numeric_std.unsigned.
So add use ieee.numeric_std.all;after the library ieee; clause, declare it as
variable clk_count: unsigned(25 downto 0) := (others => '0');
and you are done.
Brian has the best answer, for powers-of-two anyway. Arguably, for other wrap around values, you should also use an integer for clock_count and wrap it:
signal clk_div : std_logic := '0';
clk_divider: process(clk) --clk is the clock port
subtype t_clk_count: integer range 0 to 12345678; -- for example
variable clk_count: t_clk_count := 0;
begin
if clk'event and clk = '1' then
if clk_count+1 >= t_clk_count'high then
clk_div <= not clk_div;
clk_count <= 0;
else
clk_count <= clk_count+1;
end if;
end if;
end process;
In process clk_divider modify the following line:
clk_count <= clk_count +1;
to
clk_count := std_logic_vector(UNSIGNED(clk_count) + 1);
This is because clk_count is defined as a variable of type 'std_logic_vector'.

Resources