Read and Write 2d array in BRAM VHDL - vhdl

I want to sort an array of length 16 having 8 bit numbers. I have used bubblesort for it and it's working fine.
Now I want to read the input array from BRAM and write the sorted output to BRAM. I have used Single Port RAM for testbench and here is how it looks.
library IEEE;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity testbench is
end testbench;
architecture Behavioral of testbench is
--temporary signal declarations.
signal ena : std_logic := '0';
signal wea : std_logic_VECTOR(0 downto 0):="0";
signal addra,dina,douta : std_logic_VECTOR(7 downto 0) := (others => '0');
signal clk : std_logic := '0';
begin
--Instantiating BRAM.
BRAM : entity work.BRAM_test
port map(
clka => clk, --clock for writing data to RAM.
ena => ena, --Enable signal.
wea => wea, --Write enable signal for Port A.
addra => addra, --8 bit address for the RAM.
dina => dina, --8 bit data input to the RAM.
douta => douta); --8 bit data output from the RAM.
--Simulation process.
process(clk)
begin
addra <= X"00"; --reset the address value for reading from memory location "0"
end process;
--Clock generation - Generates 500 MHz clock with 50% duty cycle.
process
begin
clk <= '1';
wait for 1 ns; --"ON" time.
clk <= '0';
wait for 1 ns; --"OFF" time.
end process;
end Behavioral;
I am unable to do that. Please help me.

you can do something like the attached code below. it's a process going through the states to read the BRAM content, to sort the data (you can add the logic for the sorting) and to write the results back.
gen_reset: process
begin
reset<='1';
wait for 50 ns;
reset<='0';
wait;
end process gen_reset;
gen_bram_access: process(clk, reset)
type state_t is (read_bram, sort, write_bram, end_state);
type buf_t is array(255 downto 0) of std_logic_vector(7 downto 0);
variable buf: buf_t;
variable state: state_t;
begin
if reset='1' then
addra<=X"00";
buf:=(others=>(others => '0'));
ena<='1';
wea<="0";
state:=read_bram;
elsif rising_Edge(clk) then
-- defaults
ena<='1';
wea<="0";
case state is
-- readout
when read_bram =>
if addra<X"FF" then --expected that X"FF" is last address
buf(to_integer(unsigned(addra))):=dina;
state:=read_bram;
addra<=std_logic_vector(unsigned(addra) + 1);
else
addra<=X"00";
state:=sort;
end if;
-- sort with whatever algo
when sort =>
-- add algo here! when finished, write results!
state:=write_bram;
-- write sorted to bram
when write_bram =>
if addra<X"FF" then --expected that X"FF" is last address
douta<=buf(to_integer(unsigned(addra)));
wea<="1";
state:=write_bram;
addra<=std_logic_vector(unsigned(addra) + 1);
else
addra<=X"00";
state:=end_state;
end if;
when others => -- (end_state)
state:=end_state;
end case;
end if;
end process gen_bram_access;

Related

VHDL counter simulated using a test bench giving 'Uninitialized' for the output, how is this resolved?

Below is a counter that is designed to represent an 8 bit binary number with 8 LEDs, it is being simulated using a test bench, however when running the simulation the output simply shows UU for the led.
Here is the main entity that I wish to test:
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_unsigned.all;
entity Lab_3_Source_File is
generic(N_BITS : integer := 8);
port(
btnd : in STD_LOGIC ;
clk : in STD_LOGIC;
led : out STD_LOGIC_VECTOR(7 downto 0)
);
end Lab_3_Source_File;
architecture counter of Lab_3_Source_File is
signal count: STD_LOGIC_VECTOR(7 downto 0);
begin
process(clk, btnd)
begin
if btnd = '1' then
count <= (others => '0');
elsif rising_edge(clk) then
count <= count + 1;
end if;
end process;
led <= count;
end counter;
Here is the test bench that I have tried to map to the main entity:
use IEEE.STD_LOGIC_1164.ALL;
entity Count_TestBench is
end Count_TestBench;
architecture Behavioral of Count_TestBench is
signal btnd, clk : STD_LOGIC;
signal led : STD_LOGIC_VECTOR(7 downto 0);
begin
UUT : entity work.Lab_3_Source_File port map (btnd => btnd,clk => clk,led => led);
process
begin
btnd<='1';
wait for 1 ns;
btnd<='0';
led<= (others => '0');
for i in 1 to 100 loop
clk<='1';
wait for 10 ns;
clk<='0';
wait for 10 ns;
led<=led;
end loop;
end process;
end Behavioral;
Please could somebody help me understand how to enable the simulation to display the led output incrementing?
EDIT:
Set btnd to 1 with a 1ns wait in the test bench to initialise the led, following the answer from mkrieger1, the led output is still at U following this change.
count is not initialized inside Lab_3_Source_File until btnd is set to '1', which it isn't in the testbench.
Since the led output is driven by count, it is also uninitialized. The uninitialized value of the led output of Lab_3_Source_File is then assigned to the led signal in the testbench.
So, to fix this, you need to set btnd to '1' once for a non-zero duration in the testbench, before setting it to '0' again (otherwise led is held at "00000000" constantly).

