VHDL : how to read / write data of 16 bits in RAM with 8 bits per address - vhdl

I have a VHDL code for reading and writing data of 8 bits to a RAM with 8 bits per address, but i need to make changes to the code in order to read/write data of 16 bits to the RAM with 8 bits per address.
What changes could be done?
The initial code i have is:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity RAM is
port(address: in std_logic_vector(0 to 15);
datain: in std_logic_vector(7 downto 0);
dataout: out std_logic_vector(7 downto 0);
WE, CS, OE: in std_logic);
end entity RAM;
architecture behavior6 of RAM is
type RAM_type is array (0 to 2**16) of std_logic_vector(7 downto 0);
signal RAM1: RAM_type;
begin
process (address, CS, WE, OE)
begin
dataout <= (others => 'Z'); --chip is not selected (this is the first row of the T.T)
if (CS = '0')
then
if WE= '0' then --we want to write
RAM1(to_integer(unsigned(address))) <= datain;
end if;
if WE= '1' and OE= '0'
then--we want to read
dataout <= RAM1(to_integer(unsigned(address)));
else
dataout <= (others => 'Z');
end if;
end if;
end process;
end behavior6;

Try this code
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity RAM is
port(address: in std_logic_vector(7 down to 0);
datain: in std_logic_vector(15 downto 0);
dataout: out std_logic_vector(15 downto 0);
WE, CS, OE: in std_logic);
end entity RAM;
architecture behavior6 of RAM is
type RAM_type is array (255 down to 0) of std_logic_vector(15 downto 0);
signal RAM1:memory:=(others=>"0000000000000000");
begin
process (address, CS, WE, OE)
variable a:integer range 0 to 255;
begin
a:=conv_integer(address);
if (CS = '0')
then
if WE= '0' then
RAM1(a)<=datain;
end if;
if WE= '1' and OE= '0'
then
dataout<=RAM1(a);
end if;
end if;
end process;
end behavior6;

Related

4-bit comparator issue in vhdl

I am new to VHDL and I have an issue writing a 4-bit comparator.
When I want to compare different sets of inputs there is only one output for all of them. And I don't know how to solve this problem. I want to have only one output and need to show 0000 if A is less than B, and 1111 if A is greater than B, and 0011 if they are equal. Can anybody please help me with my problem?
Here is my code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity comp_4 is
port ( A:IN STD_LOGIC_VECTOR(3 downto 0);
B:IN STD_LOGIC_VECTOR(3 downto 0);
output:OUT STD_LOGIC_VECTOR(3 downto 0)
);
end comp_4;
architecture dataflow of comp_4 is
begin
process
begin
if (A=B) then
output <= "0011";
elsif (A>B) then
output <= "1111";
else
output <= "0000";
end if;
wait;
end process;
end dataflow;
And also my test bench:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY Comparator_test IS
END Comparator_test;
ARCHITECTURE Ctest OF Comparator_test IS
COMPONENT comp_4 IS
port( A:IN STD_LOGIC_VECTOR(3 downto 0);
B:IN STD_LOGIC_VECTOR(3 downto 0);
output:OUT STD_LOGIC_VECTOR(3 downto 0)
);
END COMPONENT;
SIGNAL a : STD_LOGIC_VECTOR(3 downto 0);
SIGNAL b : STD_LOGIC_VECTOR(3 downto 0);
SIGNAL c : STD_LOGIC_VECTOR(3 downto 0);
BEGIN
uut : comp_4 PORT MAP(a, b , c);
a <= "0100" , "1111" After 10 NS;
b <= "0101" , "1100" AFTER 10 NS;
END Ctest;
And my simulation looks like this:
You need to put the inputs on the sensitivity list.
Note, wait; stops the process infinitely (only in simulation, it cannot be synthesized).
Solution 1:
Use the process' sensitivity list, and remove wait;.
architecture dataflow of comp_4 is
begin
process(A, B)
begin
if (A = B) then
output <= "0011";
elsif (A > B) then
output <= "1111";
else
output <= "0000";
end if;
end process;
end dataflow;
Solution 2:
Use the sensitivity list of wait.
architecture dataflow of comp_4 is
begin
process
begin
if (A = B) then
output <= "0011";
elsif (A > B) then
output <= "1111";
else
output <= "0000";
end if;
wait on A, B;
end process;
end dataflow;

Refilling Ram vhdl

