Suppose one has an entity which has two architectures defined. Those two architectures work with the same entity (obviously) and subsequently the two set the output pins to different values. My question is, how does the program (simulator) determine what the output should be (i.e. which architecture to choose)?
Here is an example:
library ieee;
use ieee.std_logic_1164.all;
entity Exercise_4 is
generic (n : integer := 4);
port(
a, b : std_logic_vector (n-1 downto 0);
clk, rst : std_logic;
q, qn : buffer std_logic_vector (n-1 downto 0));
end;
architecture one of Exercise_4 is
begin
process (clk, rst)
begin
if rst = '0' then
q <= (others=>'0');
elsif (clk' event and clk = '0') then
q <= a ;
end if;
end process;
process (clk, rst)
begin
if rst = '0' then
qn <= (others=>'1');
elsif (clk' event and clk = '0') then
for i in a'range loop
qn(i) <= not q(i) ;
end loop;
end if;
end process;
end;
architecture two of Exercise_4 is
begin
process (clk,rst)
begin
if rst = '0' then
q <= (others=>'0');
qn <= (others=>'0');
elsif (clk' event and clk = '0') then
q <= a;
qn <= b ;
end if;
end process;
end;
I did a simulation and saw that q gets the value of a assigned and qn gets the value of b assigned. It seems that the second architecture has been chosen by the compiler I don't understand why the program decided to do so.
Thank you.
If you don't specify yourself which architecture to choose² then the compiler will take "the most recently analyzed architecture body associated with the entity declaration" (assuming the compiler is compliant to the IEEE standard) [1].
² You can select the architecture you prefer e.g. in the component declaration section (where you map the signals) on a higher design level:
entity topentity is
end;
architecture toparch of topentity is
-- component instantiation
component Exercise_4 is
generic (n : integer := 4);
port(
a, b : std_logic_vector (n-1 downto 0);
clk, rst : std_logic;
q, qn : buffer std_logic_vector (n-1 downto 0));
end component Exercise_4;
begin
-- component mapping
E4: entity work.Exercise_4(one)
generic map ( .. )
port( .. );
end architecture toparch;
[1] IEEE Std 1076-2008 7.3.3 Default binding indication, paragraph 4.
Disclaimer: Answer was constructed with the help of the comments above. No copyright infringement intended. ;P
In absence of configuration binding, by default the compiler consider the last architecture body in the code file.
Related
Let's assume I have two processes PROC_A and PROC_B, and they share a signal between them. Let me write a dummy example:
library ieee;
use ieee.std_logic_1164.all;
entity example is
port (
clk : in std_logic;
rst_n : in std_logic;
a : in std_logic;
b : in std_logic;
c : in std_logic;
z_out : out std_logic);
end entity example;
architecture rtl of example is
signal a_and_b : std_logic;
signal ab_xor_c : std_logic;
begin -- architecture rtl
z_out <= ab_xor_c;
PROC_A : process (clk, rst_n) is
begin -- process PROC_A
if rst_n = '0' then -- asynchronous reset (active low)
a_and_b <= '0';
elsif rising_edge(clk) then -- rising clock edge
a_and_b <= a and b;
end if;
end process PROC_A;
PROC_B : process (clk, rst_n) is
begin -- process PROC_B
if rst_n = '0' then -- asynchronous reset (active low)
ab_xor_c <= '0';
elsif rising_edge(clk) then -- rising clock edge
ab_xor_c <= a_and_b xor c;
end if;
end process PROC_B;
end architecture rtl;
Now, I want to have a pipeline register between a_and_b and ab_xor_c signals, and I want to hardcode it but also enable/disable it with ease. I really want something like a ifdef in C/C++. I could think of a generic to do that but I am also open to any other method (maybe with pragmas?). I am writing an example below, I know that it is so wrong in terms of VHDL but just see it as an idea:
library ieee;
use ieee.std_logic_1164.all;
entity example is
generic (
PIPELINE_EN : std_logic := '1');
port (
clk : in std_logic;
rst_n : in std_logic;
a : in std_logic;
b : in std_logic;
c : in std_logic;
z_out : out std_logic);
end entity example;
architecture rtl of example is
signal a_and_b : std_logic;
signal ab_xor_c : std_logic;
if PIPELINE_EN = '1' then
signal pipeline_reg : std_logic;
end if;
begin -- architecture rtl
z_out <= ab_xor_c;
PROC_A : process (clk, rst_n) is
begin -- process PROC_A
if rst_n = '0' then -- asynchronous reset (active low)
a_and_b <= '0';
elsif rising_edge(clk) then -- rising clock edge
a_and_b <= a and b;
end if;
end process PROC_A;
PROC_B : process (clk, rst_n) is
begin -- process PROC_B
if rst_n = '0' then -- asynchronous reset (active low)
ab_xor_c <= '0';
if PIPELINE_EN = '1' then
pipeline_reg <= '0'
end if;
elsif rising_edge(clk) then -- rising clock edge
if PIPELINE_EN = '1' then
pipeline_reg <= a_and_b;
ab_xor_c <= pipeline_reg xor c;
else
ab_xor_c <= a_and_b xor c;
end if;
end if;
end process PROC_B;
end architecture rtl;
Your example has been modified to removed the register from process A and show a generic controlling the presence of the register. Additional pipeline registers could be added generically as well.
library ieee;
use ieee.std_logic_1164.all;
entity example is
generic ( PIPELINED: BOOLEAN := TRUE);
port (
clk: in std_logic;
rst_n: in std_logic;
a: in std_logic;
b: in std_logic;
c: in std_logic;
z_out: out std_logic
);
end entity example;
architecture genericly_pipelined of example is
signal a_and_b: std_logic;
signal ab_xor_c: std_logic;
begin
NO_PIPELINE:
if not PIPELINED generate
PROC_A:
process (a, b) is
begin
a_and_b <= a and b; -- could be a concurrent statement instead
end process;
end generate;
GEN_PIPELINED:
if PIPELINED generate
PIPELINED_PROC_A:
process (clk, rst_n) is
begin
if rst_n = '0' then
a_and_b <= '0';
elsif rising_edge(clk) then
a_and_b <= a and b;
end if;
end process;
end generate;
PROC_B:
process (clk, rst_n) is
begin
if rst_n = '0' then
ab_xor_c <= '0';
elsif rising_edge(clk) then
ab_xor_c <= a_and_b xor c;
end if;
end process;
end architecture genericly_pipelined;
The granularity using a generate statement is to a concurrent statement. For purposes of changing signal names you can declare intermediary signals in the block statement elaborated by the generate statement's block declarative region. Generate statements can be nested (it's a concurrent statement) which can be used to add more pipeline registers.
A generate statement body can have a block declarative part prior to any concurrent statements in the block statement body. Concurrent statements are delineated by the reserved words begin and end followed by a semicolon when any declarations are present in the block declarative part. E.g. IEEE Std 10786-2008:
11.8 Generate statements
if_generate_statement ::=
generate_label :
if [ alternative_label : ] condition generate
generate_statement_body
{ elsif [ alternative_label : ] condition generate
generate_statement_body }
[ else [ alternative_label : ] generate
generate_statement_body ]
end generate [ generate_label ] ;
generate_statement_body ::=
[ block_declarative_part
begin ]
{ concurrent_statement }
[ end [ alternative_label ] ; ]
The generate statements in the above VHDL code have no declarations. Braces { } enclosing the item concurrent_statement indicate you can use the 'long form' with the begin and end reserved words with zero or more concurrent statements. You'd declare any intermediary signals used to communicate between statements found in different generate statements in the same design hierarchy. (The block statement elaborated by a generate statement is a separate declarative region.)
The BNF found in the standard's numbered sections is normative.
Note you didn't assign z_out.
Here's an example compatible with the OP's code:
library ieee;
use ieee.std_logic_1164.all;
entity example1 is
generic ( PIPELINES: natural := 1);
port (
clk: in std_logic;
rst_n: in std_logic;
a: in std_logic;
b: in std_logic;
c: in std_logic;
z_out: out std_logic
);
end entity example1;
architecture generic_pipeline_stages of example1 is
signal a_and_b: std_logic;
signal ab_xor_c: std_logic;
begin
NO_PIPELINE:
if PIPELINES = 0 generate
PROC_A:
process (a, b) is
begin
a_and_b <= a and b; -- could be a concurrent statement instead
end process;
end generate;
GEN_PIPELINED:
if PIPELINES > 0 generate
type pipeline is array (0 to PIPELINES - 1) of std_logic;
signal pipeline_reg: pipeline;
begin
PIPELINED_PROC_A:
process (clk, rst_n) is
begin
if rst_n = '0' then
pipeline_reg <= (others => '0');
elsif rising_edge(clk) then
for i in pipeline'range loop
if i = 0 then
pipeline_reg(i) <= a and b;
else
pipeline_reg(i) <= pipeline_reg(i - 1);
end if;
end loop;
end if;
end process;
a_and_b <= pipeline_reg(PIPELINES - 1); -- a separate process
end generate;
PROC_B:
process (clk, rst_n) is
begin
if rst_n = '0' then
ab_xor_c <= '0';
elsif rising_edge(clk) then
ab_xor_c <= a_and_b xor c;
end if;
end process;
end architecture generic_pipeline_stages;
which produces:
And shows the two clock delays using natural generic PIPELINES.
With PIPELINES = 1:
The signals a_and_b and a_xor_b show up one clock earlier. It's compatible with the first VHDL example in this answer with PIPELINED = TRUE.
Note the block declarative part contains a composite signal declaration for the pipeline stages. A generate statement is it's own declarative region which means pipeline_reg wouldn't be visible outside the elaborated block. To access intermediary pipeline stages you'd either move the pipeline_reg declaration to the top level (example1, here) or assign signals declared in the top level assigned in the generate statement.
Principles in the design you wrote are fine, except for the if PIPELINE_EN = '1' then part in the declaration of pipeline_reg, which should be skipped, since the synthesis will then just remove the unused pipeline_reg. Also I would suggest that PIPELINE_EN is declared as type boolean instead, since that is a more obvious choice, and the = '1' can then be skipped in the conditions.
If for some reason you want to avoid declaration of the pipeline signal 'pipeline_reg' in the actual design, then you can declare a variable in the process, with code like below. It is required to assign the variable after use in the code, to get a flip-flop, since it otherwise just becomes combinatorial logic. However, such creation of flip-flops through use of variables is advised against, since it is hard to read and get right, thus error prone, and should be avoided in general. Though here it comes:
PROC_B : process (clk, rst_n) is
variable pipeline_reg_v : std_logic; -- Results in pipeline register if PIPELINE_EN, otherwise removed by synthesis
begin -- process PROC_B
if rst_n = '0' then -- asynchronous reset (active low)
ab_xor_c <= '0';
if PIPELINE_EN then
pipeline_reg_v := '0';
end if;
elsif rising_edge(clk) then -- rising clock edge
if PIPELINE_EN then
ab_xor_c <= pipeline_reg_v xor c;
pipeline_reg_v := a_and_b;
else
ab_xor_c <= a_and_b xor c;
end if;
end if;
end process PROC_B;
An alternative is to use the VHDL block construction, together with generate, whereby you can have signal declarations that are local to the block, as shown below. Though note that the block construction is rarely used in VHDL, thus there is a higher risk of encountering bugs in tools.
PIPELINE_EN_TRUE_GENERATE : if PIPELINE_EN generate
PIPELINE_EN_TRUE_BLOCK : block
signal pipeline_reg : std_logic;
begin
PROC_B : process (clk, rst_n) is
begin -- process PROC_B
if rst_n = '0' then -- asynchronous reset (active low)
ab_xor_c <= '0';
pipeline_reg <= '0';
elsif rising_edge(clk) then -- rising clock edge
pipeline_reg <= a_and_b;
ab_xor_c <= pipeline_reg xor c;
end if;
end process PROC_B;
end block PIPELINE_EN_TRUE_BLOCK;
end generate PIPELINE_EN_TRUE_GENERATE;
PIPELINE_EN_FALSE_GENERATE : if not PIPELINE_EN generate
PROC_B : process (clk, rst_n) is
begin -- process PROC_B
if rst_n = '0' then -- asynchronous reset (active low)
ab_xor_c <= '0';
elsif rising_edge(clk) then -- rising clock edge
ab_xor_c <= a_and_b xor c;
end if;
end process PROC_B;
end generate PIPELINE_EN_FALSE_GENERATE;
With a generic parameter for the pipeline depth:
library ieee;
use ieee.std_logic_1164.all;
entity example is
generic(
depth: natural := 0
);
port(
clk: in std_logic;
rst_n: in std_logic;
a: in std_logic;
b: in std_logic;
c: in std_logic;
z_out: out std_logic
);
end entity example;
architecture rtl of example is
signal a_and_b: std_logic;
signal ab_xor_c: std_logic_vector(0 to depth);
begin
z_out <= ab_xor_c(depth);
process(clk, rst_n) is
begin
if rst_n = '0' then
a_and_b <= '0';
ab_xor_c <= (others => '0');
elsif rising_edge(clk) then
a_and_b <= a and b;
ab_xor_c <= ab_xor_c srl 1;
ab_xor_c(0) <= a_and_b xor c;
end if;
end process;
end architecture rtl;
And then, with depth=2:
use std.env.all;
library ieee;
use ieee.std_logic_1164.all;
entity example_sim is
end entity example_sim;
architecture sim of example_sim is
signal clk: std_logic;
signal rst_n: std_logic;
signal a: std_logic;
signal b: std_logic;
signal c: std_logic;
signal z_out: std_logic;
begin
u0: entity work.example(rtl)
generic map(
depth => 2
)
port map(
clk => clk,
rst_n => rst_n,
a => a,
b => b,
c => c,
z_out => z_out
);
process
begin
clk <= '0';
wait for 1 ns;
clk <= '1';
wait for 1 ns;
end process;
process
begin
rst_n <= '0';
a <= '1';
b <= '1';
c <= '1';
wait until rising_edge(clk);
rst_n <= '1';
for i in 1 to 15 loop
wait until rising_edge(clk);
c <= not c;
end loop;
finish;
end process;
end architecture sim;
Demo:
$ ghdl -a --std=08 example_sim.vhd
$ ghdl -r --std=08 example_sim --vcd=example_sim.vcd
simulation finished #21ns
$ open example_sim.vcd
Of course, if your data type (T) is more complex than a single std_logic you will need some extra work.
Define a vector type of your data type (T_vector).
Define a "zero" constant value for your base type (T_zero), this will be the value that enters on the left when shifting to the right.
Overload the srl operator for the T_vector vector type.
Example with a T type (not tested):
type T_vector is array(natural range <>) of T;
constant T_zero: T := <some zero value for your type>;
...
function "srl"(l: T_vector; r: natural) return T_vector is
constant size: positive := l'length;
constant tmp: T_vector(0 to size - 1) := l;
variable res: T_vector(0 to size - 1);
begin
if r = 0 then
res := tmp;
elsif r = 1 then
res := T_zero & tmp(0 to size - 2);
else
res := (l srl 1) srl (r - 1);
end if;
return res;
end function "srl";
When I run this code two errors appear that say "Actual parameter type in port map does not match the type of the formal port 's'. I need help to understand how to fix these.
-- code that try in EDA playground to transfer from one register to another
-- library
library ieee;
use ieee. std_logic_1164.all;
-- declaration for d flip-flop
entity D_FF is
PORT( D : in std_logic_vector(7 downto 0);
s :in std_logic;
CLOCK: in std_logic;
Q: out std_logic_vector(7 downto 0));
end D_FF;
architecture behavioral of D_FF is
-- signals declaration
signal s1,s2,s3,s4,s5,s6,s7,s8: std_logic;
begin
--transfer the 4 bit to another register
s1 <= D(0) and (not s);
Q(0) <= s and D(0);
s2 <= D(1) and (not s);
Q(1) <= (Q(0)and s) or s2;
s3 <= D(2) and (not s);
Q(2) <= (Q(1)and s) or s3;
s4 <= D(3) and not s;
Q(3) <= (Q(2)and s)or s4;
s5 <= D(4) and not s;
Q(4) <= (Q(3)and s)or s5;
s6 <= D(5) and not s;
Q(5) <= (Q(4)and s)or s6;
s7 <= D(6) and not s;
Q(6) <= (Q(5)and s)or s7;
s8 <= D(7) and not s;
Q(7) <= (Q(6)and s)or s8;
end behavioral;
------------------------------
-- testbench
------------------------------
-- library
library ieee;
use ieee. std_logic_1164.all;
entity testbench is
-- empty entity
end testbench;
-----------------------------
architecture tb of testbench is -- testbench
-- architecture -- REDUNDANT transcription error?
-- component declaration
component D_FF is
PORT( D : in std_logic_vector(7 downto 0);
s :in std_logic;
CLOCK: in std_logic;
Q: out std_logic_vector(7 downto 0));
end component;
-- signals that need in testbench -- COMMENT DELIMITER transcription error?
signal D_s: std_logic_vector(7 downto 0);-- signals for entity i/o
signal Q_s: std_logic_vector(7 downto 0);-- signals for entity i/o
signal s_s: std_logic;
signal CLOCK_s: std_logic;
-- is the signal that must be run 4 time to transfer the bit
signal loop_count: integer;
begin
dut:D_FF port map(D_s,Q_s,s_s,CLOCK_s);
-- design under test instantiation
stimProcess: process --
--stimulus generator
begin
--the run 4 time this to transfer the 4 bit
for loop_counter in 0 to 3 loop
D_s <= "01100000";
wait until CLOCK_s = '1' and CLOCK_s'event;
end loop;
end process stimProcess;
-- without sensitivity list
end tb;
You are using a positional association for the port map. When you do this, the order of ports in your port map must match the order of ports in your component declaration. Using positional association, the proper order is:
dut:D_FF port map(D_s,s_s,CLOCK_s,Q_s);
Note that in your example, you've connected the signal Q_s to s, s_s to CLOCK, and CLOCK_s to Q (because your order was not the same).
I always prefer named association. On the left, you have your "formal" (the port outlined in your component declaration). On the right, you have the "actual" (the signal you're connecting to that port). The whitespace is just to improve readability.
dut: D_FF
port map (
D => D_s,
s => s_s,
CLOCK => CLOCK_s,
Q => Q_s
);
Named association port maps are much easier to debug, and the ports can be mapped in any order.
I have been stuck with this problem for a while. I would be really grateful if someone is able help. Have gone through most of the code repeatedly without any solution. There are sets of codes in use; this bcd counter is used further in the rest of my project. I have added the necessary codes below:
BCD counter for 1 digit:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
USE WORK.mypackage_p.ALL;
ENTITY bcd_e IS
PORT(
res_i, clk_i, enable_i, counter_res_i : IN STD_LOGIC;
bcd_o : OUT STD_LOGIC_VECTOR(bcd_width_c-1 DOWNTO 0);
carry_o : OUT STD_LOGIC
);
END bcd_e;
ARCHITECTURE bcd_a OF bcd_e IS
SIGNAL count_s : INTEGER RANGE bcd_cnt_c DOWNTO 0;
BEGIN
PROCESS(res_i, clk_i)
BEGIN
IF (res_i = '1') THEN
count_s <= 0;
ELSIF (clk_i = '1' AND clk_i'EVENT) THEN
IF (enable_i = '1') THEN
IF(count_s >= bcd_cnt_c) THEN
count_s <= 0;
ELSE
count_s <= count_s + 1;
END IF;
END IF;
IF (counter_res_i = '1') THEN
count_s <= 0;
END IF;
END IF;
END PROCESS;
bcd_o <= STD_LOGIC_VECTOR(to_unsigned(count_s, bcd_width_c));
carry_o <= '1' WHEN (count_s = bcd_cnt_c) ELSE '0';
END bcd_a;
8 digit BCD using the above bcd counter to create 8 digits
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
USE WORK.mypackage_p.ALL;
ENTITY bcd_8counter_e IS
PORT(
res_i, clk_i, enable_i, counter_res_i : IN STD_LOGIC;
bcd_array_o : OUT bcd_array_t
);
END bcd_8counter_e;
ARCHITECTURE bcd_8counter_a OF bcd_8counter_e IS
COMPONENT bcd
PORT(
res_i, clk_i, enable_i, counter_res_i : IN STD_LOGIC;
bcd_o : OUT STD_LOGIC_VECTOR(bcd_width_c-1 DOWNTO 0);
carry_o : OUT STD_LOGIC
);
END COMPONENT;
SIGNAL bcd_array_s : bcd_array_t;
SIGNAL enable_s : STD_LOGIC_VECTOR(no_of_digits_c-1 DOWNTO 0);
SIGNAL carry_s : STD_LOGIC_VECTOR(no_of_digits_c-1 DOWNTO 0);
FOR ALL : bcd USE ENTITY WORK.bcd_e (bcd_a);
BEGIN
carry_s(0) <= enable_i;
gen_carry : FOR i IN 1 TO (no_of_digits_c-1) GENERATE
carry_s(i) <= carry_s((i-1)) AND enable_s((i-1));
END GENERATE gen_carry;
gen_bcd : FOR i IN 0 TO (no_of_digits_c-1) GENERATE
digitx : bcd PORT MAP(res_i, clk_i, carry_s(i), counter_res_i, bcd_array_s(i), enable_s(i));
END GENERATE gen_bcd;
bcd_array_o <= bcd_array_s
END bcd_8counter_a;
My package file for the constants:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
PACKAGE mypackage_p IS
CONSTANT freq_20k_c : INTEGER := 2500;
CONSTANT bcd_cnt_c : INTEGER := 9;
CONSTANT bcd_width_c : INTEGER := 4;
CONSTANT no_of_digits_c : INTEGER := 8;
TYPE bcd_array_t IS ARRAY(7 DOWNTO 0) OF STD_LOGIC_VECTOR(3 DOWNTO 0);
END PACKAGE;
I keep getting the following warning:
Warning: /home/stud/mr-131416/Desktop/VHDL_Project_Latest/src/bcd_counter8_a.vhd(15): (vcom-1263) Configuration specification "all : bcd" applies to no component instantiation statements.
The code does not pass test/simulation of a test-bench because of this warning. Help would be really appreciated.
It's a matter of scope. A component configuration configures a component instantiation. The generate statement produces a block statement (or nested block statements when a port map is supplied).
A block statement (for an internal or external block) use a block configuration which is only found in a configuration declaration.
Binding indications are not hierarchical, without the ability to reach down into a block to specify a component instantiation you can either use a configuration declaration or move the configuration specification:
-- for all : bcd use entity work.bcd_e (bcd_a);
begin
carry_s(0) <= enable_i;
gen_carry :
for i in 1 to (no_of_digits_c-1) generate
carry_s(i) <= carry_s((i-1)) and enable_s((i-1));
end generate gen_carry;
gen_bcd :
for i in 0 to (no_of_digits_c-1) generate
for all: bcd use entity work.bcd_e (bcd_a);
begin
digitx : bcd port map (res_i, clk_i, carry_s(i),
counter_res_i, bcd_array_s(i), enable_s(i));
end generate gen_bcd;
bcd_array_o <= bcd_array_s; -- CHANGED WAS MISSING SEMICOLON
end bcd_8counter_a;
Note the missing semicolon on the assignment statement for bcd_array_o has been added.
With these changes your design analyzes and elaborates without warnings.
You could note not all synthesis tools support configuration declarations while most support configuration specifications.
See IEEE Std 1076-2008 7.3 Configuration specification, 3.4 Configuration declarations, 3.4.2 Block configurations
The failure to simulate or synthesize would be because the distx component instantiations are unbound because there isn't a bcd entity found in the working directory.
Writing a simple testbench that does not invoke the synchronous reset, uses a clock with a 10 ns period and runs for 10 ms:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.mypackage_p.all;
entity tb is
end entity;
architecture foo of tb is
signal reset: std_logic; -- '1' for RESET
signal clk: std_logic := '0';
signal en: std_logic; -- '1' for ENABLE
signal syn_reset: std_logic; -- '1' for SYNCHRONOUS RESET
signal bcd_array: bcd_array_t;
begin
DUT:
entity work.bcd_8counter_e
port map (
res_i => reset,
clk_i => clk,
enable_i => en,
counter_res_i => syn_reset,
bcd_array_o => bcd_array
);
CLOCK:
process
begin
wait for 5 ns;
clk <= not clk;
if now > 10 ms then
wait;
end if;
end process;
STIMULI:
process
begin
wait for 10 ns;
reset <= '0';
en <= '0';
syn_reset <= '0';
wait for 10 ns;
reset <= '1';
wait for 20 ns;
reset <= '0';
wait for 20 ns;
en <= '1';
wait;
end process;
end architecture;
Shows that the counter depends on enable and shows that the first 6 digits work:
in VHDL all the code lines are executed in a parallel way, since its a machine.
i want to create this RAM that reads a certain register from a ram block to the output and only 'afterwards' writes to the same register the input. my code goes like this:
architecture Behavioral of RAM is
type ram_t is array (0 to numOfRegs-1) of std_logic_vector (rLength-1 downto 0);
signal ram_s: ram_t;
signal loc : integer;
begin
process(clk)
begin
if(rising_edge(clk)) then
if(we='1') then
dataout <= ram_s(loc); -- reads the 'old' data to the output
ram_s(loc) <= datain; -- writes the 'new' data to the RAM
loc <= conv_integer(addr);
end if;
end if;
end process;
end Behavioral;
there is a similar case presented
here.
so I'd like to ask, is my code works fine or is there need for tweaking like putting a delay of half clock cycle, and if so, how to implement it.
I'm very new to VHDL thanks for your patience and help.
ive add a testbench simulation below . as can be seen the dataout isnt working at all.
Your question doesn't present a Minimal, Verifiable and Complete example, lacking the ability to replicate your results.
One of the consequences of this is that answers can be ambiguous should there be one or more causes of the problem in portions of your code not shown.
Brian's comment that you aren't reading data when we is invalid is poignant and would be responsible for 'U's in the clock cycle left of your yellow marker in your waveform.
There's also the issue with loc being a signal. Signals are scheduled for update, and no update occurs while any process that is scheduled to resume in the current simulation cycle has not been resumed and suspended.
This means the integer version of your address is delayed and won't be seen in the process until the next rising edge.
Fixing loc by making it a variable as an alternative to pipelining datain and moving the dataout assignment are accomplished in the following changes to your RAM process:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all; -- standard package
entity ram is
generic (
ADDRLENGTH: natural := 8;
RLENGTH: natural := 16;
NUMOFREGS: natural := 256
);
port (
clk: in std_logic;
we: in std_logic;
addr: in std_logic_vector (ADDRLENGTH - 1 downto 0);
datain: in std_logic_vector (RLENGTH - 1 downto 0);
dataout: out std_logic_vector (RLENGTH - 1 downto 0)
);
end entity;
architecture behavioral of ram is
type ram_t is array (0 to NUMOFREGS - 1) of
std_logic_vector (RLENGTH - 1 downto 0);
signal ram_s: ram_t;
-- signal loc: integer; -- USE VARIABLE in process instead
begin
process(clk)
variable loc: integer; -- MAKE loc variable so it's immediately available
begin
if rising_edge(clk) then
loc := to_integer(unsigned(addr)); -- MOVED so READ works
if we = '1' then
-- dataout <= ram_s(loc); -- reads the 'old' data to the output
ram_s(loc) <= datain; -- writes the 'new' data to the ram
-- loc <= conv_integer(addr);
end if;
dataout <= ram_s(loc); -- MOVED reads the 'old' data to the output
end if;
end process;
end architecture behavioral;
There's also the liberty of filling in the entity declaration and converting from conv_integer using Synopsys's package std_logic_arith to to_integer in the IEEE's numeric_std package. With a -2008 compliant tool chain you could instead use IEEE's package numeric_std_unsigned and do away with the type conversion to unsigned.
Because the ram_test testbench was also not supplied a testbench was written to replicate your waveform display image:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity ram_tb is
end entity;
architecture foo of ram_tb is
constant ADDRLENGTH: natural := 8;
constant RLENGTH: natural := 16;
constant NUMOFREGS: natural := 256;
signal clk: std_logic := '0';
signal we: std_logic := '1';
signal addr: std_logic_vector (ADDRLENGTH - 1 downto 0);
signal datain: std_logic_vector (RLENGTH - 1 downto 0);
signal dataout: std_logic_vector (RLENGTH - 1 downto 0);
begin
DUT:
entity work.ram
generic map (
ADDRLENGTH => ADDRLENGTH,
RLENGTH => RLENGTH,
NUMOFREGS => NUMOFREGS
)
port map (
clk => clk,
we => we,
addr => addr,
datain => datain,
dataout => dataout
);
CLOCK:
process
begin
if now = 500 ps then
wait for 200 ps;
else
wait for 100 ps;
end if;
clk <= not clk;
if now >= 1100 ps then
wait;
end if;
end process;
STIMULI:
process
begin
for i in 0 to 2 loop
addr <= std_logic_vector(to_unsigned (i, ADDRLENGTH));
case i is
when 0 =>
datain <= x"00FF";
when 1 =>
datain <= x"FF00";
when 2 =>
datain <= x"FFFF";
end case;
wait until falling_edge(clk);
if i = 1 then
we <= '0';
end if;
end loop;
for i in 1 to 2 loop
addr <= std_logic_vector(to_unsigned (i, ADDRLENGTH));
case i is
when 1 =>
datain <= x"FF00";
when 2 =>
datain <= x"FFFF";
end case;
wait until falling_edge(clk);
end loop;
wait;
end process;
end architecture;
And this produced:
Where the one written address that is subsequently read shows the correct data.
The simulator used does not present non-signals in a waveform dump (bounds in declarations are required to be static) and rst is not found in the portion of your design specification provided.
As noted previously there is no guarantee there isn't another issue with portions of your design specification or testbench not provided in your question.
The testbench shown is by no means comprehensive.
i have 27MHz frequency at the input and want to get 400Hz, 100Hz and 1Hz frequencies at the output. but when i simulate it i dont get anything its just undefined, i dont have any idea what's wrong.
code
entity clk_div is
port
(
clk : in std_logic;
clock_set : in std_logic;
clk1_out : out std_logic;
clk100_out : out std_logic;
clk400_out : out std_logic
);
end entity;
architecture rtl of clk_div is
signal q : std_logic_vector(24 downto 0);
begin
process (clk)
begin
if(rising_edge(clk)) then
q <= q+1;
end if;
end process;
clk1_out <= q(24); -- 1Hz freq
clk400_out <= q(15); --400Hz freq
clk100_out <= q(17); --100Hz freq
end rtl;
q is never initalised, so when you add one to it, the result is not defined.
You need something like:
signal q : std_logic_vector(24 downto 0) := (others => '0');
Also, you are performing a mathematical operation on an std_logic_vector. This is not recommended; you should have a look at using the numeric_std package, and make your counter type unsigned.