Read/writing to array of vectors with clock rising edge and read/write enable signal

I am trying to create a simple memory that stores vectors whenever the clock is 1 and wrenable is 1 (and likewise for reading), but unfortunately I've been facing timing issues:
Source:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY test_memdata IS
PORT (
address, data : IN std_logic_vector(31 DOWNTO 0) := (OTHERS => '0');
wrenable, clock, rdenable : IN std_logic := '0';
readout : OUT std_logic_vector(31 DOWNTO 0)
);
END test_memdata;
ARCHITECTURE arch OF test_memdata IS
TYPE ram_type IS ARRAY(0 TO 31) OF std_logic_vector(31 DOWNTO 0);
SIGNAL ram_block : ram_type;
BEGIN
process(clock, wrenable, address)
variable write_addr : integer;
variable write_en, read_en : std_logic;
begin
write_en := wrenable;
read_en := rdenable;
write_addr := to_integer(unsigned(address));
if rising_edge(clock) then
if write_en = '1' then
ram_block(write_addr) <= data;
elsif read_en = '1' then
readout <= ram_block(write_addr);
end if;
end if;
end process;
END arch;
Modelsim Testbench
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY memdata_test IS
END memdata_test;
ARCHITECTURE arch OF memdata_test IS
SIGNAL address, data : std_logic_vector(31 DOWNTO 0) := (OTHERS => '0');
SIGNAL wrenable, clock, rdenable : std_logic := '0';
SIGNAL readout : std_logic_vector(31 DOWNTO 0);
COMPONENT test_memdata IS
PORT (
address, data : IN std_logic_vector(31 DOWNTO 0) := (OTHERS => '0');
wrenable, clock, rdenable : IN std_logic := '0';
readout : OUT std_logic_vector(31 DOWNTO 0)
);
END COMPONENT test_memdata;
BEGIN
uut : test_memdata PORT MAP(
address => address,
data => data,
wrenable => wrenable,
rdenable => rdenable,
clock => clock,
readout => readout
);
PROCESS
BEGIN
address <= (OTHERS => '0');
data <= (OTHERS => '1');
WAIT FOR 200 ns;
clock <= '1';
wrenable <= '1';
WAIT FOR 200 ns;
clock <= '0';
wrenable <= '0';
WAIT FOR 200 ns;
clock <= '1';
rdenable <= '1';
WAIT FOR 200 ns;
REPORT "end";
WAIT;
END PROCESS;
END arch;
In ModelSim, this testbench works as expected:
But in Quartus, it doesn't work as expected for some reason:
But if I extend the rden and wren before the clock signal rising edges, it works:
I've been at this for a very long time, and would really appreciate some insight as to how I would be able to make the read/write happen when both wrenable/rdenable and clock are positive edged at the same time.
Thank you.
ModelSim-Altera 10.1d, Quartus version 13.0sp1
Your memory model is wrong, you should only use one event which is the clock edge so remove the wrenable and address from your process sensitivity list, there is also no need for the 3 variables.
Good luck,
Hans.

Read, then write RAM VHDL

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.

array of signals in VHDL?

