I am to determine the length of each column in a 4x4 matrix. The lengths of each columns are counted from the bottom of each column upwards and are only counted from the initial '1' accessed onwards.
1110
0111
0110
0001
Column1=1, Column2=3, Column3=3, Column4=4 etc...
Does anyone have any ideas how I could do this? I have thus far attempted to produce a matrix alongside a function to extract each of the columns.
type col_mat is array (0 to 3) of std_logic;
type matrix is array (0 to 3, 0 to 3) of std_logic;
signal M: matrix;
signal temp_col : col_mat;
signal count : unsigned (1 downto 0):= "00";
function extract_col(x: matrix; column : integer) return col_mat is
variable ret: col_mat;
begin
for i in col_mat'range loop
ret(i) := x(i,column)
end loop;
return ret;
end function;
begin
if rising_edge(clk) then
temp_col<= extract_col(M, to_integer(count) );
count <= count+1;
end if;
end process;
You're describing a priority encoder and from the looks of it you're implying it operates in one clock, which can run into some clock rate limit based on the target device (assuming you'll synthesize).
A priority encode can be an if statement, a case statement, a loop statement with an exit (as Martin Zabel commented), describe one combinatorially with logic operators or with a conditional signal assignment.
For this particular use a loop statement is the most compact and one has been added to your process.
The following code is derived from your question, fleshed out into a Minimal, Complete, and Verifiable example.
The results are in terms of array type indexes (starting from 0).
I added a pipeline register for count named column as well as registers for a signal to specify a '1' was found (found_1) and the highest row value a '1' is found in (imaginatively named row):
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity column is
end entity;
architecture foo of column is
type col_mat is array (0 to 3) of std_logic;
type matrix is array (0 to 3, 0 to 3) of std_logic; -- (row,column)
-- signal M: matrix;
-- 1110
-- 0111
-- 0110
-- 0001
--
-- Column1=1, Column2=3, Column3=3, Column4=4 etc...
--
-- column0 = 0, column1 = 2 column2 = 2, column3 = 3
-- (matrix is defined so (0,0) is the upper left hand corner)
-- Looking for the highest column index occupied by a '1'
signal M: matrix := ( -- for demo provide matrix default value
('1','1','1','0'), -- row 0
('0','1','1','1'),
('0','1','1','0'),
('0','0','0','1') -- row 3
);
-- signal temp_col: col_mat;
signal count: unsigned (1 downto 0):= "00";
function extract_col(x: matrix; column: integer) return col_mat is
variable ret: col_mat;
begin
for i in col_mat'range loop
ret(i) := x(i,column); -- was missing semicolon
end loop;
return ret;
end function;
-- added signals:
signal clk: std_logic := '1'; -- rising_edge() requires 0 -> 1 trans
signal found_1: std_logic := '0';
signal column: unsigned (1 downto 0);
signal row: integer range 0 to 3;
signal mat_col: col_mat;
begin
UNLABELED:
process (clk)
variable temp_col: col_mat; -- made temp_col a variable, use immediately
begin
if rising_edge(clk) then
temp_col := extract_col(M, to_integer(count)); -- was signal
-- priority encoder: -- added loop
for i in temp_col'RIGHT downto temp_col'LEFT loop -- highest first
if temp_col(i) = '1' then
found_1 <= '1';
column <= count;
row <= i;
exit;
else
found_1 <= '0';
end if;
end loop;
mat_col <= temp_col; -- added
count <= count + 1;
end if;
end process;
CLOCK: -- Added clock process
process
begin
wait for 10 ns;
clk <= not clk;
if now > 90 ns then
wait;
end if;
end process;
end architecture;
And when simulated this gives:
I added mat_col because the tool I used doesn't do delta cycle waveforms and variables have no notion of time. temp_col was made a variable to allow it's value to be used in immediately after it's assigned (an updated signal value is not available in the current simulation cycle).
You can also see I provided a default value for M from your question.
Related
I am new to VHDL and trying to generate 1 second counter. For simplicity, I am using the clock frequency of 10 Hz. For this purpose I am using a clk as an input and LED as an output. My VHDL code is given below:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
USE ieee.std_logic_unsigned.ALL;
use ieee.numeric_std.all;
entity tick_counter is
generic(FrequencyHz : integer := 10);
Port ( clk : in STD_LOGIC;
led : out STD_LOGIC);
end tick_counter;
architecture Behavioral of tick_counter is
signal tick :integer;
signal counter :integer;
begin
process(clk, tick, counter)
begin
if rising_edge(clk) then
if tick = FrequencyHz - 1 then
tick <= 0;
counter <= counter + 1;
else
tick <= tick + 1;
end if;
end if;
end process;
led <= '1' when counter = 3 else '0';
end Behavioral;
I tried to write the code in such a way so that, when three seconds pass, the LED turns ON. My test bench code is given below:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_unsigned.ALL;
use ieee.numeric_std.all;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
ENTITY tick_counter_tb IS
END tick_counter_tb;
ARCHITECTURE behavior OF tick_counter_tb IS
-- Component Declaration for the Unit Under Test (UUT)
-- We're slowing down the clock to speed up simulation time
constant FrequencyHz : integer := 10; -- 10 Hz
constant clk_period : time := 1000 ms / FrequencyHz;
COMPONENT tick_counter
PORT( clk : IN std_logic;
led : OUT std_logic);
END COMPONENT;
--Inputs
signal clk : std_logic := '0';
--Outputs
signal led : std_logic;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut : entity work.tick_counter
generic map(FrequencyHz => FrequencyHz)
PORT MAP (clk => clk,
led => led);
-- 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 until rising_edge(clk);
-- insert stimulus here
wait;
end process;
END;
But in the simulation result, I am just seeing a blank diagram as shown below (link given):
I don't understand where I am making a mistake. Any help would be highly appreciated.
The default initial value of an integer is INTEGER'LOW (a very negative number).
That means counter won't become 3 for a very long time (as the busybee indicated).
You can constrain and/or provide an initial value for tick. counter appears to be meant as a modulo counter range 0 to 3. It's modulus could be passed identically to tick which uses FrequencyHZ. Also note that any integer counter needs explicit roll over, it's an error if the result of an addition doesn't fall with the range INTEGER'LOW to INTEGER'HIGH or the constrained range.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
-- USE ieee.std_logic_unsigned.ALL;
-- use ieee.numeric_std.all;
entity tick_counter is
generic(FrequencyHz : integer := 10);
Port ( clk : in STD_LOGIC;
led : out STD_LOGIC);
end tick_counter;
architecture Behavioral of tick_counter is
-- Initial value of integers is INTEGER'LOW (a large negative number)
signal tick: integer range 0 to FrequencyHz - 1 := 0;
signal counter: integer := 0; -- ADDED default initial value
begin
process(clk, tick, counter)
begin
if rising_edge(clk) then
if tick = FrequencyHz - 1 then
tick <= 0;
if counter = 3 then -- ADDED MODULUS 4 test for counter
counter <= 0;
else
counter <= counter + 1;
end if;
else
tick <= tick + 1;
end if;
end if;
end process;
led <= '1' when counter = 3 else '0';
end Behavioral;
With the changes the simulation will cause led to be a '1' for one second every four seconds.
I have a bit vector like this
subtype alarms_type : std_logic_vector(1 to 8)
signal alarms : alarms_type := (others => '0');
and the purpose of each bit is defined like this
constant sys1_temp_hi_al : integer := 1;
constant sys1_temp_lo_al : integer := 2;
constant sys1_crnt_hi_al : integer := 3;
constant sys1_cnrt_lo_al : integer := 4;
constant sys2_temp_hi_al : integer := 5;
constant sys2_temp_lo_al : integer := 6;
constant sys2_crnt_hi_al : integer := 7;
constant sys2_cnrt_lo_al : integer := 8;
I would like to be able to access subsets of the alarms_type with a short, readable notation. For example
alarms(SYS2_ALS) <= (others => '0'); -- set multiple values
temp_alarm <= or(alarms(TEMP_ALS)); -- or together multiple values to a std_logic
temp_alarms <= alarms(TEMP_ALS)); -- extract a subset to a suitably sized vector
alarms(TEMP_ALS) := (others => '1'); -- set (or clear) multiple disjoint values
I would like to know if the alias keyword will help me, like this:
alias HI_ALARMS is sys1_temp_hi_al|sys1_crnt_hi_al|sys2_temp_hi_al|sys2_crnt_hi_al;
alias LO_ALARMS is sys1_temp_lo_al|sys1_crnt_lo_al|sys2_temp_lo_al|sys2_crnt_lo_al;
alias TEMP_ALS is sys1_temp_hi_al|sys1_temp_lo_al|sys2_temp_hi_al|sys2_temp_lo_al;
alias CRNT_ALS is sys1_crnt_hi_al|sys1_crnt_lo_al|sys2_crnt_hi_al|sys2_crnt_lo_al;
alias SYS1_ALS is sys1_temp_hi_al|sys1_crnt_hi_al|sys2_temp_hi_al|sys2_crnt_hi_al;
alias SYS2_ALS is sys1_temp_hi_al|sys1_crnt_hi_al|sys2_temp_hi_al|sys2_crnt_hi_al;
It appears from the Alias chapter of the Ashenden book that this is not how an alias should be used, but hopefully I am missing something.
If there is a correct way to use alias to achieve my goal, please provide examples.
Alternatively, if there is a different or better way using constant or some other aspect of VHDL, please show me how.
Or just tell me that it can't be done, and if it is appropriate, please confirm that I could write functions to get and procedures to set the different subsets.
If I use functions and procedures, is there a cleaner notation than this? (I may need lots of this functions and procedures).
function get_temp_als(alarms : alarms_type)
return alarms(sys1_temp_hi_al) & alarms(sys1_temp_lo_al) & alarms(sys2_temp_hi_al) & alarms(sys2_temp_lo_al);
function get_combined_temp_als(alarms : alarms_type)
return alarms(sys1_temp_hi_al) or alarms(sys1_temp_lo_al) or alarms(sys2_temp_hi_al) or alarms(sys2_temp_lo_al);
procedure set_temp_als(alarms: alarm_type, value:std_logic)
begin
alarms(sys1_temp_hi_al) <= value;
alarms(sys1_temp_lo_al) <= value;
alarms(sys2_temp_hi_al) <= value;
alarms(sys2_temp_lo_al) <= value;;
end;
I would like this to work with VHDL 2002 and it is intended for synthesis.
Aliases are new names for existing named entities not new entities.
Alternatively, if there is a different or better way using constant or some other aspect of VHDL, please show me how.
There's the basic issue where it isn't clear what you're going to do with information, lacking a minimal, complete, and verifiable example you're trying to make more 'elegant'.
It is possible to use constants to specify alarms_type indexes:
library ieee;
use ieee.std_logic_1164.all;
entity alarming is
end entity;
architecture fum of alarming is
-- subprograms, constants and type declarations could be in a package
subtype alarm_range is integer range 1 to 8;
subtype alarms_type is std_logic_vector(alarm_range);
signal alarms: alarms_type := (others => '0');
constant sys1_temp_hi_al : integer := 1;
constant sys1_temp_lo_al : integer := 2;
constant sys1_crnt_hi_al : integer := 3;
constant sys1_crnt_lo_al : integer := 4;
constant sys2_temp_hi_al : integer := 5;
constant sys2_temp_lo_al : integer := 6;
constant sys2_crnt_hi_al : integer := 7;
constant sys2_crnt_lo_al : integer := 8;
type index is array (natural range <>) of alarm_range;
constant HI_ALARMS: index := (sys1_temp_hi_al, sys1_crnt_hi_al,
sys2_temp_hi_al, sys2_crnt_hi_al);
constant LO_ALARMS: index := (sys1_temp_lo_al, sys1_crnt_lo_al,
sys2_temp_lo_al, sys2_crnt_lo_al);
constant TEMP_ALS: index := (sys1_temp_hi_al, sys1_temp_lo_al,
sys2_temp_hi_al, sys2_temp_lo_al);
constant CRNT_ALS: index := (sys1_crnt_hi_al, sys1_crnt_lo_al,
sys2_crnt_hi_al, sys2_crnt_lo_al);
constant SYS1_ALS: index := (sys1_temp_hi_al, sys1_temp_lo_al,
sys1_crnt_hi_al, sys1_crnt_lo_al);
constant SYS2_ALS: index := (sys2_temp_hi_al, sys2_temp_lo_al,
sys2_crnt_hi_al, sys2_crnt_lo_al);
function get_alarm (alarm: alarms_type; indx: alarm_range)
return std_logic is
begin
return alarm(indx);
end function;
function set_alarm (alarm: alarms_type; indx: alarm_range)
return alarms_type is
variable ret_val: alarms_type := alarm;
begin
ret_val(indx) := '1';
return ret_val;
end function;
function get_alarms (alarm: alarms_type; alarm_indx: index)
return std_logic_vector is -- doesn't look real useful.
variable ret_val: std_logic_vector(alarm_indx'range);
begin
for i in alarm_indx'range loop
ret_val(i) := alarm(alarm_indx(i));
end loop;
return ret_val;
end function;
-- instead:
function select_alarms (alarm: alarms_type; alarm_indx: index)
return alarms_type is
variable ret_val: alarms_type := (others => '0');
begin
for i in alarm_indx'range loop
ret_val(alarm_indx(i)) := alarm(alarm_indx(i));
end loop;
return ret_val;
end function;
-- which returns a mask selected alarms_type value that allows the use of a
-- single alarm service routine.
function set_alarms (alarm: alarms_type; alarm_indx: index)
return alarms_type is
variable ret_val: alarms_type := (others => '0');
begin
for i in alarm_indx'range loop
ret_val(i) := alarm(alarm_indx(i));
end loop;
return ret_val;
end function;
procedure report_alarms (alarm: in alarms_type) is
type name_array is array (alarm_range) of string (1 to 15);
constant alarm_name: name_array := (
"sys1_temp_hi_al", "sys1_temp_lo_al",
"sys1_crnt_hi_al", "sys1_crnt_lo_al",
"sys2_temp_hi_al", "sys2_temp_lo_al",
"sys2_crnt_hi_al", "sys2_crnt_lo_al"
);
begin
for i in alarm_range loop
if alarm(i) = '1' then
report "alarm " & alarm_name(i) & " is set";
end if;
end loop;
end procedure;
begin
alarms <= select_alarms("11111111", TEMP_ALS) after 5 ns;
LABELED:
process (alarms)
begin
report_alarms(alarms);
end process;
end architecture;
And
ghdl -r alarming
alarming.vhdl:102:17:#5ns:(report note): alarm sys1_temp_hi_al is set
alarming.vhdl:102:17:#5ns:(report note): alarm sys1_temp_lo_al is set
alarming.vhdl:102:17:#5ns:(report note): alarm sys2_temp_hi_al is set
alarming.vhdl:102:17:#5ns:(report note): alarm sys2_temp_lo_al is set
tells us I can set all the temperature alarms using alarms selected by the set of temperature alarm indexes.
By providing a second parameter for selecting a set of alarms by name the number of subprograms drops (the alternative is to declare a type for all the different sets of alarms and provide subprograms for them all).
You are correct in that aliases do not work like that. They are an alias to a single object (or slice thereof) and cannot be used to make new compounded objects like you might do with a pointer in another language.
A procedure is likely the only way you can achieve this. The alarms paramter should be a signal and mode out:
procedure set_temp_als(signal alarms: out alarm_type; value:std_logic)
begin
alarms(sys1_temp_hi_al) <= value;
alarms(sys1_temp_lo_al) <= value;
alarms(sys2_temp_hi_al) <= value;
alarms(sys2_temp_lo_al) <= value;
end;
so you can assign the alarms with:
set_temp_als(alarms, '1');
Your functions are the right idea, but syntactically wrong:
function get_temp_als(alarms : alarms_type) return std_logic_vector is
begin
return alarms(sys1_temp_hi_al) & alarms(sys1_temp_lo_al) & alarms(sys2_temp_hi_al) & alarms(sys2_temp_lo_al);
end function;
signal some_other_slv : std_logic_vector(3 downto 0);
some_other_slv <= get_temp_als(alarms);
I have an array of std_logic_vectors in which I want to implement a delay chain. I wrote it up like this, and it works fine:
--Signal Declaration
type MyArrayType is array(0 to 3) of std_logic_vector(31 downto 0);
signal s_aslv_DelayChain : MyArrayType;
--Concurrent Statement, Load input chain
s_aslv_DelayChain(0) <= ip_slv_Input;
--Delay line Process
DelayProc : process(ip_sl_Clk)
begin
if(rising_edge(ip_sl_Clk)) then
s_aslv_DelayChain(1) <= s_aslv_DelayChain(0);
s_aslv_DelayChain(2) <= s_aslv_DelayChain(1);
s_aslv_DelayChain(3) <= s_aslv_DelayChain(2);
end if; --rising_edge(ip_sl_Clk)
end process DelayProc;
This produces the result I would expect:
However, if I change the process to use a looping variable:
--Delay line Process
DelayProc : process(ip_sl_Clk)
begin
if(rising_edge(ip_sl_Clk)) then
for n in 1 to 3 loop
s_aslv_DelayChain(n) <= s_aslv_DelayChain(n-1);
end loop;
end if; --rising_edge(ip_sl_Clk)
end process DelayProc;
It doesn't work and I get a bunch of U's:
Shouldn't the 2 coding styles describe the same behavior?
I have a vector A that's 64bits long and I want the output B to equal 3 while A is 30-35 and zero elsewhere. I can't figure out the testbench to loop through the vector A as a bit. I've tried several different ways but only got 1/5 of the array to give any output at all. This is as far as I could get without syntax/compile errors.
Main code
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.ALL;
entity ent is
port(A:in std_logic_vector(5 downto 0);
B:out std_logic_vector(3 downto 0));
end ent;
architecture arch_ent of ent is
begin
with A select
B <= "0011" when "011110",
"0011" when "011111",
"0011" when "100000",
"0011" when "100001",
"0011" when "100010",
"0011" when "100011",
"0000" when others;
end arch_ent;
Testbench
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity tb is
end tb;
architecture arch_tb of tb is
component ent
port(A:in std_logic_vector(5 downto 0);
B:out std_logic_vector(3 downto 0));
end component;
signal A_tb: std_logic_vector(5 downto 0);
signal B_tb: std_logic_vector(3 downto 0);
begin
uut: entity ent port map(A=>A_tb, B=>B_tb);
tb: process
constant period: time := 20ns;
begin
for i in A_tb'range loop
A_tb <= std_logic_vector(to_unsigned(i,6));
wait for period;
assert (B_tb = "0011")
report "test failed" severity error;
end loop;
wait;
end process;
end arch_tb;
In the end I'm trying to plot out the waveform like this:
http://i10.photobucket.com/albums/a142/blargonblop/wave.png
where A will go to 63 and each output is its correct value from 30-35 and 0 elsewhere
The loop parameter you use to specify the number of 'tests' is A_tb'range, which happens to be 5 downto 0, or six tests, i is assigned 5,4,3,2,1 and 0 successively.
You want to specify i in 0 to 2**A-tb'length-1 or i in 0 to 63 to get all 64 possible A_tb 'binary' values.
(A_tb'length = 6, 2**6-1 = 63, where ** is the exponentiation operator, 2 to the 6th power minus 1 equals 63)
I found two syntax errors in your test bench, 20ns where the standard requires a space between 20 and ns:
constant period: time := 20 ns;
And entity ent where that should either be just ent (you have a component declaration ent) or entity work.ent and no need for a component declaration:
uut: ent port map(A=>A_tb, B=>B_tb);
or
uut: entity work.ent port map(A=>A_tb, B=>B_tb);
And in keeping with Russell's answer there is no implied logic replication in a loop other than through synthesis which unravels loop iterations by paralleling logic (the replication). Not all loop statements are intended as synthesis targets.
Test benches are generally not synthesized and are used to write tests (as in your case) for a VHDL model that might be used as a synthesis target.
First, loops are just fine, and common, in testbenches. #Russell's comment applies to RTL code. You can adapt his approach for this problem and make it work. You would need to use 64 as a sentinel (ending) value and do your end of test checks then. Keep in mind though that the most important thing you do is code for readability. Test cases generally run from top to bottom of a process one time.
You loop has some issues in addition to the recommendations #DavidKoontz gave. Specifically,
Your assertion is should not be checked when you expect B to be 0.
Using numeric_std_unsigned (requires VHDL-2008 compile switch) will simplify your conversions.
Keep an error count so you can report pass or failed at the end.
Keep your constants in the architecture or a package
So the modified code is:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std_unsigned.all;
entity tb is
end tb;
architecture arch_tb of tb is
constant period: time := 20 ns;
...
begin
...
tb: process
variable ErrorCount :
begin
for i in i in 0 to 2**A-tb'length-1
A_tb <= to_slv(i,6);
wait for period;
if i >= 30 and i <= 35 then
if B_tb /= 3 then
ErrorCount := Error Count + 1 ;
report "B_tb = " & to_string(B_tb) & " Expecting: 0011" severity ERROR ;
end if;
else
if B_tb /= 0 then
ErrorCount := Error Count + 1 ;
report "B_tb = " & to_string(B_tb) & " Expecting: 0000" severity ERROR ;
end if;
end loop;
if ErrorCount = 0 then
report "Test Passed" severity NOTE ;
else
report "Test FAILED. There were " & to_string(ErrorCount) & " Errors " severity NOTE;
end if;
std.env.stop(0) ; -- testbench stops here
end process;
Note that the rules about using (or forbidding usage of) numeric_std_unsigned do not apply to testbenches.
You really should not be using a for loop for this. For loops in VHDL are used to REPLICATE LOGIC, not to do something some number of times. Try something like this in your test bench:
signal r_CLOCK : std_logic := '0';
signal r_INDEX : unsigned(5 downto 0) := (others => '0');
begin
r_CLOCK <= not r_CLOCK after period/2;
process (r_CLOCK)
begin
if rising_edge(r_CLOCK) then
r_INDEX <= r_INDEX + 1;
end if;
end process;
Now simply cast r_INDEX as std_logic_vector and pass it to your ent component.
I am currently doing a project in VHDL and since I am not an expert I am having some problems.
I'll try to clarify everything. So let's split in parts.
What I am trying to do is to write certain values in two different RAM memories and then reading from them and storing different values into an array which would be used by a different block to perform MAC filtering.
Here is the RAM code that I am using (is a modification of the code provided by Weijun Zhang) I don't know if I have to post the link here. If somebody needs it 'll post it
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
--------------------------------------------------------------
entity SRAM is
generic( width: integer:=32;
depth: integer:=1024;
addr: integer:=10);
port( clk: in std_logic;
enable: in std_logic;
read_en: in std_logic;
write_en: in std_logic;
read_addr: in std_logic_vector(addr-1 downto 0);
write_addr: in std_logic_vector(addr-1 downto 0);
Data_in: in std_logic_vector(width-1 downto 0);
Data_out: out std_logic_vector(width-1 downto 0)
);
end SRAM;
--------------------------------------------------------------
architecture behav of SRAM is
-- use array to define the bunch of internal temporary signals
type ram_type is array (0 to depth-1) of std_logic_vector(width-1 downto 0);
signal tmp_ram: ram_type:= ((others=> (others=>'0')));
begin
-- read_en Functional Section
process(clk, read_en)
begin
if (clk'event and clk='1') then
if enable='1' then
if read_en='1' then
-- buildin function conv_integer change the type
-- from std_logic_vector to integer
Data_out <= tmp_ram(conv_integer(read_addr));
else
Data_out <= (Data_out'range => 'Z');
end if;
end if;
end if;
end process;
-- write_en Functional Section
process(clk, write_en)
begin
if (clk'event and clk='1') then
if enable='1' then
if write_en='1' then
tmp_ram(conv_integer(write_addr)) <= Data_in;
end if;
end if;
end if;
end process;
end behav;
This RAM code works fine, I can't attach images because I don't have enough reputation (this somehow sounds familiar to me...)
What I wanted to explain with the image, is that at the same moment that I set an address to read, the output value is the value contained in that address.
Now let´s move to the actual problem:
What I am trying to do is to create a block with two of these RAM memories. One of this RAM is used to store the values of the input to be filtered, and the other one is to store the values of the filter coefficients. So the execution would be something like this:
Write only input coefficient into its dedicated memory (address from 1 to 1024)
Write all the new coefficients into their memory (again address from 1 to 1024)
Read from both memories one coefficient and one input value (staring from address 1) and store them in two arrays (in this case array of 4 vectors)
Fill up the arrays (3 cycles more in step 3)
Once the array is full perform the filtering with 4 input values and 4 coefficients (still not implemented)
Start again point 3
I'll try to save all the space that I can removing several lines (initialization and port declaration)
library IEEE; -- declare the library
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
library work;
use work.mypackage.all; -- use of mypackage to use arrays as inputs
entity MAC_1024 is
port( clk: in std_logic;
enable: in std_logic;
enable_MAC: in std_logic;
rst: in std_logic;
read_input_en: in std_logic;
write_input_en: in std_logic;
read_coeff_en: in std_logic;
write_coeff_en: in std_logic;
X: in std_logic_vector(31 downto 0);
W: in std_logic_vector(31 downto 0);
Yt: out std_logic_vector(31 downto 0);
Yn: out std_logic_vector(31 downto 0)
);
end MAC_1024;
Now declaration of two RAMs
input_RAM: SRAM generic map (width=> t_width, depth=> t_depth, addr=> t_addr)
port map (clk, enable, read_input_en, write_input_en,read_input_addr, write_input_addr, X, saved_input);
coeff_RAM: SRAM generic map (width=> t_width, depth=> t_depth, addr=> t_addr)
port map (clk, enable, read_coeff_en, write_coeff_en,read_coeff_addr, write_coeff_addr, W, saved_coeff);
Here comes the process (the constant one has the value "0000000001")
process (clk, write_input_en, write_coeff_en)
begin
if (clk'event and clk='1') then
if (write_coeff_en='1') then
write_coeff_addr <= cont2;
cont2 <= unsigned(cont2) + unsigned(one);
end if;
if (write_input_en='1') then
i:=0;
write_input_addr <= cont1;
cont1 <= unsigned(cont1) + unsigned(one);
end if;
if (read_input_en='1' and read_coeff_en='1') then
read_input_addr <= cont3;
read_coeff_addr <= cont4;
X_in(i) <= saved_input;
W_in(i) <= saved_coeff;
cont3 <= unsigned(cont3) + unsigned(one);
cont4 <= unsigned(cont4) + unsigned(one);
X_in(i) <= saved_input;
W_in(i) <= saved_coeff;
i:=i+1;
if(i=4) then
i:=0;
end if;
end if;
end if;
end process;
Yn <= X_in(0);
Yt <= saved_input;
As you can see I am using the variable i to start in 0 and be filling up the arrays X_in and W_in. When the value is 4 then the position to place in that array goes back to 0.
The outputs Y_n and Y_t are used to test the functionality. Y_n outputs the value stored in X_in[0] and Y_t the output value of the RAM of the coefficients
So let's say to keep it simple that I have a sequence of input values (X) that is 1,2,3,4....1024 and each of these values are stored in address 1,2,3,4....1024
I would expect to be placing the values in the array following the next sequence:
X_in [Z Z Z 1]
X_in [Z Z 2 1]
X_in [Z 3 2 1]
X_in [4 3 2 1]
X_in [4 3 2 5]
X_in [4 3 6 5]
...
(when read enable is active)
The output Y_n (which reads X_in[0]) would be 1 1 1 1 5 5 5 5 9 9 9 9...
and the output Y_t (which reads RAM output) would be 1 2 3 4 5 6 7 8 9 ...
but what I obtain instead is
Y_n Z Z Z Z 4 4 4 4 8 8 8 8....
Y_t 1 2 3 4 5 6 7 8 9 ... (which is expected)
It looks like a problem with the index i (if read output the value X_in[1] I obtain the values that would correspond to my expected X_in[0] ), but if it was that in the same moment that I obtain in Y_t the value 4 I should obtain the value 4 in Y_n but i still got the previous Z. (bold)
The same happens to the array W_in...
Frankly I am kind of lost, I dont know if there is a problem with i, with delay or with what.
I have tried to be clear but I can understand that is a problem rather complicated to explain
Thank you very much for the help
Update 1:
I don't want to reset the address counters because I want to write in sequential addresses from 1 to 1024. Since the address depth is 1024 is 10 bits i am adding to the address the constant one which is a constant with 10 bits ("0000000001"). Once "1111111111" is reached the next address would be "0000000000". The code right now is prepared for a 1024 FIR filter, later i would try to do more flexible. Also i just want to add one value of input values to the memory but 1024 new coefficients every filter cycle, so the counter for coefficient could be reset after writing operation, but i dont reset the counter for input values because i need to know where i will store this value.
Update 2: I have been reading that the data output appears some cycles after you set the address to read in RAM (normally one cycle). That would be a possible cause for my problem but then why is my RAM code working without any delay???
You shouldn't drive i in two other if statements. Try to Change to if...elseif. Maybe it's not a reason of your bug but it's a basic rule.