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;
Related
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.
This is my first time using rtl so I am having some issues which may be simple, but I have not been able to find anything that explains why this is happening and how to fix it. Currently when I create an rtl from my vhdl code, the ouputs are not shown to be connected to the rest of the design. The image below shows the outputs, not the rest of the design since it is pretty big.
The parts of my code which are relevant can be seen below:
`library IEEE;
use IEEE.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
use ieee.numeric_std.all;
entity FIFOClockOut is
port (
--Inputs
dataIn : IN std_logic_vector(7 downto 0); -- data input
clk : IN std_logic; -- clock input
EnableWr : IN std_logic; -- a value is being transmitted to the FIFO
clearMem : IN std_logic; -- clears the memory of the FIFO
resetOut : IN std_logic; -- resets the FIFO output counter
resetFull : IN std_logic; -- resets the the FIFO completely
--Outputs
MemNear : INOUT std_logic; -- the memory is almost out
FullMem : OUT std_logic; -- the memory is full in the FIFO
dataOut : OUT std_logic_vector(7 downto 0); -- data output
sel : INOUT std_logic_vector(2 downto 0); -- select output for mux
FinishedOut : OUT std_logic; -- the FIFO has finished sending out the data
clkOut : INOUT std_logic := '0' -- the clock that the output data is using
);
end FIFOClockOut;
architecture architecture_FIFOClockOut of FIFOClockOut is
-- signal, component etc. declarations
type ram_t is array (0 to 4095) of std_logic_vector(7 downto 0); -- The memory for the FIFO
signal ram: ram_t;
signal counterIn : integer; -- counter for input
signal counterOut : integer; -- counter for output
signal counterClock : std_logic_vector(2 downto 0); -- counter for clock
signal FullMemBuff : std_logic;
signal FinishedOutBuff: std_logic;
begin
process(clk)
begin
--there is some more code here which does not use dataOut
if (clk='1') then
if (FullMemBuff = '0') then
if (EnableWr = '1') then
ram(counterIn)<= dataIn;
counterIn <= counterIn + 1;
end if;
end if;
if(clkOut ='1') then
if (FinishedOutBuff = '0') then
counterClock <= counterClock + "1";
sel <= sel+"1";
end if;
if (counterClock = "111") then
if (FinishedOutBuff = '0') then
dataOut <= ram(counterOut);
counterOut <= counterOut+1;
if (counterIn <= (counterOut)) then
FinishedOutBuff <= '1';
sel<= "111";
dataOut <= "00000000";
end if;
else
dataOut <= "00000000";
sel <= "111";
end if;
end if;
end if;
end if;
end process;
end architecture_FIFOClockOut;
Thank you for the help. I am using Libero Polar Fire to code the vhdl and create the rtl. I have simulated the code and it works as expected and provides the correct output. Please ask questions if something is unclear or want more of the code.
So I fixed this by adding a buffer signal in the beginning of the code and setting the DataOut value equal to the DataOut buffer. Not quite sure why this worked, but it fixed it. If any one knows why I would love to know.
I am currently slightly confused about my simple counter.
It is implemented as follows:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity simple_counter is
port(
DOUT : out std_logic_vector(3 downto 0);
CE : in std_logic;
CLK : in std_logic;
RSTN : in std_logic
);
end simple_counter;
architecture behavioral of simple_counter is
signal temp : unsigned(3 downto 0);
begin
process(CLK)
begin
if RSTN = '0' then
temp <= (others => '0');
elsif(rising_edge(CLK)) then
if CE = '1' then
if std_logic_vector(temp) = (temp'range => '1') then
temp <= (others => '0');
else
temp <= temp + 1;
end if;
end if;
end if;
end process;
DOUT <= std_logic_vector(temp);
end behavioral;
I use the following testbench for simulation:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library std;
use std.textio.all;
use work.tools_pkg.all;
library work;
--! #class tools_tb
--! #brief Test bench for the tools_tb design
entity counter_tb is
generic (
VOID : integer := 0);
port (
void_i : in std_logic);
end entity counter_tb;
--! #brief
--! #details
architecture sim of counter_tb is
-- Clock period definitions
-- Clock, reset and baud rate definitions
constant CLK_FREQ : integer := 100_000_000;
constant clk_period : time := (1.0 / real(CLK_FREQ)) * (1 sec);
signal end_sim : boolean := false;
signal rstn : std_logic;
signal clk : std_logic;
signal s_en : std_logic := '0';
------------------------------------------------------------------------------
-- DUT signals
------------------------------------------------------------------------------
signal s_dout : std_logic_vector(3 downto 0) := (others => '0');
signal s_ce : std_logic := '0';
begin -- architecture
fifo : entity work.simple_counter
port map (
DOUT => s_dout,
CE => s_ce,
RSTN => rstn,
CLK => clk
);
-- Clock process definitions (clock with 50% duty cycle is generated here).
clk_process : process
begin
if end_sim = false then
clk <= '1';
wait for clk_period/2;
clk <= '0';
wait for clk_period/2;
else
wait;
end if;
end process;
-- Stimulus process
stim_proc: process
begin
-- startup and wait for some time
rstn <= '0';
wait for clk_period;
rstn <= '1';
wait for clk_period;
wait for clk_period;
wait for clk_period;
s_ce <= '1';
wait;
end process;
end architecture sim;
I am confused why the counter increases instantly when I set CE <= '1
(see the attached simulation).
Since the counter is implemented in a synchrous process, shouldn't it take a single clock cycle until it is increased from '0' to '1'?
Thanks a lot!
You most likely have a race condition between s_ce and clk. If you will generate the s_ce on the rising edge of clk then you should see that counter works correctly.
I don't know this simulator but to check the race you can expand deltas when counter changes 0->1
I have spent the whole day trying to solve the following problem. I am building a small averaging multichannel oscilloscope and I have the following module for storing the signal:
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.numeric_std.all;
entity storage is
port
(
clk_in : in std_logic;
reset : in std_logic;
element_in : in std_logic;
data_in : in std_logic_vector(11 downto 0);
addr : in std_logic_vector(9 downto 0);
add : in std_logic; -- add = '1' means add to RAM
-- add = '0' means write to RAM
dump : in std_logic;
element_out : out std_logic;
data_out : out std_logic_vector(31 downto 0)
);
end storage;
architecture rtl of storage is
component bram is
port
(
clk : in std_logic;
we : in std_logic;
en : in std_logic;
addr : in std_logic_vector(9 downto 0);
di : in std_logic_vector(31 downto 0);
do : out std_logic_vector(31 downto 0)
);
end component bram;
type state is (st_startwait, st_add, st_write);
signal current_state : state := st_startwait;
signal next_state : state := st_startwait;
signal start : std_logic;
signal we : std_logic;
signal en : std_logic;
signal di : std_logic_vector(31 downto 0);
signal do : std_logic_vector(31 downto 0);
signal data : std_logic_vector(11 downto 0);
begin
ram : bram port map
(
clk => clk_in,
we => we,
en => en,
addr => addr,
di => di,
do => do
);
process(clk_in, reset, start)
begin
if rising_edge(clk_in) then
if (reset = '1') then
current_state <= st_startwait;
else
start <= '0';
current_state <= next_state;
if (element_in = '1') then
start <= '1';
end if;
end if;
end if;
end process;
process(current_state, start, dump)
variable acc : std_logic_vector(31 downto 0);
begin
element_out <= '0';
en <= '1';
we <= '0';
case current_state is
when st_startwait =>
if (start = '1') then
acc(11 downto 0) := data_in;
acc(31 downto 12) := (others => '0');
next_state <= st_add;
else
next_state <= st_startwait;
end if;
when st_add =>
if (add = '1') then
acc := acc + do;
end if;
we <= '1';
di <= acc;
next_state <= st_write;
when st_write =>
if (dump = '1') then
data_out <= acc;
element_out <= '1';
end if;
next_state <= st_startwait;
end case;
end process;
end rtl;
Below is the BRAM module as copied from the XST manual. This is a no-change type of BRAM and I believe there is the problem. The symptom is that, while this simulates fine, I read only zeroes from the memory when I use the design on the device.
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
entity bram is
port
(
clk : in std_logic;
we : in std_logic;
en : in std_logic;
addr : in std_logic_vector(9 downto 0);
di : in std_logic_vector(31 downto 0);
do : out std_logic_vector(31 downto 0)
);
end bram;
architecture rtl of bram is
type ram_type is array (0 to 999) of std_logic_vector (31 downto 0);
signal buf : ram_type;
begin
process(clk, en, we)
begin
if rising_edge(clk) then
if en = '1' then
if we = '1' then
buf(conv_integer(addr)) <= di;
else
do <= buf(conv_integer(addr));
end if;
end if;
end if;
end process;
end rtl;
What follows is a description of the chip use and the expected output. "clk_in" is a 50 MHz clock. "element_in" is '1' for 20 ns and '0' for 60 ns. "addr_in" iterates from 0 to 999 and changes every 80 ns. "element_in", "data_in", and "addr" are all aligned and synchronous. Now "add" is '1' for 1000 elements, then both "add" and "dump" are zero for 8000 elements and, finally "dump" is '1' for 1000 elements. Now, if I have a test bench that supplies "data_in" from 0 to 999, I expect data_out to be 0, 10, 20, 30, ..., 9990 when "dump" is '1'. That is according to the simulation. In reality I get 0, 1, 2, 3, ..., 999....
Some initial issues to address are listed below.
The process(current_state, start, dump) in storage entity looks like it is
intended to implement a combinatorial element (gates), but the signal (port)
data_in is not in the sensitivity list.
This is very likely to cause a difference between simulation and synthesis
behavior, since simulation will typically only react to the signals in the
sensitivity list, where synthesis will implement the combinatorial design and
react on all used signals, but may give a warning about incomplete sensitivity
list or inferred latches. If you are using VHDL-2008 then use can use a
sensitivity list of (all) to have the process sensitivity to all used
signals, and otherwise you need to add missing signals manually.
The case current_state is in process(current_state, start, dump) lacks an
when others => ..., so the synthesis tool has probably given you a warning
about inferred latches. This should be fixed by adding the when others =>
with and assign all signals driven by the process to the relevant value.
The use clause lists:
use IEEE.std_logic_unsigned.all;
use IEEE.numeric_std.all;
But both of these should not be used at the same time, since they declare some
of the same identifiers, for example is unsigned declared in both. Since the
RAM uses std_logic_unsigned I suggest that you stick with that only, and
delete use of numeric_std. For new code I would though recommend use of
numeric_std.
Also the process(clk_in, reset, start) in storage entity implements a
sequential element (flip flop) sensitive to only rising edge of clk_in, so
the two last signals in sensitivity list ..., reset, start) are unnecessary,
but does not cause a problem.
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;