i'm trying to define a 4096*16 RAM, i did like this:
entity Test is
port(
...
IR : inout std_logic_vector(15 downto 0);
AR : inout std_logic_vector(11 downto 0));
end test
architecture test1 of test is
type ram is array(4095 downto 0) of std_logic_vector(15 downto 0);
signal ram1 : ram := (others => (others => '0'));
begin
AR <= "000000000000";
ram1(0) <= "0010000000000100";
...
...
process(arguments)
IR <= ram1(conv_integer(AR));
my problem is, when i give ram1 values, and then give ram1 values to an output port, its ones (1s) become Unknown (X) in Isim
i get "00X000000X00" for IR in isim
Here is a synchronous design for your RAM entity:
library IEEE;
use IEEE.std_logic_1164.all;
USE ieee.numeric_std.ALL;
entity Test is
port(
clock : in std_logic; -- clock
IR : inout std_logic_vector(15 downto 0); -- data port
AR : in std_logic_vector(11 downto 0); -- address port
write_enable : in std_logic -- '1' -> write, '0' -> read
);
end test;
architecture test1 of Test is
type ram is array(0 to 4095) of std_logic_vector(15 downto 0);
-- the actual ram
signal ram1 : ram := (others => (others => '0'));
-- internal signal for reading data
signal IR_out : std_logic_vector(15 downto 0) := (others => 'Z');
begin
-- only apply our own signal to the data port
-- during read
IR <= IR_out when write_enable = '0' else (others => 'Z');
proc: process(clock) is
begin
if rising_edge(clock) then
if write_enable = '1' then
-- write to RAM
ram1(to_integer(unsigned(AR))) <= IR;
else
-- read from RAM
IR_out <= ram1(to_integer(unsigned(AR)));
end if;
end if; -- rising edge
end process;
end; -- architecture
and here is a testbench for it:
library IEEE;
use IEEE.std_logic_1164.all;
entity Testbench is
end Testbench;
architecture TB of Testbench is
component Test
port(
clock : in std_logic; -- clock
IR : inout std_logic_vector(15 downto 0); -- data port
AR : in std_logic_vector(11 downto 0); -- address port
write_enable : in std_logic -- '1' -> write, '0' -> read
);
end component;
-- define signals
signal clock : std_logic := '0';
-- our internal signals
signal IRtest : std_logic_vector(15 downto 0) := (others => 'Z');
signal ARtest : std_logic_vector(11 downto 0) := (others => '0');
signal write_enable_test : std_logic := '0';
begin
-- Instantiate a RAM to be tested and connect it to our signals
uut: Test PORT MAP (
clock => clock,
AR => ARtest,
IR => IRtest,
write_enable => write_enable_test
);
-- clock generator (10 MHz)
clockgen : process
begin
clock <= '0';
wait for 50ns;
clock <= '1';
wait for 50ns;
end process;
-- generate signals to test the RAM
stimulus : process
begin
-- write data into ram
ARtest <= "000000000000";
IRtest <= "0010000000000100";
write_enable_test <= '1';
wait for 100 ns;
-- read a different address back from RAM
ARtest <= "000000000001";
IRtest <= (others => 'Z');
write_enable_test <= '0';
wait for 100 ns;
-- read the original address back from ram
ARtest <= "000000000000";
IRtest <= (others => 'Z');
write_enable_test <= '0';
wait for 100 ns;
wait;
end process;
end; -- architecture
The testbench essentially writes the value to the RAM in the first clock cycle, reads a different address in the second clock cycle and then reads the contents of the original address in the third clock cycle.
The waveform output for the testbench is:
Note that you'll get the contents of the ram at the output port of the RAM entity only on the next rising edge of the clock cycle.
You can fiddle with the design and testbench here: http://www.edaplayground.com/x/5w8
I saw also an asynchronous (not using if rising_edge(clock)) example here: http://www.edaplayground.com/x/3Zs
When using ISim, I assume you use Xilinx FPGA. In that case, take a looks at the Xilinx, HDL Coding Practices for inferring different kind of elements, e.g. RAMs.
Also, only use inout at the toplevel of the design, and even if the RAM is at the top level, then separate the inout from the RAM, so the synthesis tool can implement the different parts of the design, like IO elements and RAMs, correctly.
An example of coding style for inferred RAM, based on the above paper, is:
process (clk)
begin
if (rising_edge(clk)) then
if (we = '1') then
mem(conv_integer(addr)) <= di ;
else
do <= mem(conv_integer(addr));
end if;
end if;
end process;

