I want to use generate statement but in my code I have a case statements which only takes sequential statements.
Then I thought I will use it in a package where I can define a function such that there also I am getting error as : 'Illegal Sequential statement'.
So what can be done. Any suggestions?
Code block:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE work.my_package.all;
-- Entity for ALU component
-- Use this Entity for your C&A project
ENTITY ALU_E IS
PORT(
reset_n : in std_logic;
clk : in std_logic;
OperandA : in std_logic_vector(3 downto 0);
OperandB : in std_logic_vector(3 downto 0);
Operation : in std_logic_vector(2 downto 0);
Start : in std_logic;
Result_Low : out std_logic_vector(3 downto 0);
Result_High : out std_logic_vector(3 downto 0);
Ready : out std_logic;
Errorsig : out std_Logic);
END ALU_E;
architecture Behavioral_ALU of ALU_E is
signal c : std_logic_vector(7 downto 0);
signal carry_internal :std_logic_vector(4 downto 0);
COMPONENT fulladder IS
PORT(
a: IN std_logic;
b: IN std_logic;
cin : IN std_logic;
cout: OUT std_logic;
s: OUT std_logic );
END component fulladder;
begin
adders: for N in 0 to 3 generate
ff1:fulladder
port map
(a => OperandA(N),b => OperandB(N),cin => carry_internal(N),cout => carry_internal(N+1),s => c(N));
end generate adders;
c(4) <= carry_internal(4);
process(clk,reset_n)
begin
if reset_n = '0' then
if (clk'event) then
case Operation is
when "000" => --no operation
NULL;
when "001" => --Rotate left logical operator ?0000?&A by B steps
c <= rotlef (OperandA,OperandB);
when "010" => --Rotate right logical operator ?0000?&A by B steps (result width is 8 bit)
c <= rotrig (OperandA,OperandB);
when "011" => --Bitwise XOR operation
Result_Low <= OperandA xor OperandB;
when "100" => --Sum of A and B
--here i want to use a statement such that i can call the gatelevel --add function
--I have already all functions gatelevel defined when i try to use portmap or ----generate it gives an error illegal sequential statement
when Others =>
NULL;
end case;
end if;
end if;
end process;
end Behavioral_ALU;
There are a couple of misconceptions in the question.
First the title : there is no function in your actual code. What you have done with the for ... generate statement is generate a separate piece of hardware, operating in parallel with the main process. It will always operate, and always drive signal 'c' with the sum, as if you had written c <= a + b; in place of the for ... generate. It's always, continuously working, not a function you can call only when you want to.
Second, that means that both the adder and the clocked process drive c all the time, with different values. This will not go well... in fact you should see "XXXX" on signal c in simulation.
What I think you want to do is create a new signal, called sum for the adder's output, and drive sum, not c, in the for ... generate. Then, in the Case statement, assigning sum to c will accomplish the Add operation.
As far as why you get the error messages you do, a component instantiation statement or generate statement is a concurrent statement, while a case choice or a function body is comprised of sequential statements.
You don't need a function, you need the sum and carry out from the generate statement instantiated four fulladders.
o
Dummy up an entity/architecture pair for fulladder:
library ieee;
use ieee.std_logic_1164.all;
entity fulladder is
port (
a: in std_logic;
b: in std_logic;
cin: in std_logic;
cout: out std_logic;
s: out std_logic
);
end entity;
architecture foo of fulladder is
begin
s <= a xor b xor cin;
cout <= (a and b) or (a and cin) or (b and cin);
end architecture;
Dummy up a non functional my_package:
library ieee;
use ieee.std_logic_1164.all;
package my_package is
function rotlef (a, b: std_logic_vector) return std_logic_vector;
function rotrig (a, b: std_logic_vector) return std_logic_vector;
end package;
package body my_package is
function rotlef (a, b: std_logic_vector) return std_logic_vector is
variable ret_val: std_logic_vector (a'range);
begin
return ret_val;
end function;
function rotrig (a, b: std_logic_vector) return std_logic_vector is
variable ret_val: std_logic_vector (a'range);
begin
return ret_val;
end function;
end package body;
(note the function return value lengths match the left operand length)
Add a new declaration for the output of the generated fulladders:
architecture changed of alu_e is
signal c: std_logic_vector(7 downto 0);
signal carry_internal: std_logic_vector(4 downto 0);
signal s: std_logic_vector(3 downto 0); -- added
Change the generate statement to use the new signal for the sum:
adders:
for n in 0 to 3 generate
ff1:
fulladder
port map (
a => operanda(n),
b => operandb(n),
cin => carry_internal(n),
cout => carry_internal(n+1),
s => s(n) -- was c(n)
);
end generate;
-- c(4) <= carry_internal(4);
(eliminating the assignment to c(4))
And change the sequence of statements for choice "100":
when "100" => --sum of a and b
result_low <= s; -- added
result_high(0) <= carry_internal(4); --(un)signed?
And your design analyzes, elaborates and simulates (while not doing much - no assignments in the process for case others when operation is undriven and all Us, I didn't write a testbench to drive operation or provide it with a default value).
Notice the declaration of c has a length of 8 while the return value of the two functions will match their a input (length 4).
If you were to execute the dummy functions for operations "001" or "010" you'd get a simulation error due to length mismatch on the right hand side. I left this as is with no insight in to whether or not your rotlef or rotrig functions actually return a longer length.
In general you only want an 8 bit result for multiplies. The length of c and how it get's assigned to result_low and result_high aren't apparent (as yet).
It wasn't possible to discern whether you're doing signed or unsigned arithmetic without more detail. Instead of:
result_high(0) <= carry_internal(4); --(un)signed?
A signed sign extension could look like:
result_high <= (others => carry_internal(4)); --sign extended
Note that when you instantiate your multiplier you'd also want to use a new signal declaration for the 8 bit result. Modifying your rotate operations to assign result_low and result_high would allow c to be used for an instantiated multiply, although you might choose to rename it.
Think of the case statement in the process statement as instantiating a multiplexer, and in some cases you happen to be also expressing logic on inputs. The xor or the sign extension or function calls (which are expressions) are examples.
When you have instantiated components providing function you want to connect their output to a multiplexer input.
Related
I have a vector that has a configurable size like
signal a_vector : std_logic_vector(size-1 downto 0);
where size is defined in a configuration file. What I now would like to do is to OR all elements of a_vector into a separate std_logic in a way like
signal result : std_logic;
result <= a_vector(0) or a_vector(1) or ... or a_vector(size-1)
Is there a way to do this with a GENERATE statement, I couldn't figure that out.
scary_jeff's answer works like a charm for the given problem. Is there a similar way if I'd have
type byte_array is array (0 to size) of std_logic_vector(7 downto 0);
signal a_vector : byte_array;
and I'd like to have
result <= a_vector(0)(1) or a_vector(1)(1) or ... or a_vector(size-1)(1);
If you're using VHDL2008 or later, which has 'reductive' and and or functions built in, you can simply write result <= or(a_vector); or result <= or a_vector;.
If not, you can use a for loop (not a generate loop). You could put this loop in a function if you wanted.
function reductive_or (a_vector : std_logic_vector) return std_logic is
variable r : std_logic := '0';
begin
for i in a_vector`range loop
r := r or a_vector(i);
end loop;
return r;
end function;
The lines:
type some_array_type is array (0 to 4, 0 to 4) of unsigned(7 downto 0);
signal some_array : some_array_type := (others=>(others=>'0'));
cause vivado 2018.2 to throw the error:
[Synth 8-1807] character '0' is not in type unresolved_unsigned
for some reason in a VHDL 2008 file. What it the magical syntax to get Vivado to realize that I'm just trying to initialize the array to zeros? I shouldn't have to write a function to do this. I also tried unsigned((others=>(others=>'0')));
The code below can of course be ignored and isn't needed for anything at all. It is just there for the OCD people. "You have to always include a minimal working example!"
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity some_entity is
port (
clk, rst: in std_logic ;
);
end some_entity ;
architecture arch of some_entity is
type some_array_type is array (0 to 4, 0 to 4) of unsigned(7 downto 0);
-- throws error
signal some_array : some_array_type := (others=>(others=>'0'));
type some_other_array_type is array (natural range <>) of std_logic_vector(7 downto 0);
-- doesn't throw error
signal some_other_array : some_other_array_type(0 to 4) := (others=>(others=>'0'));
begin
-- some made up process
process(clk, rst)
begin
if(rising_edge(clk)) then
if rst = '1' then
some_array <= (others=>(others=>'0'));
else
some_array <= (others=>(others=>'1'));
end if;
end if;
end process;
end arch;
I want to pass a value from one vector to another.
Can I simply do it this way?
vector_one : out STD_LOGIC_VECTOR (3 downto 0);
vector_two : out STD_LOGIC_VECTOR (3 downto 0);
vector_one <= vector_two;
The vector_one is an output port (mode out), and reading this is allowed in VHDL-2008, so you can do:
vector_one <= vector_two;
However, in VHDL-2002 it is not allowed to read an output port, so you must drive both outputz from the source, say vector_source, like:
vector_one <= vector_source;
vector_two <= vector_source;
Generally, it should be avoided to duplicate an output signal like that, since it is not obvious from the use of that module that some output are driven with identical values, which makes it harder to understand the module use.
you can but you need to take note that if you will need to use vector_one in your module before it gets used outside meaning that the module will need to hold information about it. Then you will need to declare an internal signal in order to work on it.
example:
entity exampleModule is
port( iClk : in STD_LOGIC;
iTrigger : in STD_LOGIC;
iVector_one : out STD_LOGIC_VECTOR (3 downto 0);
oVector_two : out STD_LOGIC_VECTOR (3 downto 0));
end exampleModule ;
Architecture RTL of exampleModule is
signal mVectorBuff : std_logic_vector (3 downto 0);
begin
process (iClk) begin
if rising_edge (iClk) then
if iTrigger then mVectorBuff <= iVector_one;
end if;
end if;
end process;
oVector_two <= mVector_one;
end Architecture RTL;
I'm starting a big project in VHDL and I would like to have every basic components (adders, multiplexers, registers, ...) written such that they are as most ordered as possible.
I'm thinking to use different architectures for each entity (to go through different layer of abstraction or different kind of implementation) and then select one using configurations.
My question is: is it possible to recursively self-instantiate a component but with a different configuration?
For example, let's take the adder:
entity ADDER is
generic( ... );
port( ... );
end entity ADDER;
Then I would like to have different kind of architecture, for example:
-- Behavioral Add
architecture BHV of ADDER is
out <= A + B;
end architecture BHV;
-- Ripple Carry Adder
architecture RCA of ADDER is
...
end architecture RCA;
-- Carry Select Adder
architecture CSA of ADDER is
component ADDER -- <== this should be configured as RCA
...
end architecture CSA;
Is it possible to configure the adder used inside the Carry Select with a Ripple Carry without ending in an infinite instantiation loop?
Yes, it is possible to configure the adder used inside the Carry Select with a Ripple Carry without ending in an infinite instantiation loop. With recursive instantiation a termination condition is required - something that terminates the recursion. The configuration is carrying out that role.
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity ADDER is
generic( WIDTH : positive := 8 );
port( CIN : in std_logic;
A : in std_logic_vector(WIDTH-1 downto 0);
B : in std_logic_vector(WIDTH-1 downto 0);
F : out std_logic_vector(WIDTH-1 downto 0);
COUT : out std_logic);
end entity ADDER;
-- Ripple Carry Adder
architecture RCA of ADDER is
signal CIN0 : unsigned(0 downto 0);
signal FIN : unsigned(WIDTH downto 0);
begin
CIN0(0) <= CIN;
FIN <= resize(unsigned(A), WIDTH+1) + resize(unsigned(B), WIDTH+1) + CIN0; -- yes, I know it's not a ripple carry adder
F <= std_logic_vector(FIN(WIDTH-1 downto 0));
COUT <= FIN(WIDTH);
end architecture RCA;
-- Carry Select Adder
architecture CSA of ADDER is
component ADDER is
generic( WIDTH : positive );
port( CIN : in std_logic;
A : in std_logic_vector(WIDTH-1 downto 0);
B : in std_logic_vector(WIDTH-1 downto 0);
F : out std_logic_vector(WIDTH-1 downto 0);
COUT : out std_logic);
end component ADDER;
signal F0, F1 : std_logic_vector(WIDTH-1 downto 0);
signal COUT0, COUT1 : std_logic;
begin
ADD0: ADDER generic map( WIDTH => WIDTH)
port map (
CIN => '0' ,
A => A ,
B => B ,
F => F0 ,
COUT => COUT0 );
ADD1: ADDER generic map( WIDTH => WIDTH)
port map (
CIN => '1' ,
A => A ,
B => B ,
F => F1 ,
COUT => COUT1 );
COUT <= COUT1 when CIN = '1' else COUT0;
F <= F1 when CIN = '1' else F0;
end architecture CSA;
-- here's the configuration
configuration CSAC of ADDER is
for CSA
for all: ADDER
use entity work.ADDER(RCA);
end for;
end for;
end configuration CSAC;
http://www.edaplayground.com/x/2Yu3
Here is a design for 4-bit asynchronous ripple counter (using T flip flop however I didn't define a component for Tff and just coded the behavior of circuit regarding T signals).
Following are the questions:
1.) inout ports, I first defined Q as inout (since it's obviously my output and the bits are also used as clk inputs to their following flip flops). Still, when I wanted to simulate my code, the Q output was UUUU which makes sense cause I had to initialize it with the number I wanted my count to begin with. Though I didn't know how to set an inout initial value (I tried Process ... Q <= "0000"; wait; end process but it didn't work)!
2.) In order to solve the above-mentioned problem I changed my inout port to out (Q_out) and defined Q as a signal, this worked BUT...my counter only changed the Q(0) bit and not the others...thus it counts like: 0,1,0,1,0,1,...
3.) I want to debug this code. I tried another style, instead of a 4-bit output I defined 4 1-bit output signals (Q_out1 to Q_out2) in addition to 4 internal signals Q0 to Q1 and this perfectly works
I just want to know why the first style (Q as a 4_bit vector) didn't work out.
thanks in advance for your help.
Here is my code and its test bench:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity four_bit_Asynch_Counter is
Port ( T0,T1,T2,T3 : in STD_LOGIC;
clk : in STD_LOGIC;
Q_out: out STD_LOGIC_VECTOR (3 downto 0));
end four_bit_Asynch_Counter;
architecture Behavioral of four_bit_Asynch_Counter is
signal Q : STD_LOGIC_VECTOR (3 downto 0) := "0000";
begin
Process (clk,Q(0),Q(1),Q(2))
begin
if (falling_edge(clk)) then
if (T0 = '1') then
Q(0) <= not Q(0);
else
Q(0) <= Q(0);
end if;
end if;
if (falling_edge(Q(0))) then
if (T1 = '1') then
Q(1) <= not Q(1);
else
Q(1) <= Q(1);
end if;
end if;
if (falling_edge(Q(1))) then
if (T2 = '1') then
Q(2) <= not Q(2);
else
Q(2) <= Q(2);
end if;
end if;
if (falling_edge(Q(2))) then
if (T3 = '1') then
Q(3) <= not Q(3);
else
Q(3) <= Q(3);
end if;
end if;
Q_out <= Q;
end Process;
end Behavioral;
--------------- Test Bench------------
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY tb_counter IS
END tb_counter;
ARCHITECTURE behavior OF tb_counter IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT four_bit_Asynch_Counter
PORT(
T0 : IN std_logic;
T1 : IN std_logic;
T2 : IN std_logic;
T3 : IN std_logic;
clk : IN std_logic;
Q_out : OUT std_logic_vector(3 downto 0)
);
END COMPONENT;
--Inputs
signal T0 : std_logic := '1';
signal T1 : std_logic := '1';
signal T2 : std_logic := '1';
signal T3 : std_logic := '1';
signal clk : std_logic := '0';
--Outputs
signal Q_out : std_logic_vector(3 downto 0);
-- Clock period definitions
constant clk_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: four_bit_Asynch_Counter PORT MAP (
T0 => T0,
T1 => T1,
T2 => T2,
T3 => T3,
clk => clk,
Q_out => Q_out
);
-- Clock process definitions
clk_process :process
begin
clk <= '0';
wait for clk_period/2;
clk <= '1';
wait for clk_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for 100 ns;
wait for clk_period*10;
-- insert stimulus here
wait;
end process;
END;
The TL;DR answer is that q(3) doesn't show up in your process sensitivity list.
architecture behavioral of four_bit_asynch_counter is
signal q: std_logic_vector (3 downto 0) := "0000";
begin
process (clk, q(0), q(1), q(2))
begin
if falling_edge(clk) then
if t0 = '1' then
q(0) <= not q(0);
-- else
-- q(0) <= q(0);
end if;
end if;
if falling_edge(q(0)) then
if t1 = '1' then
q(1) <= not q(1);
-- else
-- q(1) <= q(1);
end if;
end if;
if falling_edge(q(1)) then
if t2 = '1' then
q(2) <= not q(2);
-- else
-- q(2) <= q(2);
end if;
end if;
if falling_edge(q(2)) then
if t3 = '1' then
q(3) <= not q(3);
-- else
-- q(3) <= q(3);
end if;
end if;
q_out <= q;
end process;
end architecture behavioral;
For your process sensitivity list you've discovered a feature in how the sensitivity list is constructed from the expression consisting of primaries - clk, q(0), q(1), q(2).
From IEEE Std 1076 -1993, 8.1 Wait statement:
...
The sensitivity set is initially empty. For each primary in the condition of the condition clause, if the primary is
-- A simple name that denotes a signal, add the longest static prefix of the name to the sensitivity set
-- A selected name whose prefix denotes a signal, add the longest static prefix of the name to the sensitivity set
-- An expanded name whose prefix denotes a signal, add the longest static prefix of the name to the sensitivity set
-- An indexed name whose prefix denotes a signal, add the longest static prefix of the name to the sensitivity set and apply this rule to all expressions in the indexed name
...
...
This rule is also used to construct the sensitivity sets of the wait statements in the equivalent process statements for concurrent procedure call statements( 9.3 ), concurrent assertion statements ( 9.4 ), and concurrent signal assignment statements ( 9.5 ).
If a signal name that denotes a signal of a composite type appears in a sensitivity list, the effect is as if the name of each scalar subelement of that signal appears in the list.
...
I only included elements of the rule that are of interest here, the first covers the clock the last element shown covers the std_logic_vector elements specified by selected names.
It helps to understand what is meant by the longest static prefix. This explained in -1993 6.1 Names.
The primaries (indexed names) are static names (q(0), q(1), q(2)), every expression that's part of each indexed name is static.
This means the longest static prefix is the indexed name comprising each primary.
And this leaves q(3) dangling in the breeze for the process signal assignment statement:
q_out <= q;
Without sensitivity to q(3) the value of q_out is not updated until the next event in the sensitivity list, which happens to be on clk:
There are two ways to cure this, you could move the q_out assignment outside the process statement, where it becomes a concurrent signal assignment (with an elaborated equivalent process with a sensitivity list set to q), or you can change the sensitivity list in the present process:
process (clk, q)
So that q_out is updated for an event on q(3) (noting the last quoted paragraph in 8.1 above).
This behavior hold true for later revisions of the standard as well.
With the process sensitivity list is fixed:
Your counter behaves properly.
Also note I commented out the redundant else assignments to the q(0), q(1), q(2) and q(3) a signal will hold it's value until assigned and these are sequential (clocked) statements. Also eliminated the redundant parentheses pairs.
When implementing counters in realisable hardware (either ASIC or FPGA) you should never use a ripple counter. By using the flip-flop output as a clock to the next you will have sub-optimal timing, the tools will not be able to accurately validate the setup and hold times and you are not able to take advantage of dedicated clock routing. In general asynchronous design is a bad idea for real implementations.
A true synchronous design will be much better for synthesis and is much easier to infer in the VHDL code.
Examples of Counter implementations
See the above link for both verilog and vhdl examples of counter implementation.