After writing to each address of Ram and then reading every address of Ram, how would I reinitialize the Ram so that when I write to it again a second time it starts off as if it were the first time writing to it or in other words a clean slate.
Breakdown:
1) write to RAM
2) read from Ram
3) set all ram values back to 0? or can I just go ahead and provide address = 0 begin writing from 0-23 again?
Here is my Ram:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;
entity Ram is
Port(
clk : in std_logic;
address : in std_logic_vector(4 downto 0);
write_en : in std_logic;
data_in : in std_logic_vector(15 downto 0);
data_out : out std_logic_vector(15 downto 0)
);
end Ram;
architecture Behavioral of Ram is
type ram_type is array(0 to 23) of std_logic_vector(15 downto 0);
signal Memory : ram_type;
begin
process(clk)
begin
if(rising_edge(clk)) then
if(write_en = '1') then
Memory(to_integer(unsigned(address))) <= data_in;
end if;
data_out <= Memory(to_integer(unsigned(address)));
end if;
end process;
end behavioral;
If you are intending to infer BRAMs in your device it cannot be reset. reset BRAMs is done as part of device configuration. You can always write zeroes (or whetever your initial state is back to the Memory to reinitialize)
However, if you don't care whether it will be synthesized into BRAMs I think the most clean way of doing this is adding a reset port to your system and change your process to take the reset into account. When you want to reset the memory you apply a reset at the input port.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;
entity Ram is
Port(
clk : in std_logic;
rstn : in std_logic;
address : in std_logic_vector(4 downto 0);
write_en : in std_logic;
data_in : in std_logic_vector(15 downto 0);
data_out : out std_logic_vector(15 downto 0)
);
end Ram;
architecture Behavioral of Ram is
type ram_type is array(0 to 23) of std_logic_vector(15 downto 0);
signal Memory : ram_type;
begin
process(clk)
begin
if(rising_edge(clk)) then
if(rstn ='0') then
Memory <= (OTHERS => (OTHERS => '0'));
elsif(write_en = '1') then
Memory(to_integer(unsigned(address))) <= data_in;
end if;
data_out <= Memory(to_integer(unsigned(address)));
end if;
end process;
end behavioral;
An additional remark on your code example. If you intend to infer BRAMs your code is "read-before-write". This will result in slower BRAM performance according to WP231 (https://www.xilinx.com/support/documentation/white_papers/wp231.pdf)

ModelSim - Unable To Simulate Button Presses

I want to use four push buttons as inputs and three seven-segment LED displays as outputs. Two push buttons should step up and down through the sixteen RAM locations; the other two should increment and decrement the contents of the currently-displayed memory location. I have the following two entities:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity DE2_TOP is
port (
KEY : in std_logic_vector(3 downto 0); -- Push button
CLOCK_50: in std_logic;
);
end DE2_TOP;
architecture datapath of DE2_TOP is
begin
U1: entity work.lab1 port map (
key => key,
clock => clock_50,
);
end datapath;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity raminfr is -STANDARD RAM INFERENCE
port (
clock: in std_logic;
we : in std_logic;
a : in unsigned(3 downto 0);
di : in unsigned(7 downto 0);
do : out unsigned(7 downto 0)
);
end raminfr;
architecture rtl of raminfr is
type ram_type is array (0 to 15) of unsigned(7 downto 0);
signal RAM : ram_type;
signal read_a : unsigned(3 downto 0);
begin
process (clock)
begin
if rising_edge(clock) then
if we = '1' then
RAM(to_integer(a)) <= di;
end if;
read_a <= a;
end if;
end process;
do <= RAM(to_integer(read_a));
end rtl;
and
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity lab1 is
port(
clock : in std_logic;
key : in std_logic_vector(3 downto 0);
);
end lab1;
architecture up_and_down of lab1 is
signal value_in_ram : unsigned(7 downto 0);
signal we : std_logic;
signal value_counter : unsigned(7 downto 0) ;
signal register_counter : unsigned(3 downto 0);
begin
U1: entity work.raminfr port map (
a => register_counter,
di => value_counter,
do => value_in_ram,
clock => clock,
we => we
);
process(clock)
begin
if rising_edge(clock) then
if (key(3)='0' and key(2)='0' and key(1)='1' and key(0)='0') then
value_counter <= value_counter + "1";
elsif (key(3)='0' and key(2)='0' and key(1)='0' and key(0)='1') then
value_counter <= value_counter - "1";
elsif (key(3)='1' and key(2)='0' and key(1)='0' and key(0)='0') then
register_counter<= register_counter + "1";
value_counter <= value_in_ram;
elsif (key(3)='0' and key(2)='1' and key(1)='0' and key(0)='0') then
register_counter<= register_counter - "1";
value_counter <= value_in_ram;
end if;
end if;
end process;
end architecture up_and_down;
I also have the following test bench, where I try to simulate buttons being pressed via KEY:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity DE2_TOP_TEST is
end;
architecture BENCH of DE2_TOP_TEST is
signal KEY : std_logic_vector(3 downto 0);
signal CLOCK_50 : std_logic := '0';
signal hex4, hex5, hex6 : std_logic_vector(6 downto 0);
begin
clock_50 <= not clock_50 after 50 ns;
process
begin
KEY<="0010";
wait for 1 us;
KEY<="0000";
end process;
uut:work.DE2_TOP port map (
KEY=>key,
CLOCK_50=>clock_50,
hex4=>hex4,
hex5=>hex5,
hex6=>hex6
);
end BENCH;
My test bench set up looks like this:
To simulate, I compile all three of the above files, and then simulate DE2_TOP_TEST, but am met with the result that my "KEY" is still undefined, as below (although CLOCK_50 does get the default value that I set):
Anyone know what's causing this?
(1) You have unconnected ports on the entity you are typing to test. The test results are as expected for those inputs - specifically, clk, being undriven.
(2) Having connected clk, you will need to drive it.
signal clk : std_logic := '0';
and
clk <= not clk after 50 ns;
should give a 10MHz clock, check this in the simulator
(3) Drive "KEY" with a specific sequence of values
subtype keys is std_logic_vector(3 downto 0);
constant count_up : keys := "0001";
constant count_dn : keys := "0010";
constant idle : keys := "0000";
-- etc
process
begin
KEY <= count_up;
wait for 1 us;
KEY <= idle;
wait for ...
-- etc
end process;
(4) Bring the OUTPUTS back out into the testbench so that you can check their values. You need to bring them out as ports in the top level (design) entity anyway, if you are going to connect them to a display!
Then (later, once things have started going to plan) you can test them in the testbench process...
wait for 100 ns;
-- after the last press, we should have "07" on the display
assert digit(1) = "0111111" report "Left digit has wrong value" severity ERROR;
assert digit(0) = "0000111" report "Left digit has wrong value" severity ERROR;
A self-checking testbench like this saves debugging by staring at waveforms. You only need the waveforms when the tests are failing...

VHDL setting constant data in RAM

Recently i'm using VHDL to write a 16-but RAM. My code is:
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 RAM is
port(
PC_in: in std_logic_vector (5 downto 0);
EN_WR_in: in std_logic_vector (1 downto 0);
RAM_in : in std_logic_vector(15 downto 0);
RAM_out : out std_logic_vector(15 downto 0);
test : out integer
);
end RAM;
architecture Behavioral of RAM is
type ram_t is array (63 downto 0) of std_logic_vector(15 downto 0);
signal ram : ram_t;
begin
PROCESS (EN_WR_in)
BEGIN
if (EN_WR_in(1)='1') then
IF (EN_WR_in(0) = '1') THEN
ram(conv_integer(unsigned(PC_in))) <= RAM_in;
else
RAM_out <= ram(conv_integer(unsigned(PC_in)));
end if;
else
RAM_out <="ZZZZZZZZZZZZZZZZ";
end if;
END PROCESS;
ram(20) <= "0000100010010000";
end Behavioral;
The problem that i facing with is i need to set some constant data in the ram just like
ram(20) <= "0000100010010000";
But the constant data didn't exist during simulation. Is there any way to solve it?
Thanks.
You can initialize the ram when you declare it:
signal ram : ram_t := ( "0000100010010000", x"1234", ... );
or perhaps
signal ram : ram_t := ( 20 => "0000100010010000", others => (others=>'0') );

Can anyone help me with this VHDL code (currently malfunctioning)?

This code should be (and is) very simple, and I don't know what I am doing wrong.
Here is description of what it should do:
It should display a number on one 7-segment display. That number should be increased by one every time someone presses the push button. There is also reset button which sets the number to 0. That's it. Here is VHDL code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity PWM is
Port ( cp_in : in STD_LOGIC;
inc : in STD_LOGIC;
rst: in std_logic;
AN : out STD_LOGIC_VECTOR (3 downto 0);
segments : out STD_LOGIC_VECTOR (6 downto 0));
end PWM;
architecture Behavioral of PWM is
signal cp: std_logic;
signal CurrentPWMState: integer range 0 to 10;
signal inco: std_logic;
signal temp: std_logic_vector (3 downto 0);
begin
--cp = 100 Hz
counter: entity djelitelj generic map (CountTo => 250000) port map (cp_in, cp);
debounce: entity debounce port map (inc, cp, inco);
temp <= conv_std_logic_vector(CurrentPWMState, 4);
ss: entity decoder7seg port map (temp, segments);
process (inco, rst)
begin
if inco = '1' then
CurrentPWMState <= CurrentPWMState + 1;
elsif rst='1' then
CurrentPWMState <= 0;
end if;
end process;
AN <= "1110";
end Behavioral;
Entity djelitelj (the counter used to divide 50MHz clock):
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity PWM is
Port ( cp_in : in STD_LOGIC;
inc : in STD_LOGIC;
rst: in std_logic;
AN : out STD_LOGIC_VECTOR (3 downto 0);
segments : out STD_LOGIC_VECTOR (6 downto 0));
end PWM;
architecture Behavioral of PWM is
signal cp: std_logic;
signal CurrentPWMState: integer range 0 to 10;
signal inco: std_logic;
signal temp: std_logic_vector (3 downto 0);
begin
--cp = 100 Hz
counter: entity djelitelj generic map (CountTo => 250000) port map (cp_in, cp);
debounce: entity debounce port map (inc, cp, inco);
temp <= conv_std_logic_vector(CurrentPWMState, 4);
ss: entity decoder7seg port map (temp, segments);
process (inco, rst)
begin
if inco = '1' then
CurrentPWMState <= CurrentPWMState + 1;
elsif rst='1' then
CurrentPWMState <= 0;
end if;
end process;
AN <= "1110";
end Behavioral;
Debouncing entity:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_ARITH.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
ENTITY debounce IS
PORT(pb, clock_100Hz : IN STD_LOGIC;
pb_debounced : OUT STD_LOGIC);
END debounce;
ARCHITECTURE a OF debounce IS
SIGNAL SHIFT_PB : STD_LOGIC_VECTOR(3 DOWNTO 0);
BEGIN
-- Debounce Button: Filters out mechanical switch bounce for around 40Ms.
-- Debounce clock should be approximately 10ms
process
begin
wait until (clock_100Hz'EVENT) AND (clock_100Hz = '1');
SHIFT_PB(2 Downto 0) <= SHIFT_PB(3 Downto 1);
SHIFT_PB(3) <= NOT PB;
If SHIFT_PB(3 Downto 0)="0000" THEN
PB_DEBOUNCED <= '1';
ELSE
PB_DEBOUNCED <= '0';
End if;
end process;
end a;
And here is BCD to 7-segment decoder:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity decoder7seg is
port (
bcd: in std_logic_vector (3 downto 0);
segm: out std_logic_vector (6 downto 0));
end decoder7seg;
architecture Behavioral of decoder7seg is
begin
with bcd select
segm<= "0000001" when "0000", -- 0
"1001111" when "0001", -- 1
"0010010" when "0010", -- 2
"0000110" when "0011", -- 3
"1001100" when "0100", -- 4
"0100100" when "0101", -- 5
"0100000" when "0110", -- 6
"0001111" when "0111", -- 7
"0000000" when "1000", -- 8
"0000100" when "1001", -- 9
"1111110" when others; -- just - character
end Behavioral;
Does anyone see where I made my mistake(s) ?
I've tried that design on Spartan-3 Started board and it isn't working ... Every time I press the push button, I get crazy (random) values. The reset button is working properly.
Thanks !!!!
I guess the problem is here:
process (inco, rst)
begin
if inco = '1' then
CurrentPWMState <= CurrentPWMState + 1;
elsif rst='1' then
CurrentPWMState <= 0;
end if;
end process;
When rst='1' you will reset CurrentPWMState. But when inco='1' the you endlessly add 1 to CurrentPWMState. That's something like an asynchronous feedback loop through a latch. You should do something edge sensitive here. Probably you should capture inco using your clock signal, detect a 0->1 change and then add 1.
Agree with the previous answer.
A code like this should do the trick:
process (inco, ps, rst)
begin
if rst='1' then
CurrentPWMState <= '0';
prev_inco <= inco; -- This signal captures the previous value of inco
elsif ps'event and ps='1' then
if inco='1' and prev_inco='0' then -- Capture the flank rising.
CurrentPWMState <= CurrentPWMState + 1;
end if;
prev_inco <= inco;
end if;
end process;
I recognize I haven't tried the code (just coded in here) but I think it's ok.

Resources