VHDL code does not synthesize

I have written 2 state machines in my VHDL code. The simulation works fine, but the code does not synthesize. Any help would be appreciated. Here is my code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_arith.ALL;
use IEEE.STD_LOGIC_unsigned.ALL;
use IEEE.NUMERIC_STD.ALL;
entity pulse_width is
Port ( clk : in STD_LOGIC;
timer2:in std_logic;
input: in STD_LOGIC;
result: inout STD_LOGIC_VECTOR (15 downto 0);
SEL_LINE: IN STD_LOGIC_VECTOR(5 DOWNTO 0);
data_out: out STD_LOGIC_VECTOR (23 downto 0):=x"000000");
end pulse_width;
architecture Behavioral of pulse_width is
TYPE count_states is (s0,s0_dash,s1,s2,s3,s1_dash);
SIGNAL current_state, next_state : count_states := s0 ;
TYPE write_states is (ws0,ws0_dash,ws1,ws2,ws3,ws4);
SIGNAL current_state1, next_state1 : write_states := ws0 ;
TYPE index_array is ARRAY(integer range 0 to 65535) of std_logic_vector(15 downto 0);
SIGNAL mem: index_array;
SIGNAL count: std_logic_vector(15 downto 0):=x"0000";
SHARED VARIABLE j: integer:=0;
SHARED VARIABLE a,i: integer:=1;
SIGNAL flag,push_data,push_first,push_final,push_pulses,rw_first,rw_end: std_logic:='0';
SIGNAL y_clk_input ,y_clk_timer2, enable_count: std_logic:='0';
SIGNAL first,final: std_logic_vector(15 downto 0):= x"0001";
begin
-- Pulse width count
process (clk)
begin
if rising_edge(clk) then
current_state<=next_state;
current_state1<=next_state1;
end if;
end process;
process(input,SEL_LINE,current_state)
begin
------------------------------------------------------------------------
case current_state is
when s0 =>
if(input='1') then
next_state<=s1;
else
next_state<=s0;
end if;
when s1 =>
flag<='0';
if input='1' then
count <= count+ x"0001";
next_state<=s1_dash;
else
next_state<=s2;
end if;
when s1_dash =>
if input='1' then
count <= count+ x"0001";
next_state<=s1;
else
next_state<=s2;
end if;
when s2 =>
result <= count;
next_state<=s3;
when s3=>
count <= x"0000";
next_state<=s0;
enable_count<='0';
when others =>
next_state<=s0;
end case;
--------------------------------------------------------------------------
case current_state1 is
when ws0 =>
if (result>x"0000") then
next_state1<=ws1;
else
next_state1<=ws0_dash;
end if;
when ws0_dash =>
if (result>x"0000") then
next_state1<=ws1;
else
next_state1<=ws0;
end if;
when ws1=>
if rw_first='1' and rw_end='1' then
next_state1<=ws0;
else
mem(a) <= result;
a:=a+1;
final<=final+x"0001";
next_state1<=ws2;
end if;
when ws2 =>
next_state1<=ws0;
result<=x"0000";
when others =>
next_state1<=ws0;
end case;
end process;
I eventually need to implement three state machines.
The math you're trying to do in the asynchronous state logic is not registered and won't synthesize well. You need to re-arrange your state logic so statements like:
count <= count+ x"0001";
...
final<=final+x"0001";
...are synchronous and not 'free running' in an asynchronous loop.
The problem is that you read and write the same signals in one combinational process.
Either put everything in one clocked (synchronous) process
Or: use explicit registers: count_next <= count + x"0001";
Not related to your error, but still worth paying attention to:
You have a ton of unused signals and shared variables:
push_data,push_first,push_final,push_pulses, y_clk_input ,y_clk_timer2, first, i,j
This is confusing for anybody trying to read your code. 1
The packages STD_LOGIC_arith and STD_LOGIC_unsigned are deprecated

Resources