You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
341 lines
10 KiB
341 lines
10 KiB
library ieee; |
|
use ieee.std_logic_1164.all; |
|
use ieee.numeric_std.all; |
|
|
|
library work; |
|
use work.common.all; |
|
use work.wishbone_types.all; |
|
|
|
entity dram_tb is |
|
generic ( |
|
DRAM_INIT_FILE : string := ""; |
|
DRAM_INIT_SIZE : natural := 0; |
|
L2_TRACE : boolean := false; |
|
LITEDRAM_TRACE : boolean := false |
|
); |
|
end dram_tb; |
|
|
|
architecture behave of dram_tb is |
|
signal clk, rst: std_logic; |
|
signal clk_in, soc_rst : std_ulogic; |
|
|
|
-- testbench signals |
|
constant clk_period : time := 10 ns; |
|
|
|
-- Sim DRAM |
|
signal wb_in : wishbone_master_out; |
|
signal wb_out : wishbone_slave_out; |
|
signal wb_ctrl_in : wb_io_master_out; |
|
|
|
subtype addr_t is std_ulogic_vector(wb_in.adr'left downto 0); |
|
subtype data_t is std_ulogic_vector(wb_in.dat'left downto 0); |
|
subtype sel_t is std_ulogic_vector(wb_in.sel'left downto 0); |
|
|
|
-- Counter for acks |
|
signal acks : integer := 0; |
|
signal reset_acks : std_ulogic; |
|
|
|
-- Read data fifo |
|
signal rd_ready : std_ulogic := '0'; |
|
signal rd_valid : std_ulogic; |
|
signal rd_data : data_t; |
|
begin |
|
|
|
dram: entity work.litedram_wrapper |
|
generic map( |
|
DRAM_ABITS => 24, |
|
DRAM_ALINES => 1, |
|
DRAM_DLINES => 16, |
|
DRAM_CKLINES => 1, |
|
DRAM_PORT_WIDTH => 128, |
|
PAYLOAD_FILE => DRAM_INIT_FILE, |
|
PAYLOAD_SIZE => DRAM_INIT_SIZE, |
|
TRACE => L2_TRACE, |
|
LITEDRAM_TRACE => LITEDRAM_TRACE |
|
) |
|
port map( |
|
clk_in => clk_in, |
|
rst => rst, |
|
system_clk => clk, |
|
system_reset => soc_rst, |
|
pll_locked => open, |
|
|
|
wb_in => wb_in, |
|
wb_out => wb_out, |
|
wb_ctrl_in => wb_ctrl_in, |
|
wb_ctrl_out => open, |
|
wb_ctrl_is_csr => '0', |
|
wb_ctrl_is_init => '0', |
|
|
|
init_done => open, |
|
init_error => open, |
|
|
|
ddram_a => open, |
|
ddram_ba => open, |
|
ddram_ras_n => open, |
|
ddram_cas_n => open, |
|
ddram_we_n => open, |
|
ddram_cs_n => open, |
|
ddram_dm => open, |
|
ddram_dq => open, |
|
ddram_dqs_p => open, |
|
ddram_dqs_n => open, |
|
ddram_clk_p => open, |
|
ddram_clk_n => open, |
|
ddram_cke => open, |
|
ddram_odt => open, |
|
ddram_reset_n => open |
|
); |
|
|
|
clk_process: process |
|
begin |
|
clk_in <= '0'; |
|
wait for clk_period/2; |
|
clk_in <= '1'; |
|
wait for clk_period/2; |
|
end process; |
|
|
|
rst_process: process |
|
begin |
|
rst <= '1'; |
|
wait for 10*clk_period; |
|
rst <= '0'; |
|
wait; |
|
end process; |
|
|
|
wb_ctrl_in.cyc <= '0'; |
|
wb_ctrl_in.stb <= '0'; |
|
|
|
-- Read data receive queue |
|
data_queue: entity work.sync_fifo |
|
generic map ( |
|
DEPTH => 16, |
|
WIDTH => rd_data'length |
|
) |
|
port map ( |
|
clk => clk, |
|
reset => soc_rst or reset_acks, |
|
rd_ready => rd_ready, |
|
rd_valid => rd_valid, |
|
rd_data => rd_data, |
|
wr_ready => open, |
|
wr_valid => wb_out.ack, |
|
wr_data => wb_out.dat |
|
); |
|
|
|
recv_acks: process(clk) |
|
begin |
|
if rising_edge(clk) then |
|
if rst = '1' or reset_acks = '1' then |
|
acks <= 0; |
|
elsif wb_out.ack = '1' then |
|
acks <= acks + 1; |
|
-- report "WB ACK ! DATA=" & to_hstring(wb_out.dat); |
|
end if; |
|
end if; |
|
end process; |
|
|
|
sim: process |
|
procedure wb_write(addr: addr_t; data: data_t; sel: sel_t) is |
|
begin |
|
wb_in.adr <= addr; |
|
wb_in.sel <= sel; |
|
wb_in.dat <= data; |
|
wb_in.we <= '1'; |
|
wb_in.stb <= '1'; |
|
wb_in.cyc <= '1'; |
|
loop |
|
wait until rising_edge(clk); |
|
if wb_out.stall = '0' then |
|
wb_in.stb <= '0'; |
|
exit; |
|
end if; |
|
end loop; |
|
end procedure; |
|
|
|
procedure wb_read(addr: addr_t) is |
|
begin |
|
wb_in.adr <= addr; |
|
wb_in.sel <= x"ff"; |
|
wb_in.we <= '0'; |
|
wb_in.stb <= '1'; |
|
wb_in.cyc <= '1'; |
|
loop |
|
wait until rising_edge(clk); |
|
if wb_out.stall = '0' then |
|
wb_in.stb <= '0'; |
|
exit; |
|
end if; |
|
end loop; |
|
end procedure; |
|
|
|
procedure wait_acks(count: integer) is |
|
begin |
|
wait until acks = count; |
|
wait until rising_edge(clk); |
|
end procedure; |
|
|
|
procedure clr_acks is |
|
begin |
|
reset_acks <= '1'; |
|
wait until rising_edge(clk); |
|
reset_acks <= '0'; |
|
end procedure; |
|
|
|
procedure read_data(data: out data_t) is |
|
begin |
|
assert rd_valid = '1' report "No data to read" severity failure; |
|
rd_ready <= '1'; |
|
wait until rising_edge(clk); |
|
rd_ready <= '0'; |
|
data := rd_data; |
|
end procedure; |
|
|
|
function add_off(a: addr_t; off: integer) return addr_t is |
|
begin |
|
return addr_t(unsigned(a) + off); |
|
end function; |
|
|
|
function make_pattern(num : integer) return data_t is |
|
variable r : data_t; |
|
variable t,b : integer; |
|
begin |
|
for i in 0 to (data_t'length/8)-1 loop |
|
t := (i+1)*8-1; |
|
b := i*8; |
|
r(t downto b) := std_ulogic_vector(to_unsigned(num+1, 8)); |
|
end loop; |
|
return r; |
|
end function; |
|
|
|
procedure check_data(p: data_t) is |
|
variable d : data_t; |
|
begin |
|
read_data(d); |
|
assert d = p report "bad data, want " & to_hstring(p) & |
|
" got " & to_hstring(d) severity failure; |
|
end procedure; |
|
|
|
variable a : addr_t := (others => '0'); |
|
variable d : data_t := (others => '0'); |
|
variable d1 : data_t := (others => '0'); |
|
begin |
|
reset_acks <= '0'; |
|
rst <= '1'; |
|
wait until rising_edge(clk_in); |
|
wait until rising_edge(clk_in); |
|
wait until rising_edge(clk_in); |
|
wait until rising_edge(clk_in); |
|
wait until rising_edge(clk_in); |
|
rst <= '0'; |
|
wait until rising_edge(clk_in); |
|
wait until soc_rst = '0'; |
|
wait until rising_edge(clk); |
|
|
|
report "Simple write miss..."; |
|
clr_acks; |
|
wb_write(a, x"0123456789abcdef", x"ff"); |
|
wait_acks(1); |
|
|
|
report "Simple read miss..."; |
|
clr_acks; |
|
wb_read(a); |
|
wait_acks(1); |
|
read_data(d); |
|
assert d = x"0123456789abcdef" report "bad data, got " & to_hstring(d) severity failure; |
|
|
|
report "Simple read hit..."; |
|
clr_acks; |
|
wb_read(a); |
|
wait_acks(1); |
|
read_data(d); |
|
assert d = x"0123456789abcdef" report "bad data, got " & to_hstring(d) severity failure; |
|
|
|
report "Back to back 4 stores 4 reads on hit..."; |
|
clr_acks; |
|
for i in 0 to 3 loop |
|
wb_write(add_off(a, i), make_pattern(i), x"ff"); |
|
end loop; |
|
for i in 0 to 3 loop |
|
wb_read(add_off(a, i)); |
|
end loop; |
|
wait_acks(8); |
|
for i in 0 to 7 loop |
|
if i < 4 then |
|
read_data(d); |
|
else |
|
check_data(make_pattern(i-4)); |
|
end if; |
|
end loop; |
|
|
|
report "Back to back 4 stores 4 reads on miss..."; |
|
a(10) := '1'; |
|
clr_acks; |
|
for i in 0 to 3 loop |
|
wb_write(add_off(a, i), make_pattern(i), x"ff"); |
|
end loop; |
|
for i in 0 to 3 loop |
|
wb_read(add_off(a, i)); |
|
end loop; |
|
wait_acks(8); |
|
for i in 0 to 7 loop |
|
if i < 4 then |
|
read_data(d); |
|
else |
|
check_data(make_pattern(i-4)); |
|
end if; |
|
end loop; |
|
|
|
report "Back to back interleaved 4 stores 4 reads on hit..."; |
|
a(10) := '1'; |
|
clr_acks; |
|
for i in 0 to 3 loop |
|
wb_write(add_off(a, i), make_pattern(i), x"ff"); |
|
wb_read(add_off(a, i)); |
|
end loop; |
|
wait_acks(8); |
|
for i in 0 to 3 loop |
|
read_data(d); |
|
check_data(make_pattern(i)); |
|
end loop; |
|
|
|
report "Pre-fill a line"; |
|
a(11) := '1'; |
|
clr_acks; |
|
wb_write(add_off(a, 0), x"1111111100000000", x"ff"); |
|
wb_write(add_off(a, 1), x"3333333322222222", x"ff"); |
|
wb_write(add_off(a, 2), x"5555555544444444", x"ff"); |
|
wb_write(add_off(a, 3), x"7777777766666666", x"ff"); |
|
wb_write(add_off(a, 4), x"9999999988888888", x"ff"); |
|
wb_write(add_off(a, 5), x"bbbbbbbbaaaaaaaa", x"ff"); |
|
wb_write(add_off(a, 6), x"ddddddddcccccccc", x"ff"); |
|
wb_write(add_off(a, 7), x"ffffffffeeeeeeee", x"ff"); |
|
wb_write(add_off(a, 8), x"1111111100000000", x"ff"); |
|
wb_write(add_off(a, 9), x"3333333322222222", x"ff"); |
|
wb_write(add_off(a, 10), x"5555555544444444", x"ff"); |
|
wb_write(add_off(a, 11), x"7777777766666666", x"ff"); |
|
wb_write(add_off(a, 12), x"9999999988888888", x"ff"); |
|
wb_write(add_off(a, 13), x"bbbbbbbbaaaaaaaa", x"ff"); |
|
wb_write(add_off(a, 14), x"ddddddddcccccccc", x"ff"); |
|
wb_write(add_off(a, 15), x"ffffffffeeeeeeee", x"ff"); |
|
wait_acks(16); |
|
|
|
report "Scattered from middle of line..."; |
|
clr_acks; |
|
wb_read(add_off(a, 3)); |
|
wb_read(add_off(a, 4)); |
|
wb_read(add_off(a, 0)); |
|
wb_read(add_off(a, 2)); |
|
wait_acks(4); |
|
read_data(d); |
|
assert d = x"7777777766666666" report "bad data (24), got " & to_hstring(d) severity failure; |
|
read_data(d); |
|
assert d = x"9999999988888888" report "bad data (32), got " & to_hstring(d) severity failure; |
|
read_data(d); |
|
assert d = x"1111111100000000" report "bad data (0), got " & to_hstring(d) severity failure; |
|
read_data(d); |
|
assert d = x"5555555544444444" report "bad data (16), got " & to_hstring(d) severity failure; |
|
|
|
std.env.finish; |
|
end process; |
|
end architecture;
|
|
|