forked from cores/microwatt
Merge pull request #191 from ozbenh/litedram
Litedram updates with L2 cache and sim supportjtag-port
commit
983f4fefe1
@ -0,0 +1,135 @@
|
||||
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 core_dram_tb is
|
||||
generic (
|
||||
MEMORY_SIZE : natural := (384*1024);
|
||||
MAIN_RAM_FILE : string := "main_ram.bin";
|
||||
DRAM_INIT_FILE : string := "";
|
||||
DRAM_INIT_SIZE : natural := 16#c000#
|
||||
);
|
||||
end core_dram_tb;
|
||||
|
||||
architecture behave of core_dram_tb is
|
||||
signal clk, rst: std_logic;
|
||||
signal system_clk, soc_rst : std_ulogic;
|
||||
|
||||
-- testbench signals
|
||||
constant clk_period : time := 10 ns;
|
||||
|
||||
-- Sim DRAM
|
||||
signal wb_dram_in : wishbone_master_out;
|
||||
signal wb_dram_out : wishbone_slave_out;
|
||||
signal wb_dram_ctrl_in : wb_io_master_out;
|
||||
signal wb_dram_ctrl_out : wb_io_slave_out;
|
||||
signal wb_dram_is_csr : std_ulogic;
|
||||
signal wb_dram_is_init : std_ulogic;
|
||||
signal core_alt_reset : std_ulogic;
|
||||
|
||||
-- ROM size
|
||||
function get_rom_size return natural is
|
||||
begin
|
||||
if MEMORY_SIZE = 0 then
|
||||
return DRAM_INIT_SIZE;
|
||||
else
|
||||
return 0;
|
||||
end if;
|
||||
end function;
|
||||
|
||||
constant ROM_SIZE : natural := get_rom_size;
|
||||
begin
|
||||
|
||||
soc0: entity work.soc
|
||||
generic map(
|
||||
SIM => true,
|
||||
MEMORY_SIZE => MEMORY_SIZE,
|
||||
RAM_INIT_FILE => MAIN_RAM_FILE,
|
||||
RESET_LOW => false,
|
||||
HAS_DRAM => true,
|
||||
DRAM_SIZE => 256 * 1024 * 1024,
|
||||
DRAM_INIT_SIZE => ROM_SIZE,
|
||||
CLK_FREQ => 100000000
|
||||
)
|
||||
port map(
|
||||
rst => soc_rst,
|
||||
system_clk => system_clk,
|
||||
uart0_rxd => '0',
|
||||
uart0_txd => open,
|
||||
wb_dram_in => wb_dram_in,
|
||||
wb_dram_out => wb_dram_out,
|
||||
wb_dram_ctrl_in => wb_dram_ctrl_in,
|
||||
wb_dram_ctrl_out => wb_dram_ctrl_out,
|
||||
wb_dram_is_csr => wb_dram_is_csr,
|
||||
wb_dram_is_init => wb_dram_is_init,
|
||||
alt_reset => core_alt_reset
|
||||
);
|
||||
|
||||
dram: entity work.litedram_wrapper
|
||||
generic map(
|
||||
DRAM_ABITS => 24,
|
||||
DRAM_ALINES => 1,
|
||||
PAYLOAD_FILE => DRAM_INIT_FILE,
|
||||
PAYLOAD_SIZE => ROM_SIZE
|
||||
)
|
||||
port map(
|
||||
clk_in => clk,
|
||||
rst => rst,
|
||||
system_clk => system_clk,
|
||||
system_reset => soc_rst,
|
||||
core_alt_reset => core_alt_reset,
|
||||
pll_locked => open,
|
||||
|
||||
wb_in => wb_dram_in,
|
||||
wb_out => wb_dram_out,
|
||||
wb_ctrl_in => wb_dram_ctrl_in,
|
||||
wb_ctrl_out => wb_dram_ctrl_out,
|
||||
wb_ctrl_is_csr => wb_dram_is_csr,
|
||||
wb_ctrl_is_init => wb_dram_is_init,
|
||||
|
||||
serial_tx => open,
|
||||
serial_rx => '1',
|
||||
|
||||
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 <= '0';
|
||||
wait for clk_period/2;
|
||||
clk <= '1';
|
||||
wait for clk_period/2;
|
||||
end process;
|
||||
|
||||
rst_process: process
|
||||
begin
|
||||
rst <= '1';
|
||||
wait for 10*clk_period;
|
||||
rst <= '0';
|
||||
wait;
|
||||
end process;
|
||||
|
||||
jtag: entity work.sim_jtag;
|
||||
|
||||
end;
|
@ -0,0 +1,301 @@
|
||||
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
|
||||
);
|
||||
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,
|
||||
PAYLOAD_FILE => DRAM_INIT_FILE,
|
||||
PAYLOAD_SIZE => DRAM_INIT_SIZE
|
||||
)
|
||||
port map(
|
||||
clk_in => clk_in,
|
||||
rst => rst,
|
||||
system_clk => clk,
|
||||
system_reset => soc_rst,
|
||||
core_alt_reset => open,
|
||||
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',
|
||||
|
||||
serial_tx => open,
|
||||
serial_rx => '1',
|
||||
|
||||
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" severity failure;
|
||||
|
||||
report "Simple read hit...";
|
||||
clr_acks;
|
||||
wb_read(a);
|
||||
wait_acks(1);
|
||||
read_data(d);
|
||||
assert d = x"0123456789abcdef" report "bad data" 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*8), make_pattern(i), x"ff");
|
||||
end loop;
|
||||
for i in 0 to 3 loop
|
||||
wb_read(add_off(a, i*8));
|
||||
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*8), make_pattern(i), x"ff");
|
||||
end loop;
|
||||
for i in 0 to 3 loop
|
||||
wb_read(add_off(a, i*8));
|
||||
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*8), make_pattern(i), x"ff");
|
||||
wb_read(add_off(a, i*8));
|
||||
end loop;
|
||||
wait_acks(8);
|
||||
for i in 0 to 3 loop
|
||||
read_data(d);
|
||||
check_data(make_pattern(i));
|
||||
end loop;
|
||||
|
||||
std.env.finish;
|
||||
end process;
|
||||
end architecture;
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,10 @@
|
||||
OPT_FAST=-O3 -fstrict-aliasing
|
||||
OPT_SLOW=-O3 -fstrict-aliasing
|
||||
|
||||
top_all: top_all2
|
||||
|
||||
include Vlitedram_core.mk
|
||||
|
||||
top_all2: default $(VK_GLOBAL_OBJS)
|
||||
|
||||
.PHONY: top_all top_all2
|
@ -0,0 +1,214 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
|
||||
package sim_litedram is
|
||||
-- WB req format:
|
||||
-- 73 .. 71 : cti(2..0)
|
||||
-- 70 .. 69 : bte(1..0)
|
||||
-- 68 .. 65 : sel(3..0)
|
||||
-- 64 : we
|
||||
-- 63 : stb
|
||||
-- 62 : cyc
|
||||
-- 61 .. 32 : addr(29..0)
|
||||
-- 31 .. 0 : write_data(31..0)
|
||||
--
|
||||
procedure litedram_set_wb(req : in std_ulogic_vector(73 downto 0));
|
||||
attribute foreign of litedram_set_wb : procedure is "VHPIDIRECT litedram_set_wb";
|
||||
|
||||
-- WB rsp format:
|
||||
-- 35 : init_error;
|
||||
-- 34 : init_done;
|
||||
-- 33 : err
|
||||
-- 32 : ack
|
||||
-- 31 .. 0 : read_data(31..0)
|
||||
--
|
||||
procedure litedram_get_wb(rsp : out std_ulogic_vector(35 downto 0));
|
||||
attribute foreign of litedram_get_wb : procedure is "VHPIDIRECT litedram_get_wb";
|
||||
|
||||
-- User req format:
|
||||
-- 171 : cmd_valid
|
||||
-- 170 : cmd_we
|
||||
-- 169 : wdata_valid
|
||||
-- 168 : rdata_ready
|
||||
-- 167 .. 144 : cmd_addr(23..0)
|
||||
-- 143 .. 128 : wdata_we(15..0)
|
||||
-- 127 .. 0 : wdata_data(127..0)
|
||||
--
|
||||
procedure litedram_set_user(req: in std_ulogic_vector(171 downto 0));
|
||||
attribute foreign of litedram_set_user : procedure is "VHPIDIRECT litedram_set_user";
|
||||
|
||||
-- User rsp format:
|
||||
-- 130 : cmd_ready
|
||||
-- 129 : wdata_ready
|
||||
-- 128 : rdata_valid
|
||||
-- 127 .. 0 : rdata_data(127..0)
|
||||
|
||||
procedure litedram_get_user(req: in std_ulogic_vector(130 downto 0));
|
||||
attribute foreign of litedram_get_user : procedure is "VHPIDIRECT litedram_get_user";
|
||||
|
||||
procedure litedram_clock;
|
||||
attribute foreign of litedram_clock : procedure is "VHPIDIRECT litedram_clock";
|
||||
|
||||
procedure litedram_init(trace: integer);
|
||||
attribute foreign of litedram_init : procedure is "VHPIDIRECT litedram_init";
|
||||
end sim_litedram;
|
||||
|
||||
package body sim_litedram is
|
||||
procedure litedram_set_wb(req : in std_ulogic_vector(73 downto 0)) is
|
||||
begin
|
||||
assert false report "VHPI" severity failure;
|
||||
end procedure;
|
||||
procedure litedram_get_wb(rsp : out std_ulogic_vector(35 downto 0)) is
|
||||
begin
|
||||
assert false report "VHPI" severity failure;
|
||||
end procedure;
|
||||
procedure litedram_set_user(req: in std_ulogic_vector(171 downto 0)) is
|
||||
begin
|
||||
assert false report "VHPI" severity failure;
|
||||
end procedure;
|
||||
procedure litedram_get_user(req: in std_ulogic_vector(130 downto 0)) is
|
||||
begin
|
||||
assert false report "VHPI" severity failure;
|
||||
end procedure;
|
||||
procedure litedram_clock is
|
||||
begin
|
||||
assert false report "VHPI" severity failure;
|
||||
end procedure;
|
||||
procedure litedram_init(trace: integer) is
|
||||
begin
|
||||
assert false report "VHPI" severity failure;
|
||||
end procedure;
|
||||
end sim_litedram;
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.sim_litedram.all;
|
||||
|
||||
entity litedram_core is
|
||||
port(
|
||||
clk : in std_ulogic;
|
||||
rst : in std_ulogic;
|
||||
pll_locked : out std_ulogic;
|
||||
ddram_a : out std_ulogic_vector(0 downto 0);
|
||||
ddram_ba : out std_ulogic_vector(2 downto 0);
|
||||
ddram_ras_n : out std_ulogic;
|
||||
ddram_cas_n : out std_ulogic;
|
||||
ddram_we_n : out std_ulogic;
|
||||
ddram_cs_n : out std_ulogic;
|
||||
ddram_dm : out std_ulogic_vector(1 downto 0);
|
||||
ddram_dq : inout std_ulogic_vector(15 downto 0);
|
||||
ddram_dqs_p : inout std_ulogic_vector(1 downto 0);
|
||||
ddram_dqs_n : inout std_ulogic_vector(1 downto 0);
|
||||
ddram_clk_p : out std_ulogic;
|
||||
ddram_clk_n : out std_ulogic;
|
||||
ddram_cke : out std_ulogic;
|
||||
ddram_odt : out std_ulogic;
|
||||
ddram_reset_n : out std_ulogic;
|
||||
init_done : out std_ulogic;
|
||||
init_error : out std_ulogic;
|
||||
user_clk : out std_ulogic;
|
||||
user_rst : out std_ulogic;
|
||||
wb_ctrl_adr : in std_ulogic_vector(29 downto 0);
|
||||
wb_ctrl_dat_w : in std_ulogic_vector(31 downto 0);
|
||||
wb_ctrl_dat_r : out std_ulogic_vector(31 downto 0);
|
||||
wb_ctrl_sel : in std_ulogic_vector(3 downto 0);
|
||||
wb_ctrl_cyc : in std_ulogic;
|
||||
wb_ctrl_stb : in std_ulogic;
|
||||
wb_ctrl_ack : out std_ulogic;
|
||||
wb_ctrl_we : in std_ulogic;
|
||||
wb_ctrl_cti : in std_ulogic_vector(2 downto 0);
|
||||
wb_ctrl_bte : in std_ulogic_vector(1 downto 0);
|
||||
wb_ctrl_err : out std_ulogic;
|
||||
user_port_native_0_cmd_valid : in std_ulogic;
|
||||
user_port_native_0_cmd_ready : out std_ulogic;
|
||||
user_port_native_0_cmd_we : in std_ulogic;
|
||||
user_port_native_0_cmd_addr : in std_ulogic_vector(23 downto 0);
|
||||
user_port_native_0_wdata_valid : in std_ulogic;
|
||||
user_port_native_0_wdata_ready : out std_ulogic;
|
||||
user_port_native_0_wdata_we : in std_ulogic_vector(15 downto 0);
|
||||
user_port_native_0_wdata_data : in std_ulogic_vector(127 downto 0);
|
||||
user_port_native_0_rdata_valid : out std_ulogic;
|
||||
user_port_native_0_rdata_ready : in std_ulogic;
|
||||
user_port_native_0_rdata_data : out std_ulogic_vector(127 downto 0)
|
||||
);
|
||||
end entity litedram_core;
|
||||
|
||||
architecture behaviour of litedram_core is
|
||||
signal idone : std_ulogic := '0';
|
||||
signal ierr : std_ulogic := '0';
|
||||
signal old_wb_cyc : std_ulogic := '1';
|
||||
begin
|
||||
user_rst <= rst;
|
||||
user_clk <= clk;
|
||||
pll_locked <= '1';
|
||||
init_done <= idone;
|
||||
init_error <= ierr;
|
||||
|
||||
poll: process(user_clk)
|
||||
procedure send_signals is
|
||||
begin
|
||||
litedram_set_wb(wb_ctrl_cti & wb_ctrl_bte &
|
||||
wb_ctrl_sel & wb_ctrl_we &
|
||||
wb_ctrl_stb & wb_ctrl_cyc &
|
||||
wb_ctrl_adr & wb_ctrl_dat_w);
|
||||
litedram_set_user(user_port_native_0_cmd_valid &
|
||||
user_port_native_0_cmd_we &
|
||||
user_port_native_0_wdata_valid &
|
||||
user_port_native_0_rdata_ready &
|
||||
user_port_native_0_cmd_addr &
|
||||
user_port_native_0_wdata_we &
|
||||
user_port_native_0_wdata_data);
|
||||
end procedure;
|
||||
|
||||
procedure recv_signals is
|
||||
variable wb_response : std_ulogic_vector(35 downto 0);
|
||||
variable ur_response : std_ulogic_vector(130 downto 0);
|
||||
begin
|
||||
litedram_get_wb(wb_response);
|
||||
wb_ctrl_dat_r <= wb_response(31 downto 0);
|
||||
wb_ctrl_ack <= wb_response(32);
|
||||
wb_ctrl_err <= wb_response(33);
|
||||
idone <= wb_response(34);
|
||||
ierr <= wb_response(35);
|
||||
litedram_get_user(ur_response);
|
||||
user_port_native_0_cmd_ready <= ur_response(130);
|
||||
user_port_native_0_wdata_ready <= ur_response(129);
|
||||
user_port_native_0_rdata_valid <= ur_response(128);
|
||||
user_port_native_0_rdata_data <= ur_response(127 downto 0);
|
||||
end procedure;
|
||||
|
||||
begin
|
||||
if rising_edge(user_clk) then
|
||||
|
||||
send_signals;
|
||||
recv_signals;
|
||||
-- Then generate a clock cycle ( 0->1 then 1->0 )
|
||||
litedram_clock;
|
||||
recv_signals;
|
||||
end if;
|
||||
|
||||
if falling_edge(user_clk) then
|
||||
send_signals;
|
||||
recv_signals;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end architecture;
|
||||
|
||||
library work;
|
||||
use work.sim_litedram.all;
|
||||
|
||||
entity litedram_trace_stub is
|
||||
end entity;
|
||||
|
||||
architecture behaviour of litedram_trace_stub is
|
||||
begin
|
||||
process
|
||||
begin
|
||||
litedram_init(1);
|
||||
wait;
|
||||
end process;
|
||||
end architecture;
|
@ -0,0 +1,198 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include "sim_vhpi_c.h"
|
||||
#include "Vlitedram_core.h"
|
||||
#include "verilated_vcd_c.h"
|
||||
|
||||
static Vlitedram_core *v;
|
||||
vluint64_t main_time = 0;
|
||||
|
||||
#if VM_TRACE
|
||||
VerilatedVcdC *tfp;
|
||||
#endif
|
||||
|
||||
static void cleanup(void)
|
||||
{
|
||||
#if VM_TRACE
|
||||
if (tfp) {
|
||||
tfp->flush();
|
||||
tfp->close();
|
||||
delete tfp;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void check_init(bool traces)
|
||||
{
|
||||
if (v)
|
||||
return;
|
||||
// XX Catch exceptions ?
|
||||
v = new Vlitedram_core;
|
||||
if (!v) {
|
||||
fprintf(stderr, "Failure allocating litedram core\n");
|
||||
exit(1);
|
||||
}
|
||||
#if VM_TRACE
|
||||
if (traces) {
|
||||
// init trace dump
|
||||
Verilated::traceEverOn(true);
|
||||
tfp = new VerilatedVcdC;
|
||||
v->trace(tfp, 99);
|
||||
tfp->open("litedram.vcd");
|
||||
}
|
||||
#endif
|
||||
atexit(cleanup);
|
||||
}
|
||||
|
||||
unsigned char get_bit(unsigned char **p)
|
||||
{
|
||||
unsigned char b = **p;
|
||||
|
||||
*p = *p + 1;
|
||||
|
||||
return b == vhpi1 ? 1 : 0;
|
||||
}
|
||||
|
||||
uint64_t get_bits(unsigned char **p, int len)
|
||||
{
|
||||
uint64_t r = 0;
|
||||
|
||||
while(len--)
|
||||
r = (r << 1) | get_bit(p);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void set_bit(unsigned char **p, int bit)
|
||||
{
|
||||
**p = bit ? vhpi1 : vhpi0;
|
||||
*p = *p + 1;
|
||||
}
|
||||
|
||||
void set_bits(unsigned char **p, uint64_t val, int len)
|
||||
{
|
||||
while(len--)
|
||||
set_bit(p, (val >> len) & 1);
|
||||
}
|
||||
|
||||
double sc_time_stamp(void)
|
||||
{
|
||||
return main_time;
|
||||
}
|
||||
|
||||
#define check_size(s, exp) \
|
||||
do { \
|
||||
int __s = (s); \
|
||||
int __e = (exp); \
|
||||
if (__s != __e) \
|
||||
fprintf(stderr, "WARNING: %s exp %d got %d\n", __func__, __e, __s); \
|
||||
} while(0)
|
||||
|
||||
static void do_eval(void)
|
||||
{
|
||||
v->eval();
|
||||
#if VM_TRACE
|
||||
if (tfp)
|
||||
tfp->dump((double) main_time);
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" void litedram_set_wb(unsigned char *req)
|
||||
{
|
||||
unsigned char *orig = req;
|
||||
|
||||
check_init(false);
|
||||
|
||||
v->wb_ctrl_cti = get_bits(&req, 3);
|
||||
v->wb_ctrl_bte = get_bits(&req, 2);
|
||||
v->wb_ctrl_sel = get_bits(&req, 4);
|
||||
v->wb_ctrl_we = get_bit(&req);
|
||||
v->wb_ctrl_stb = get_bit(&req);
|
||||
v->wb_ctrl_cyc = get_bit(&req);
|
||||
v->wb_ctrl_adr = get_bits(&req, 30);
|
||||
v->wb_ctrl_dat_w = get_bits(&req, 32);
|
||||
|
||||
check_size(req - orig, 74);
|
||||
|
||||
do_eval();
|
||||
}
|
||||
|
||||
extern "C" void litedram_get_wb(unsigned char *req)
|
||||
{
|
||||
unsigned char *orig = req;
|
||||
|
||||
check_init(false);
|
||||
|
||||
set_bit(&req, v->init_error);
|
||||
set_bit(&req, v->init_done);
|
||||
set_bit(&req, v->wb_ctrl_err);
|
||||
set_bit(&req, v->wb_ctrl_ack);
|
||||
set_bits(&req, v->wb_ctrl_dat_r, 32);
|
||||
|
||||
check_size(req - orig, 36);
|
||||
}
|
||||
|
||||
extern "C" void litedram_set_user(unsigned char *req)
|
||||
{
|
||||
unsigned char *orig = req;
|
||||
|
||||
check_init(false);
|
||||
|
||||
v->user_port_native_0_cmd_valid = get_bit(&req);
|
||||
v->user_port_native_0_cmd_we = get_bit(&req);
|
||||
v->user_port_native_0_wdata_valid = get_bit(&req);
|
||||
v->user_port_native_0_rdata_ready = get_bit(&req);
|
||||
v->user_port_native_0_cmd_addr = get_bits(&req, 24);
|
||||
v->user_port_native_0_wdata_we = get_bits(&req, 16);
|
||||
v->user_port_native_0_wdata_data[3] = get_bits(&req, 32);
|
||||
v->user_port_native_0_wdata_data[2] = get_bits(&req, 32);
|
||||
v->user_port_native_0_wdata_data[1] = get_bits(&req, 32);
|
||||
v->user_port_native_0_wdata_data[0] = get_bits(&req, 32);
|
||||
|
||||
check_size(req - orig, 172);
|
||||
|
||||
do_eval();
|
||||
}
|
||||
|
||||
extern "C" void litedram_get_user(unsigned char *req)
|
||||
{
|
||||
unsigned char *orig = req;
|
||||
|
||||
check_init(false);
|
||||
|
||||
set_bit(&req, v->user_port_native_0_cmd_ready);
|
||||
set_bit(&req, v->user_port_native_0_wdata_ready);
|
||||
set_bit(&req, v->user_port_native_0_rdata_valid);
|
||||
set_bits(&req, v->user_port_native_0_rdata_data[3], 32);
|
||||
set_bits(&req, v->user_port_native_0_rdata_data[2], 32);
|
||||
set_bits(&req, v->user_port_native_0_rdata_data[1], 32);
|
||||
set_bits(&req, v->user_port_native_0_rdata_data[0], 32);
|
||||
|
||||
check_size(req - orig, 131);
|
||||
}
|
||||
|
||||
extern "C" void litedram_clock(void)
|
||||
{
|
||||
check_init(false);
|
||||
|
||||
v->clk = 1;
|
||||
do_eval();
|
||||
main_time++;
|
||||
v->clk = 0;
|
||||
do_eval();
|
||||
main_time++;
|
||||
}
|
||||
|
||||
extern "C" void litedram_init(int trace_on)
|
||||
{
|
||||
check_init(!!trace_on);
|
||||
}
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,84 @@
|
||||
$ version 1.1
|
||||
|
||||
# Signals in entities :
|
||||
/core_dram_tb/dram/rst
|
||||
/core_dram_tb/dram/system_clk
|
||||
/core_dram_tb/dram/system_reset
|
||||
/core_dram_tb/dram/wb_in
|
||||
/core_dram_tb/dram/wb_out
|
||||
/core_dram_tb/dram/user_port0_cmd_valid
|
||||
/core_dram_tb/dram/user_port0_cmd_ready
|
||||
/core_dram_tb/dram/user_port0_cmd_we
|
||||
/core_dram_tb/dram/user_port0_cmd_addr
|
||||
/core_dram_tb/dram/user_port0_wdata_valid
|
||||
/core_dram_tb/dram/user_port0_wdata_ready
|
||||
/core_dram_tb/dram/user_port0_wdata_we
|
||||
/core_dram_tb/dram/user_port0_wdata_data
|
||||
/core_dram_tb/dram/user_port0_rdata_valid
|
||||
/core_dram_tb/dram/user_port0_rdata_ready
|
||||
/core_dram_tb/dram/user_port0_rdata_data
|
||||
/core_dram_tb/dram/cache_tags
|
||||
/core_dram_tb/dram/cache_valids
|
||||
/core_dram_tb/dram/storeq_rd_ready
|
||||
/core_dram_tb/dram/storeq_rd_valid
|
||||
/core_dram_tb/dram/storeq_rd_data
|
||||
/core_dram_tb/dram/storeq_wr_ready
|
||||
/core_dram_tb/dram/storeq_wr_valid
|
||||
/core_dram_tb/dram/storeq_wr_data
|
||||
/core_dram_tb/dram/accept_store
|
||||
/core_dram_tb/dram/state
|
||||
/core_dram_tb/dram/wb_req
|
||||
/core_dram_tb/dram/store_queued
|
||||
/core_dram_tb/dram/read_ack_0
|
||||
/core_dram_tb/dram/read_ack_1
|
||||
/core_dram_tb/dram/read_ad3_0
|
||||
/core_dram_tb/dram/read_ad3_1
|
||||
/core_dram_tb/dram/read_way_0
|
||||
/core_dram_tb/dram/read_way_1
|
||||
/core_dram_tb/dram/req_index
|
||||
/core_dram_tb/dram/req_row
|
||||
/core_dram_tb/dram/req_hit_way
|
||||
/core_dram_tb/dram/req_tag
|
||||
/core_dram_tb/dram/req_op
|
||||
/core_dram_tb/dram/req_laddr
|
||||
/core_dram_tb/dram/req_ad3
|
||||
/core_dram_tb/dram/req_we
|
||||
/core_dram_tb/dram/req_wdata
|
||||
/core_dram_tb/dram/store_way
|
||||
/core_dram_tb/dram/store_index
|
||||
/core_dram_tb/dram/store_row
|
||||
/core_dram_tb/dram/cache_out
|
||||
/core_dram_tb/dram/plru_victim
|
||||
/core_dram_tb/dram/replace_way
|
||||
/core_dram_tb/dram/rams/do_read
|
||||
/core_dram_tb/dram/rams/do_write
|
||||
/core_dram_tb/dram/rams/rd_addr
|
||||
/core_dram_tb/dram/rams/wr_addr
|
||||
/core_dram_tb/dram/rams/wr_data
|
||||
/core_dram_tb/dram/rams/wr_sel
|
||||
/core_dram_tb/dram/rams/wr_sel_m
|
||||
/core_dram_tb/dram/rams/dout
|
||||
/core_dram_tb/dram/rams/way/clk
|
||||
/core_dram_tb/dram/rams/way/rd_en
|
||||
/core_dram_tb/dram/rams/way/rd_addr
|
||||
/core_dram_tb/dram/rams/way/rd_data
|
||||
/core_dram_tb/dram/rams/way/wr_sel
|
||||
/core_dram_tb/dram/rams/way/wr_addr
|
||||
/core_dram_tb/dram/rams/way/wr_data
|
||||
/core_dram_tb/dram/rams/way/rd_data0
|
||||
/core_dram_tb/dram/store_queue/wr_ready
|
||||
/core_dram_tb/dram/store_queue/wr_valid
|
||||
/core_dram_tb/dram/store_queue/wr_data
|
||||
/core_dram_tb/dram/store_queue/rd_ready
|
||||
/core_dram_tb/dram/store_queue/rd_valid
|
||||
/core_dram_tb/dram/store_queue/rd_data
|
||||
/core_dram_tb/dram/store_queue/rd_idx
|
||||
/core_dram_tb/dram/store_queue/rd_next
|
||||
/core_dram_tb/dram/store_queue/wr_idx
|
||||
/core_dram_tb/dram/store_queue/wr_next
|
||||
/core_dram_tb/dram/store_queue/op_prev
|
||||
/core_dram_tb/dram/store_queue/op_next
|
||||
/core_dram_tb/dram/store_queue/full
|
||||
/core_dram_tb/dram/store_queue/empty
|
||||
/core_dram_tb/dram/store_queue/push
|
||||
/core_dram_tb/dram/store_queue/pop
|
@ -0,0 +1,80 @@
|
||||
[*]
|
||||
[*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI
|
||||
[*] Sun May 31 12:53:52 2020
|
||||
[*]
|
||||
[dumpfile] "/home/ANT.AMAZON.COM/benh/hackplace/microwatt/foo.ghw"
|
||||
[dumpfile_mtime] "Sun May 31 12:50:15 2020"
|
||||
[dumpfile_size] 1134118
|
||||
[savefile] "/home/ANT.AMAZON.COM/benh/hackplace/microwatt/litedram/extras/wave_tb.gtkw"
|
||||
[timestart] 1312950000
|
||||
[size] 2509 1371
|
||||
[pos] -1 -1
|
||||
*-24.248457 1386890000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
|
||||
[treeopen] top.
|
||||
[treeopen] top.dram_tb.
|
||||
[sst_width] 301
|
||||
[signals_width] 433
|
||||
[sst_expanded] 1
|
||||
[sst_vpaned_height] 410
|
||||
@28
|
||||
top.dram_tb.reset_acks
|
||||
@420
|
||||
top.dram_tb.acks
|
||||
@28
|
||||
top.dram_tb.rst
|
||||
top.dram_tb.clk
|
||||
@22
|
||||
#{top.dram_tb.wb_in.dat[63:0]} top.dram_tb.wb_in.dat[63] top.dram_tb.wb_in.dat[62] top.dram_tb.wb_in.dat[61] top.dram_tb.wb_in.dat[60] top.dram_tb.wb_in.dat[59] top.dram_tb.wb_in.dat[58] top.dram_tb.wb_in.dat[57] top.dram_tb.wb_in.dat[56] top.dram_tb.wb_in.dat[55] top.dram_tb.wb_in.dat[54] top.dram_tb.wb_in.dat[53] top.dram_tb.wb_in.dat[52] top.dram_tb.wb_in.dat[51] top.dram_tb.wb_in.dat[50] top.dram_tb.wb_in.dat[49] top.dram_tb.wb_in.dat[48] top.dram_tb.wb_in.dat[47] top.dram_tb.wb_in.dat[46] top.dram_tb.wb_in.dat[45] top.dram_tb.wb_in.dat[44] top.dram_tb.wb_in.dat[43] top.dram_tb.wb_in.dat[42] top.dram_tb.wb_in.dat[41] top.dram_tb.wb_in.dat[40] top.dram_tb.wb_in.dat[39] top.dram_tb.wb_in.dat[38] top.dram_tb.wb_in.dat[37] top.dram_tb.wb_in.dat[36] top.dram_tb.wb_in.dat[35] top.dram_tb.wb_in.dat[34] top.dram_tb.wb_in.dat[33] top.dram_tb.wb_in.dat[32] top.dram_tb.wb_in.dat[31] top.dram_tb.wb_in.dat[30] top.dram_tb.wb_in.dat[29] top.dram_tb.wb_in.dat[28] top.dram_tb.wb_in.dat[27] top.dram_tb.wb_in.dat[26] top.dram_tb.wb_in.dat[25] top.dram_tb.wb_in.dat[24] top.dram_tb.wb_in.dat[23] top.dram_tb.wb_in.dat[22] top.dram_tb.wb_in.dat[21] top.dram_tb.wb_in.dat[20] top.dram_tb.wb_in.dat[19] top.dram_tb.wb_in.dat[18] top.dram_tb.wb_in.dat[17] top.dram_tb.wb_in.dat[16] top.dram_tb.wb_in.dat[15] top.dram_tb.wb_in.dat[14] top.dram_tb.wb_in.dat[13] top.dram_tb.wb_in.dat[12] top.dram_tb.wb_in.dat[11] top.dram_tb.wb_in.dat[10] top.dram_tb.wb_in.dat[9] top.dram_tb.wb_in.dat[8] top.dram_tb.wb_in.dat[7] top.dram_tb.wb_in.dat[6] top.dram_tb.wb_in.dat[5] top.dram_tb.wb_in.dat[4] top.dram_tb.wb_in.dat[3] top.dram_tb.wb_in.dat[2] top.dram_tb.wb_in.dat[1] top.dram_tb.wb_in.dat[0]
|
||||
#{top.dram_tb.wb_in.adr[31:0]} top.dram_tb.wb_in.adr[31] top.dram_tb.wb_in.adr[30] top.dram_tb.wb_in.adr[29] top.dram_tb.wb_in.adr[28] top.dram_tb.wb_in.adr[27] top.dram_tb.wb_in.adr[26] top.dram_tb.wb_in.adr[25] top.dram_tb.wb_in.adr[24] top.dram_tb.wb_in.adr[23] top.dram_tb.wb_in.adr[22] top.dram_tb.wb_in.adr[21] top.dram_tb.wb_in.adr[20] top.dram_tb.wb_in.adr[19] top.dram_tb.wb_in.adr[18] top.dram_tb.wb_in.adr[17] top.dram_tb.wb_in.adr[16] top.dram_tb.wb_in.adr[15] top.dram_tb.wb_in.adr[14] top.dram_tb.wb_in.adr[13] top.dram_tb.wb_in.adr[12] top.dram_tb.wb_in.adr[11] top.dram_tb.wb_in.adr[10] top.dram_tb.wb_in.adr[9] top.dram_tb.wb_in.adr[8] top.dram_tb.wb_in.adr[7] top.dram_tb.wb_in.adr[6] top.dram_tb.wb_in.adr[5] top.dram_tb.wb_in.adr[4] top.dram_tb.wb_in.adr[3] top.dram_tb.wb_in.adr[2] top.dram_tb.wb_in.adr[1] top.dram_tb.wb_in.adr[0]
|
||||
@23
|
||||
#{top.dram_tb.wb_in.sel[7:0]} top.dram_tb.wb_in.sel[7] top.dram_tb.wb_in.sel[6] top.dram_tb.wb_in.sel[5] top.dram_tb.wb_in.sel[4] top.dram_tb.wb_in.sel[3] top.dram_tb.wb_in.sel[2] top.dram_tb.wb_in.sel[1] top.dram_tb.wb_in.sel[0]
|
||||
@28
|
||||
top.dram_tb.wb_in.cyc
|
||||
top.dram_tb.wb_in.stb
|
||||
top.dram_tb.wb_in.we
|
||||
top.dram_tb.wb_out.ack
|
||||
top.dram_tb.wb_out.stall
|
||||
@22
|
||||
#{top.dram_tb.wb_out.dat[63:0]} top.dram_tb.wb_out.dat[63] top.dram_tb.wb_out.dat[62] top.dram_tb.wb_out.dat[61] top.dram_tb.wb_out.dat[60] top.dram_tb.wb_out.dat[59] top.dram_tb.wb_out.dat[58] top.dram_tb.wb_out.dat[57] top.dram_tb.wb_out.dat[56] top.dram_tb.wb_out.dat[55] top.dram_tb.wb_out.dat[54] top.dram_tb.wb_out.dat[53] top.dram_tb.wb_out.dat[52] top.dram_tb.wb_out.dat[51] top.dram_tb.wb_out.dat[50] top.dram_tb.wb_out.dat[49] top.dram_tb.wb_out.dat[48] top.dram_tb.wb_out.dat[47] top.dram_tb.wb_out.dat[46] top.dram_tb.wb_out.dat[45] top.dram_tb.wb_out.dat[44] top.dram_tb.wb_out.dat[43] top.dram_tb.wb_out.dat[42] top.dram_tb.wb_out.dat[41] top.dram_tb.wb_out.dat[40] top.dram_tb.wb_out.dat[39] top.dram_tb.wb_out.dat[38] top.dram_tb.wb_out.dat[37] top.dram_tb.wb_out.dat[36] top.dram_tb.wb_out.dat[35] top.dram_tb.wb_out.dat[34] top.dram_tb.wb_out.dat[33] top.dram_tb.wb_out.dat[32] top.dram_tb.wb_out.dat[31] top.dram_tb.wb_out.dat[30] top.dram_tb.wb_out.dat[29] top.dram_tb.wb_out.dat[28] top.dram_tb.wb_out.dat[27] top.dram_tb.wb_out.dat[26] top.dram_tb.wb_out.dat[25] top.dram_tb.wb_out.dat[24] top.dram_tb.wb_out.dat[23] top.dram_tb.wb_out.dat[22] top.dram_tb.wb_out.dat[21] top.dram_tb.wb_out.dat[20] top.dram_tb.wb_out.dat[19] top.dram_tb.wb_out.dat[18] top.dram_tb.wb_out.dat[17] top.dram_tb.wb_out.dat[16] top.dram_tb.wb_out.dat[15] top.dram_tb.wb_out.dat[14] top.dram_tb.wb_out.dat[13] top.dram_tb.wb_out.dat[12] top.dram_tb.wb_out.dat[11] top.dram_tb.wb_out.dat[10] top.dram_tb.wb_out.dat[9] top.dram_tb.wb_out.dat[8] top.dram_tb.wb_out.dat[7] top.dram_tb.wb_out.dat[6] top.dram_tb.wb_out.dat[5] top.dram_tb.wb_out.dat[4] top.dram_tb.wb_out.dat[3] top.dram_tb.wb_out.dat[2] top.dram_tb.wb_out.dat[1] top.dram_tb.wb_out.dat[0]
|
||||
@28
|
||||
top.dram_tb.rd_valid
|
||||
top.dram_tb.rd_ready
|
||||
@22
|
||||
#{top.dram_tb.rd_data[63:0]} top.dram_tb.rd_data[63] top.dram_tb.rd_data[62] top.dram_tb.rd_data[61] top.dram_tb.rd_data[60] top.dram_tb.rd_data[59] top.dram_tb.rd_data[58] top.dram_tb.rd_data[57] top.dram_tb.rd_data[56] top.dram_tb.rd_data[55] top.dram_tb.rd_data[54] top.dram_tb.rd_data[53] top.dram_tb.rd_data[52] top.dram_tb.rd_data[51] top.dram_tb.rd_data[50] top.dram_tb.rd_data[49] top.dram_tb.rd_data[48] top.dram_tb.rd_data[47] top.dram_tb.rd_data[46] top.dram_tb.rd_data[45] top.dram_tb.rd_data[44] top.dram_tb.rd_data[43] top.dram_tb.rd_data[42] top.dram_tb.rd_data[41] top.dram_tb.rd_data[40] top.dram_tb.rd_data[39] top.dram_tb.rd_data[38] top.dram_tb.rd_data[37] top.dram_tb.rd_data[36] top.dram_tb.rd_data[35] top.dram_tb.rd_data[34] top.dram_tb.rd_data[33] top.dram_tb.rd_data[32] top.dram_tb.rd_data[31] top.dram_tb.rd_data[30] top.dram_tb.rd_data[29] top.dram_tb.rd_data[28] top.dram_tb.rd_data[27] top.dram_tb.rd_data[26] top.dram_tb.rd_data[25] top.dram_tb.rd_data[24] top.dram_tb.rd_data[23] top.dram_tb.rd_data[22] top.dram_tb.rd_data[21] top.dram_tb.rd_data[20] top.dram_tb.rd_data[19] top.dram_tb.rd_data[18] top.dram_tb.rd_data[17] top.dram_tb.rd_data[16] top.dram_tb.rd_data[15] top.dram_tb.rd_data[14] top.dram_tb.rd_data[13] top.dram_tb.rd_data[12] top.dram_tb.rd_data[11] top.dram_tb.rd_data[10] top.dram_tb.rd_data[9] top.dram_tb.rd_data[8] top.dram_tb.rd_data[7] top.dram_tb.rd_data[6] top.dram_tb.rd_data[5] top.dram_tb.rd_data[4] top.dram_tb.rd_data[3] top.dram_tb.rd_data[2] top.dram_tb.rd_data[1] top.dram_tb.rd_data[0]
|
||||
@200
|
||||
-
|
||||
-
|
||||
-wrapper
|
||||
@28
|
||||
top.dram_tb.dram.accept_store
|
||||
@420
|
||||
top.dram_tb.dram.req_op
|
||||
top.dram_tb.dram.state
|
||||
@28
|
||||
top.dram_tb.dram.read_ack_1
|
||||
top.dram_tb.dram.read_ack_0
|
||||
top.dram_tb.dram.storeq_wr_valid
|
||||
top.dram_tb.dram.storeq_wr_ready
|
||||
top.dram_tb.dram.storeq_rd_valid
|
||||
top.dram_tb.dram.storeq_rd_ready
|
||||
top.dram_tb.dram.user_port0_rdata_ready
|
||||
top.dram_tb.dram.user_port0_rdata_valid
|
||||
top.dram_tb.dram.user_port0_wdata_ready
|
||||
top.dram_tb.dram.user_port0_wdata_valid
|
||||
top.dram_tb.dram.user_port0_cmd_we
|
||||
top.dram_tb.dram.user_port0_cmd_ready
|
||||
top.dram_tb.dram.user_port0_cmd_valid
|
||||
top.dram_tb.dram.refill_cmd_valid
|
||||
@420
|
||||
top.dram_tb.dram.req_index
|
||||
top.dram_tb.dram.req_hit_way
|
||||
@28
|
||||
top.dram_tb.dram.req_ad3
|
||||
@420
|
||||
top.dram_tb.dram.refill_row
|
||||
top.dram_tb.dram.refill_index
|
||||
top.dram_tb.dram.refill_way
|
||||
@28
|
||||
top.dram_tb.dram.system_clk
|
||||
[pattern_trace] 1
|
||||
[pattern_trace] 0
|
@ -0,0 +1,43 @@
|
||||
# This file is Copyright (c) 2018-2019 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||
# License: BSD
|
||||
|
||||
{
|
||||
# General ------------------------------------------------------------------
|
||||
"cpu": "None", # Type of CPU used for init/calib (vexriscv, lm32)
|
||||
"cpu_variant":"standard",
|
||||
"speedgrade": -1, # FPGA speedgrade
|
||||
"memtype": "DDR3", # DRAM type
|
||||
"sim" : "True",
|
||||
|
||||
# PHY ----------------------------------------------------------------------
|
||||
"cmd_delay": 0, # Command additional delay (in taps)
|
||||
"cmd_latency": 0, # Command additional latency
|
||||
"sdram_module": "MT41K128M16", # SDRAM modules of the board or SO-DIMM
|
||||
"sdram_module_nb": 2, # Number of byte groups
|
||||
"sdram_rank_nb": 1, # Number of ranks
|
||||
"sdram_phy": "A7DDRPHY", # Type of FPGA PHY
|
||||
|
||||
# Electrical ---------------------------------------------------------------
|
||||
"rtt_nom": "60ohm", # Nominal termination
|
||||
"rtt_wr": "60ohm", # Write termination
|
||||
"ron": "34ohm", # Output driver impedance
|
||||
|
||||
# Frequency ----------------------------------------------------------------
|
||||
"input_clk_freq": 100e6, # Input clock frequency
|
||||
"sys_clk_freq": 100e6, # System clock frequency (DDR_clk = 4 x sys_clk)
|
||||
"iodelay_clk_freq": 200e6, # IODELAYs reference clock frequency
|
||||
|
||||
# Core ---------------------------------------------------------------------
|
||||
"cmd_buffer_depth": 16, # Depth of the command buffer
|
||||
|
||||
# User Ports ---------------------------------------------------------------
|
||||
"user_ports": {
|
||||
"native_0": {
|
||||
"type": "native",
|
||||
},
|
||||
},
|
||||
|
||||
# CSR Port -----------------------------------------------------------------
|
||||
"csr_alignment" : 32,
|
||||
"csr_data_width" : 32,
|
||||
}
|
@ -1,284 +0,0 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use std.textio.all;
|
||||
|
||||
library work;
|
||||
use work.wishbone_types.all;
|
||||
|
||||
entity litedram_wrapper is
|
||||
generic (
|
||||
DRAM_ABITS : positive;
|
||||
DRAM_ALINES : positive
|
||||
);
|
||||
port(
|
||||
-- LiteDRAM generates the system clock and reset
|
||||
-- from the input clkin
|
||||
clk_in : in std_ulogic;
|
||||
rst : in std_ulogic;
|
||||
system_clk : out std_ulogic;
|
||||
system_reset : out std_ulogic;
|
||||
core_alt_reset : out std_ulogic;
|
||||
pll_locked : out std_ulogic;
|
||||
|
||||
-- Wishbone ports:
|
||||
wb_in : in wishbone_master_out;
|
||||
wb_out : out wishbone_slave_out;
|
||||
wb_ctrl_in : in wb_io_master_out;
|
||||
wb_ctrl_out : out wb_io_slave_out;
|
||||
wb_ctrl_is_csr : in std_ulogic;
|
||||
wb_ctrl_is_init : in std_ulogic;
|
||||
|
||||
-- Init core serial debug
|
||||
serial_tx : out std_ulogic;
|
||||
serial_rx : in std_ulogic;
|
||||
|
||||
-- Misc
|
||||
init_done : out std_ulogic;
|
||||
init_error : out std_ulogic;
|
||||
|
||||
-- DRAM wires
|
||||
ddram_a : out std_ulogic_vector(DRAM_ALINES-1 downto 0);
|
||||
ddram_ba : out std_ulogic_vector(2 downto 0);
|
||||
ddram_ras_n : out std_ulogic;
|
||||
ddram_cas_n : out std_ulogic;
|
||||
ddram_we_n : out std_ulogic;
|
||||
ddram_cs_n : out std_ulogic;
|
||||
ddram_dm : out std_ulogic_vector(1 downto 0);
|
||||
ddram_dq : inout std_ulogic_vector(15 downto 0);
|
||||
ddram_dqs_p : inout std_ulogic_vector(1 downto 0);
|
||||
ddram_dqs_n : inout std_ulogic_vector(1 downto 0);
|
||||
ddram_clk_p : out std_ulogic;
|
||||
ddram_clk_n : out std_ulogic;
|
||||
ddram_cke : out std_ulogic;
|
||||
ddram_odt : out std_ulogic;
|
||||
ddram_reset_n : out std_ulogic
|
||||
);
|
||||
end entity litedram_wrapper;
|
||||
|
||||
architecture behaviour of litedram_wrapper is
|
||||
|
||||
component litedram_core port (
|
||||
clk : in std_ulogic;
|
||||
rst : in std_ulogic;
|
||||
pll_locked : out std_ulogic;
|
||||
ddram_a : out std_ulogic_vector(DRAM_ALINES-1 downto 0);
|
||||
ddram_ba : out std_ulogic_vector(2 downto 0);
|
||||
ddram_ras_n : out std_ulogic;
|
||||
ddram_cas_n : out std_ulogic;
|
||||
ddram_we_n : out std_ulogic;
|
||||
ddram_cs_n : out std_ulogic;
|
||||
ddram_dm : out std_ulogic_vector(1 downto 0);
|
||||
ddram_dq : inout std_ulogic_vector(15 downto 0);
|
||||
ddram_dqs_p : inout std_ulogic_vector(1 downto 0);
|
||||
ddram_dqs_n : inout std_ulogic_vector(1 downto 0);
|
||||
ddram_clk_p : out std_ulogic;
|
||||
ddram_clk_n : out std_ulogic;
|
||||
ddram_cke : out std_ulogic;
|
||||
ddram_odt : out std_ulogic;
|
||||
ddram_reset_n : out std_ulogic;
|
||||
init_done : out std_ulogic;
|
||||
init_error : out std_ulogic;
|
||||
user_clk : out std_ulogic;
|
||||
user_rst : out std_ulogic;
|
||||
wb_ctrl_adr : in std_ulogic_vector(29 downto 0);
|
||||
wb_ctrl_dat_w : in std_ulogic_vector(31 downto 0);
|
||||
wb_ctrl_dat_r : out std_ulogic_vector(31 downto 0);
|
||||
wb_ctrl_sel : in std_ulogic_vector(3 downto 0);
|
||||
wb_ctrl_cyc : in std_ulogic;
|
||||
wb_ctrl_stb : in std_ulogic;
|
||||
wb_ctrl_ack : out std_ulogic;
|
||||
wb_ctrl_we : in std_ulogic;
|
||||
wb_ctrl_cti : in std_ulogic_vector(2 downto 0);
|
||||
wb_ctrl_bte : in std_ulogic_vector(1 downto 0);
|
||||
wb_ctrl_err : out std_ulogic;
|
||||
user_port_native_0_cmd_valid : in std_ulogic;
|
||||
user_port_native_0_cmd_ready : out std_ulogic;
|
||||
user_port_native_0_cmd_we : in std_ulogic;
|
||||
user_port_native_0_cmd_addr : in std_ulogic_vector(DRAM_ABITS-1 downto 0);
|
||||
user_port_native_0_wdata_valid : in std_ulogic;
|
||||
user_port_native_0_wdata_ready : out std_ulogic;
|
||||
user_port_native_0_wdata_we : in std_ulogic_vector(15 downto 0);
|
||||
user_port_native_0_wdata_data : in std_ulogic_vector(127 downto 0);
|
||||
user_port_native_0_rdata_valid : out std_ulogic;
|
||||
user_port_native_0_rdata_ready : in std_ulogic;
|
||||
user_port_native_0_rdata_data : out std_ulogic_vector(127 downto 0)
|
||||
);
|
||||
end component;
|
||||
|
||||
signal user_port0_cmd_valid : std_ulogic;
|
||||
signal user_port0_cmd_ready : std_ulogic;
|
||||
signal user_port0_cmd_we : std_ulogic;
|
||||
signal user_port0_cmd_addr : std_ulogic_vector(DRAM_ABITS-1 downto 0);
|
||||
signal user_port0_wdata_valid : std_ulogic;
|
||||
signal user_port0_wdata_ready : std_ulogic;
|
||||
signal user_port0_wdata_we : std_ulogic_vector(15 downto 0);
|
||||
signal user_port0_wdata_data : std_ulogic_vector(127 downto 0);
|
||||
signal user_port0_rdata_valid : std_ulogic;
|
||||
signal user_port0_rdata_ready : std_ulogic;
|
||||
signal user_port0_rdata_data : std_ulogic_vector(127 downto 0);
|
||||
|
||||
signal ad3 : std_ulogic;
|
||||
|
||||
signal wb_ctrl_adr : std_ulogic_vector(29 downto 0);
|
||||
signal wb_ctrl_dat_w : std_ulogic_vector(31 downto 0);
|
||||
signal wb_ctrl_dat_r : std_ulogic_vector(31 downto 0);
|
||||
signal wb_ctrl_sel : std_ulogic_vector(3 downto 0);
|
||||
signal wb_ctrl_cyc : std_ulogic;
|
||||
signal wb_ctrl_stb : std_ulogic;
|
||||
signal wb_ctrl_ack : std_ulogic;
|
||||
signal wb_ctrl_we : std_ulogic;
|
||||
|
||||
signal wb_init_in : wb_io_master_out;
|
||||
signal wb_init_out : wb_io_slave_out;
|
||||
|
||||
type state_t is (CMD, MWRITE, MREAD);
|
||||
signal state : state_t;
|
||||
|
||||
begin
|
||||
|
||||
-- alternate core reset address set when DRAM is not initialized.
|
||||
core_alt_reset <= not init_done;
|
||||
|
||||
-- Init code BRAM memory slave
|
||||
init_ram_0: entity work.dram_init_mem
|
||||
port map(
|
||||
clk => system_clk,
|
||||
wb_in => wb_init_in,
|
||||
wb_out => wb_init_out
|
||||
);
|
||||
|
||||
--
|
||||
-- Control bus wishbone: This muxes the wishbone to the CSRs
|
||||
-- and an internal small one to the init BRAM
|
||||
--
|
||||
|
||||
-- Init DRAM wishbone IN signals
|
||||
wb_init_in.adr <= wb_ctrl_in.adr;
|
||||
wb_init_in.dat <= wb_ctrl_in.dat;
|
||||
wb_init_in.sel <= wb_ctrl_in.sel;
|
||||
wb_init_in.we <= wb_ctrl_in.we;
|
||||
wb_init_in.stb <= wb_ctrl_in.stb;
|
||||
wb_init_in.cyc <= wb_ctrl_in.cyc and wb_ctrl_is_init;
|
||||
|
||||
-- DRAM CSR IN signals
|
||||
wb_ctrl_adr <= x"0000" & wb_ctrl_in.adr(15 downto 2);
|
||||
wb_ctrl_dat_w <= wb_ctrl_in.dat;
|
||||
wb_ctrl_sel <= wb_ctrl_in.sel;
|
||||
wb_ctrl_we <= wb_ctrl_in.we;
|
||||
wb_ctrl_cyc <= wb_ctrl_in.cyc and wb_ctrl_is_csr;
|
||||
wb_ctrl_stb <= wb_ctrl_in.stb and wb_ctrl_is_csr;
|
||||
|
||||
-- Ctrl bus wishbone OUT signals
|
||||
wb_ctrl_out.ack <= wb_ctrl_ack when wb_ctrl_is_csr = '1'
|
||||
else wb_init_out.ack;
|
||||
wb_ctrl_out.dat <= wb_ctrl_dat_r when wb_ctrl_is_csr = '1'
|
||||
else wb_init_out.dat;
|
||||
wb_ctrl_out.stall <= wb_init_out.stall when wb_ctrl_is_init else
|
||||
'0' when wb_ctrl_in.cyc = '0' else not wb_ctrl_ack;
|
||||
|
||||
--
|
||||
-- Data bus wishbone to LiteDRAM native port
|
||||
--
|
||||
-- Address bit 3 selects the top or bottom half of the data
|
||||
-- bus (64-bit wishbone vs. 128-bit DRAM interface)
|
||||
--
|
||||
-- XXX TODO: Figure out how to pipeline this
|
||||
--
|
||||
ad3 <= wb_in.adr(3);
|
||||
|
||||
-- Wishbone port IN signals
|
||||
user_port0_cmd_valid <= wb_in.cyc and wb_in.stb when state = CMD else '0';
|
||||
user_port0_cmd_we <= wb_in.we when state = CMD else '0';
|
||||
user_port0_wdata_valid <= '1' when state = MWRITE else '0';
|
||||
user_port0_rdata_ready <= '1' when state = MREAD else '0';
|
||||
user_port0_cmd_addr <= wb_in.adr(DRAM_ABITS+3 downto 4);
|
||||
user_port0_wdata_data <= wb_in.dat & wb_in.dat;
|
||||
user_port0_wdata_we <= wb_in.sel & "00000000" when ad3 = '1' else
|
||||
"00000000" & wb_in.sel;
|
||||
|
||||
-- Wishbone OUT signals
|
||||
wb_out.ack <= user_port0_wdata_ready when state = MWRITE else
|
||||
user_port0_rdata_valid when state = MREAD else '0';
|
||||
|
||||
wb_out.dat <= user_port0_rdata_data(127 downto 64) when ad3 = '1' else
|
||||
user_port0_rdata_data(63 downto 0);
|
||||
|
||||
-- We don't do pipelining yet.
|
||||
wb_out.stall <= '0' when wb_in.cyc = '0' else not wb_out.ack;
|
||||
|
||||
-- DRAM user port State machine
|
||||
sm: process(system_clk)
|
||||
begin
|
||||
|
||||
if rising_edge(system_clk) then
|
||||
if system_reset = '1' then
|
||||
state <= CMD;
|
||||
else
|
||||
case state is
|
||||
when CMD =>
|
||||
if (user_port0_cmd_ready and user_port0_cmd_valid) = '1' then
|
||||
state <= MWRITE when wb_in.we = '1' else MREAD;
|
||||
end if;
|
||||
when MWRITE =>
|
||||
if user_port0_wdata_ready = '1' then
|
||||
state <= CMD;
|
||||
end if;
|
||||
when MREAD =>
|
||||
if user_port0_rdata_valid = '1' then
|
||||
state <= CMD;
|
||||
end if;
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
litedram: litedram_core
|
||||
port map(
|
||||
clk => clk_in,
|
||||
rst => rst,
|
||||
pll_locked => pll_locked,
|
||||
ddram_a => ddram_a,
|
||||
ddram_ba => ddram_ba,
|
||||
ddram_ras_n => ddram_ras_n,
|
||||
ddram_cas_n => ddram_cas_n,
|
||||
ddram_we_n => ddram_we_n,
|
||||
ddram_cs_n => ddram_cs_n,
|
||||
ddram_dm => ddram_dm,
|
||||
ddram_dq => ddram_dq,
|
||||
ddram_dqs_p => ddram_dqs_p,
|
||||
ddram_dqs_n => ddram_dqs_n,
|
||||
ddram_clk_p => ddram_clk_p,
|
||||
ddram_clk_n => ddram_clk_n,
|
||||
ddram_cke => ddram_cke,
|
||||
ddram_odt => ddram_odt,
|
||||
ddram_reset_n => ddram_reset_n,
|
||||
init_done => init_done,
|
||||
init_error => init_error,
|
||||
user_clk => system_clk,
|
||||
user_rst => system_reset,
|
||||
wb_ctrl_adr => wb_ctrl_adr,
|
||||
wb_ctrl_dat_w => wb_ctrl_dat_w,
|
||||
wb_ctrl_dat_r => wb_ctrl_dat_r,
|
||||
wb_ctrl_sel => wb_ctrl_sel,
|
||||
wb_ctrl_cyc => wb_ctrl_cyc,
|
||||
wb_ctrl_stb => wb_ctrl_stb,
|
||||
wb_ctrl_ack => wb_ctrl_ack,
|
||||
wb_ctrl_we => wb_ctrl_we,
|
||||
wb_ctrl_cti => "000",
|
||||
wb_ctrl_bte => "00",
|
||||
wb_ctrl_err => open,
|
||||
user_port_native_0_cmd_valid => user_port0_cmd_valid,
|
||||
user_port_native_0_cmd_ready => user_port0_cmd_ready,
|
||||
user_port_native_0_cmd_we => user_port0_cmd_we,
|
||||
user_port_native_0_cmd_addr => user_port0_cmd_addr,
|
||||
user_port_native_0_wdata_valid => user_port0_wdata_valid,
|
||||
user_port_native_0_wdata_ready => user_port0_wdata_ready,
|
||||
user_port_native_0_wdata_we => user_port0_wdata_we,
|
||||
user_port_native_0_wdata_data => user_port0_wdata_data,
|
||||
user_port_native_0_rdata_valid => user_port0_rdata_valid,
|
||||
user_port_native_0_rdata_ready => user_port0_rdata_ready,
|
||||
user_port_native_0_rdata_data => user_port0_rdata_data
|
||||
);
|
||||
|
||||
end architecture behaviour;
|
@ -1,225 +0,0 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use std.textio.all;
|
||||
|
||||
library work;
|
||||
use work.wishbone_types.all;
|
||||
|
||||
entity litedram_wrapper is
|
||||
generic (
|
||||
DRAM_ABITS : positive;
|
||||
DRAM_ALINES : positive
|
||||
);
|
||||
port(
|
||||
-- LiteDRAM generates the system clock and reset
|
||||
-- from the input clkin
|
||||
clk_in : in std_ulogic;
|
||||
rst : in std_ulogic;
|
||||
system_clk : out std_ulogic;
|
||||
system_reset : out std_ulogic;
|
||||
core_alt_reset : out std_ulogic;
|
||||
pll_locked : out std_ulogic;
|
||||
|
||||
-- Wishbone ports:
|
||||
wb_in : in wishbone_master_out;
|
||||
wb_out : out wishbone_slave_out;
|
||||
wb_ctrl_in : in wb_io_master_out;
|
||||
wb_ctrl_out : out wb_io_slave_out;
|
||||
wb_ctrl_is_csr : in std_ulogic;
|
||||
wb_ctrl_is_init : in std_ulogic;
|
||||
|
||||
-- Init core serial debug
|
||||
serial_tx : out std_ulogic;
|
||||
serial_rx : in std_ulogic;
|
||||
|
||||
-- Misc
|
||||
init_done : out std_ulogic;
|
||||
init_error : out std_ulogic;
|
||||
|
||||
-- DRAM wires
|
||||
ddram_a : out std_ulogic_vector(DRAM_ALINES-1 downto 0);
|
||||
ddram_ba : out std_ulogic_vector(2 downto 0);
|
||||
ddram_ras_n : out std_ulogic;
|
||||
ddram_cas_n : out std_ulogic;
|
||||
ddram_we_n : out std_ulogic;
|
||||
ddram_cs_n : out std_ulogic;
|
||||
ddram_dm : out std_ulogic_vector(1 downto 0);
|
||||
ddram_dq : inout std_ulogic_vector(15 downto 0);
|
||||
ddram_dqs_p : inout std_ulogic_vector(1 downto 0);
|
||||
ddram_dqs_n : inout std_ulogic_vector(1 downto 0);
|
||||
ddram_clk_p : out std_ulogic;
|
||||
ddram_clk_n : out std_ulogic;
|
||||
ddram_cke : out std_ulogic;
|
||||
ddram_odt : out std_ulogic;
|
||||
ddram_reset_n : out std_ulogic
|
||||
end entity litedram_wrapper;
|
||||
|
||||
architecture behaviour of litedram_wrapper is
|
||||
|
||||
component litedram_core port (
|
||||
clk : in std_ulogic;
|
||||
rst : in std_ulogic;
|
||||
serial_tx : out std_ulogic;
|
||||
serial_rx : in std_ulogic;
|
||||
pll_locked : out std_ulogic;
|
||||
ddram_a : out std_ulogic_vector(DRAM_ALINES-1 downto 0);
|
||||
ddram_ba : out std_ulogic_vector(2 downto 0);
|
||||
ddram_ras_n : out std_ulogic;
|
||||
ddram_cas_n : out std_ulogic;
|
||||
ddram_we_n : out std_ulogic;
|
||||
ddram_cs_n : out std_ulogic;
|
||||
ddram_dm : out std_ulogic_vector(1 downto 0);
|
||||
ddram_dq : inout std_ulogic_vector(15 downto 0);
|
||||
ddram_dqs_p : inout std_ulogic_vector(1 downto 0);
|
||||
ddram_dqs_n : inout std_ulogic_vector(1 downto 0);
|
||||
ddram_clk_p : out std_ulogic;
|
||||
ddram_clk_n : out std_ulogic;
|
||||
ddram_cke : out std_ulogic;
|
||||
ddram_odt : out std_ulogic;
|
||||
ddram_reset_n : out std_ulogic;
|
||||
init_done : out std_ulogic;
|
||||
init_error : out std_ulogic;
|
||||
user_clk : out std_ulogic;
|
||||
user_rst : out std_ulogic;
|
||||
user_port_native_0_cmd_valid : in std_ulogic;
|
||||
user_port_native_0_cmd_ready : out std_ulogic;
|
||||
user_port_native_0_cmd_we : in std_ulogic;
|
||||
user_port_native_0_cmd_addr : in std_ulogic_vector(DRAM_ABITS-1 downto 0);
|
||||
user_port_native_0_wdata_valid : in std_ulogic;
|
||||
user_port_native_0_wdata_ready : out std_ulogic;
|
||||
user_port_native_0_wdata_we : in std_ulogic_vector(15 downto 0);
|
||||
user_port_native_0_wdata_data : in std_ulogic_vector(127 downto 0);
|
||||
user_port_native_0_rdata_valid : out std_ulogic;
|
||||
user_port_native_0_rdata_ready : in std_ulogic;
|
||||
user_port_native_0_rdata_data : out std_ulogic_vector(127 downto 0)
|
||||
);
|
||||
end component;
|
||||
|
||||
signal user_port0_cmd_valid : std_ulogic;
|
||||
signal user_port0_cmd_ready : std_ulogic;
|
||||
signal user_port0_cmd_we : std_ulogic;
|
||||
signal user_port0_cmd_addr : std_ulogic_vector(DRAM_ABITS-1 downto 0);
|
||||
signal user_port0_wdata_valid : std_ulogic;
|
||||
signal user_port0_wdata_ready : std_ulogic;
|
||||
signal user_port0_wdata_we : std_ulogic_vector(15 downto 0);
|
||||
signal user_port0_wdata_data : std_ulogic_vector(127 downto 0);
|
||||
signal user_port0_rdata_valid : std_ulogic;
|
||||
signal user_port0_rdata_ready : std_ulogic;
|
||||
signal user_port0_rdata_data : std_ulogic_vector(127 downto 0);
|
||||
|
||||
signal ad3 : std_ulogic;
|
||||
|
||||
signal dram_user_reset : std_ulogic;
|
||||
|
||||
type state_t is (CMD, MWRITE, MREAD);
|
||||
signal state : state_t;
|
||||
|
||||
begin
|
||||
|
||||
-- Reset, lift it when init done, no alt core reset
|
||||
system_reset <= dram_user_reset or not init_done;
|
||||
core_alt_reset <= '0';
|
||||
|
||||
-- Control bus is unused
|
||||
wb_ctrl_out.ack <= (wb_is_ctrl = '1' or wb_is_init = '1') and wb_ctrl_in.cyc;
|
||||
else wb_init_out.ack;
|
||||
wb_ctrl_out.dat <= (others => '0');
|
||||
wb_ctrl_out.stall <= '0';
|
||||
|
||||
--
|
||||
-- Data bus wishbone to LiteDRAM native port
|
||||
--
|
||||
-- Address bit 3 selects the top or bottom half of the data
|
||||
-- bus (64-bit wishbone vs. 128-bit DRAM interface)
|
||||
--
|
||||
-- XXX TODO: Figure out how to pipeline this
|
||||
--
|
||||
ad3 <= wb_in.adr(3);
|
||||
|
||||
-- Wishbone port IN signals
|
||||
user_port0_cmd_valid <= wb_in.cyc and wb_in.stb when state = CMD else '0';
|
||||
user_port0_cmd_we <= wb_in.we when state = CMD else '0';
|
||||
user_port0_wdata_valid <= '1' when state = MWRITE else '0';
|
||||
user_port0_rdata_ready <= '1' when state = MREAD else '0';
|
||||
user_port0_cmd_addr <= wb_in.adr(DRAM_ABITS+3 downto 4);
|
||||
user_port0_wdata_data <= wb_in.dat & wb_in.dat;
|
||||
user_port0_wdata_we <= wb_in.sel & "00000000" when ad3 = '1' else
|
||||
"00000000" & wb_in.sel;
|
||||
|
||||
-- Wishbone OUT signals
|
||||
wb_out.ack <= user_port0_wdata_ready when state = MWRITE else
|
||||
user_port0_rdata_valid when state = MREAD else '0';
|
||||
|
||||
wb_out.dat <= user_port0_rdata_data(127 downto 64) when ad3 = '1' else
|
||||
user_port0_rdata_data(63 downto 0);
|
||||
|
||||
-- We don't do pipelining yet.
|
||||
wb_out.stall <= '0' when wb_in.cyc = '0' else not wb_out.ack;
|
||||
|
||||
-- DRAM user port State machine
|
||||
sm: process(system_clk)
|
||||
begin
|
||||
|
||||
if rising_edge(system_clk) then
|
||||
if dram_user_reset = '1' then
|
||||
state <= CMD;
|
||||
else
|
||||
case state is
|
||||
when CMD =>
|
||||
if (user_port0_cmd_ready and user_port0_cmd_valid) = '1' then
|
||||
state <= MWRITE when wb_in.we = '1' else MREAD;
|
||||
end if;
|
||||
when MWRITE =>
|
||||
if user_port0_wdata_ready = '1' then
|
||||
state <= CMD;
|
||||
end if;
|
||||
when MREAD =>
|
||||
if user_port0_rdata_valid = '1' then
|
||||
state <= CMD;
|
||||
end if;
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
litedram: litedram_core
|
||||
port map(
|
||||
clk => clk_in,
|
||||
rst => rst,
|
||||
serial_tx => serial_tx,
|
||||
serial_rx => serial_rx,
|
||||
pll_locked => pll_locked,
|
||||
ddram_a => ddram_a,
|
||||
ddram_ba => ddram_ba,
|
||||
ddram_ras_n => ddram_ras_n,
|
||||
ddram_cas_n => ddram_cas_n,
|
||||
ddram_we_n => ddram_we_n,
|
||||
ddram_cs_n => ddram_cs_n,
|
||||
ddram_dm => ddram_dm,
|
||||
ddram_dq => ddram_dq,
|
||||
ddram_dqs_p => ddram_dqs_p,
|
||||
ddram_dqs_n => ddram_dqs_n,
|
||||
ddram_clk_p => ddram_clk_p,
|
||||
ddram_clk_n => ddram_clk_n,
|
||||
ddram_cke => ddram_cke,
|
||||
ddram_odt => ddram_odt,
|
||||
ddram_reset_n => ddram_reset_n,
|
||||
init_done => init_done,
|
||||
init_error => init_error,
|
||||
user_clk => system_clk,
|
||||
user_rst => dram_user_reset,
|
||||
user_port_native_0_cmd_valid => user_port0_cmd_valid,
|
||||
user_port_native_0_cmd_ready => user_port0_cmd_ready,
|
||||
user_port_native_0_cmd_we => user_port0_cmd_we,
|
||||
user_port_native_0_cmd_addr => user_port0_cmd_addr,
|
||||
user_port_native_0_wdata_valid => user_port0_wdata_valid,
|
||||
user_port_native_0_wdata_ready => user_port0_wdata_ready,
|
||||
user_port_native_0_wdata_we => user_port0_wdata_we,
|
||||
user_port_native_0_wdata_data => user_port0_wdata_data,
|
||||
user_port_native_0_rdata_valid => user_port0_rdata_valid,
|
||||
user_port_native_0_rdata_ready => user_port0_rdata_ready,
|
||||
user_port_native_0_rdata_data => user_port0_rdata_data
|
||||
);
|
||||
|
||||
end architecture behaviour;
|
@ -1,284 +0,0 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use std.textio.all;
|
||||
|
||||
library work;
|
||||
use work.wishbone_types.all;
|
||||
|
||||
entity litedram_wrapper is
|
||||
generic (
|
||||
DRAM_ABITS : positive;
|
||||
DRAM_ALINES : positive
|
||||
);
|
||||
port(
|
||||
-- LiteDRAM generates the system clock and reset
|
||||
-- from the input clkin
|
||||
clk_in : in std_ulogic;
|
||||
rst : in std_ulogic;
|
||||
system_clk : out std_ulogic;
|
||||
system_reset : out std_ulogic;
|
||||
core_alt_reset : out std_ulogic;
|
||||
pll_locked : out std_ulogic;
|
||||
|
||||
-- Wishbone ports:
|
||||
wb_in : in wishbone_master_out;
|
||||
wb_out : out wishbone_slave_out;
|
||||
wb_ctrl_in : in wb_io_master_out;
|
||||
wb_ctrl_out : out wb_io_slave_out;
|
||||
wb_ctrl_is_csr : in std_ulogic;
|
||||
wb_ctrl_is_init : in std_ulogic;
|
||||
|
||||
-- Init core serial debug
|
||||
serial_tx : out std_ulogic;
|
||||
serial_rx : in std_ulogic;
|
||||
|
||||
-- Misc
|
||||
init_done : out std_ulogic;
|
||||
init_error : out std_ulogic;
|
||||
|
||||
-- DRAM wires
|
||||
ddram_a : out std_ulogic_vector(DRAM_ALINES-1 downto 0);
|
||||
ddram_ba : out std_ulogic_vector(2 downto 0);
|
||||
ddram_ras_n : out std_ulogic;
|
||||
ddram_cas_n : out std_ulogic;
|
||||
ddram_we_n : out std_ulogic;
|
||||
ddram_cs_n : out std_ulogic;
|
||||
ddram_dm : out std_ulogic_vector(1 downto 0);
|
||||
ddram_dq : inout std_ulogic_vector(15 downto 0);
|
||||
ddram_dqs_p : inout std_ulogic_vector(1 downto 0);
|
||||
ddram_dqs_n : inout std_ulogic_vector(1 downto 0);
|
||||
ddram_clk_p : out std_ulogic;
|
||||
ddram_clk_n : out std_ulogic;
|
||||
ddram_cke : out std_ulogic;
|
||||
ddram_odt : out std_ulogic;
|
||||
ddram_reset_n : out std_ulogic
|
||||
);
|
||||
end entity litedram_wrapper;
|
||||
|
||||
architecture behaviour of litedram_wrapper is
|
||||
|
||||
component litedram_core port (
|
||||
clk : in std_ulogic;
|
||||
rst : in std_ulogic;
|
||||
pll_locked : out std_ulogic;
|
||||
ddram_a : out std_ulogic_vector(DRAM_ALINES-1 downto 0);
|
||||
ddram_ba : out std_ulogic_vector(2 downto 0);
|
||||
ddram_ras_n : out std_ulogic;
|
||||
ddram_cas_n : out std_ulogic;
|
||||
ddram_we_n : out std_ulogic;
|
||||
ddram_cs_n : out std_ulogic;
|
||||
ddram_dm : out std_ulogic_vector(1 downto 0);
|
||||
ddram_dq : inout std_ulogic_vector(15 downto 0);
|
||||
ddram_dqs_p : inout std_ulogic_vector(1 downto 0);
|
||||
ddram_dqs_n : inout std_ulogic_vector(1 downto 0);
|
||||
ddram_clk_p : out std_ulogic;
|
||||
ddram_clk_n : out std_ulogic;
|
||||
ddram_cke : out std_ulogic;
|
||||
ddram_odt : out std_ulogic;
|
||||
ddram_reset_n : out std_ulogic;
|
||||
init_done : out std_ulogic;
|
||||
init_error : out std_ulogic;
|
||||
user_clk : out std_ulogic;
|
||||
user_rst : out std_ulogic;
|
||||
wb_ctrl_adr : in std_ulogic_vector(29 downto 0);
|
||||
wb_ctrl_dat_w : in std_ulogic_vector(31 downto 0);
|
||||
wb_ctrl_dat_r : out std_ulogic_vector(31 downto 0);
|
||||
wb_ctrl_sel : in std_ulogic_vector(3 downto 0);
|
||||
wb_ctrl_cyc : in std_ulogic;
|
||||
wb_ctrl_stb : in std_ulogic;
|
||||
wb_ctrl_ack : out std_ulogic;
|
||||
wb_ctrl_we : in std_ulogic;
|
||||
wb_ctrl_cti : in std_ulogic_vector(2 downto 0);
|
||||
wb_ctrl_bte : in std_ulogic_vector(1 downto 0);
|
||||
wb_ctrl_err : out std_ulogic;
|
||||
user_port_native_0_cmd_valid : in std_ulogic;
|
||||
user_port_native_0_cmd_ready : out std_ulogic;
|
||||
user_port_native_0_cmd_we : in std_ulogic;
|
||||
user_port_native_0_cmd_addr : in std_ulogic_vector(DRAM_ABITS-1 downto 0);
|
||||
user_port_native_0_wdata_valid : in std_ulogic;
|
||||
user_port_native_0_wdata_ready : out std_ulogic;
|
||||
user_port_native_0_wdata_we : in std_ulogic_vector(15 downto 0);
|
||||
user_port_native_0_wdata_data : in std_ulogic_vector(127 downto 0);
|
||||
user_port_native_0_rdata_valid : out std_ulogic;
|
||||
user_port_native_0_rdata_ready : in std_ulogic;
|
||||
user_port_native_0_rdata_data : out std_ulogic_vector(127 downto 0)
|
||||
);
|
||||
end component;
|
||||
|
||||
signal user_port0_cmd_valid : std_ulogic;
|
||||
signal user_port0_cmd_ready : std_ulogic;
|
||||
signal user_port0_cmd_we : std_ulogic;
|
||||
signal user_port0_cmd_addr : std_ulogic_vector(DRAM_ABITS-1 downto 0);
|
||||
signal user_port0_wdata_valid : std_ulogic;
|
||||
signal user_port0_wdata_ready : std_ulogic;
|
||||
signal user_port0_wdata_we : std_ulogic_vector(15 downto 0);
|
||||
signal user_port0_wdata_data : std_ulogic_vector(127 downto 0);
|
||||
signal user_port0_rdata_valid : std_ulogic;
|
||||
signal user_port0_rdata_ready : std_ulogic;
|
||||
signal user_port0_rdata_data : std_ulogic_vector(127 downto 0);
|
||||
|
||||
signal ad3 : std_ulogic;
|
||||
|
||||
signal wb_ctrl_adr : std_ulogic_vector(29 downto 0);
|
||||
signal wb_ctrl_dat_w : std_ulogic_vector(31 downto 0);
|
||||
signal wb_ctrl_dat_r : std_ulogic_vector(31 downto 0);
|
||||
signal wb_ctrl_sel : std_ulogic_vector(3 downto 0);
|
||||
signal wb_ctrl_cyc : std_ulogic;
|
||||
signal wb_ctrl_stb : std_ulogic;
|
||||
signal wb_ctrl_ack : std_ulogic;
|
||||
signal wb_ctrl_we : std_ulogic;
|
||||
|
||||
signal wb_init_in : wb_io_master_out;
|
||||
signal wb_init_out : wb_io_slave_out;
|
||||
|
||||
type state_t is (CMD, MWRITE, MREAD);
|
||||
signal state : state_t;
|
||||
|
||||
begin
|
||||
|
||||
-- alternate core reset address set when DRAM is not initialized.
|
||||
core_alt_reset <= not init_done;
|
||||
|
||||
-- Init code BRAM memory slave
|
||||
init_ram_0: entity work.dram_init_mem
|
||||
port map(
|
||||
clk => system_clk,
|
||||
wb_in => wb_init_in,
|
||||
wb_out => wb_init_out
|
||||
);
|
||||
|
||||
--
|
||||
-- Control bus wishbone: This muxes the wishbone to the CSRs
|
||||
-- and an internal small one to the init BRAM
|
||||
--
|
||||
|
||||
-- Init DRAM wishbone IN signals
|
||||
wb_init_in.adr <= wb_ctrl_in.adr;
|
||||
wb_init_in.dat <= wb_ctrl_in.dat;
|
||||
wb_init_in.sel <= wb_ctrl_in.sel;
|
||||
wb_init_in.we <= wb_ctrl_in.we;
|
||||
wb_init_in.stb <= wb_ctrl_in.stb;
|
||||
wb_init_in.cyc <= wb_ctrl_in.cyc and wb_ctrl_is_init;
|
||||
|
||||
-- DRAM CSR IN signals
|
||||
wb_ctrl_adr <= x"0000" & wb_ctrl_in.adr(15 downto 2);
|
||||
wb_ctrl_dat_w <= wb_ctrl_in.dat;
|
||||
wb_ctrl_sel <= wb_ctrl_in.sel;
|
||||
wb_ctrl_we <= wb_ctrl_in.we;
|
||||
wb_ctrl_cyc <= wb_ctrl_in.cyc and wb_ctrl_is_csr;
|
||||
wb_ctrl_stb <= wb_ctrl_in.stb and wb_ctrl_is_csr;
|
||||
|
||||
-- Ctrl bus wishbone OUT signals
|
||||
wb_ctrl_out.ack <= wb_ctrl_ack when wb_ctrl_is_csr = '1'
|
||||
else wb_init_out.ack;
|
||||
wb_ctrl_out.dat <= wb_ctrl_dat_r when wb_ctrl_is_csr = '1'
|
||||
else wb_init_out.dat;
|
||||
wb_ctrl_out.stall <= wb_init_out.stall when wb_ctrl_is_init else
|
||||
'0' when wb_ctrl_in.cyc = '0' else not wb_ctrl_ack;
|
||||
|
||||
--
|
||||
-- Data bus wishbone to LiteDRAM native port
|
||||
--
|
||||
-- Address bit 3 selects the top or bottom half of the data
|
||||
-- bus (64-bit wishbone vs. 128-bit DRAM interface)
|
||||
--
|
||||
-- XXX TODO: Figure out how to pipeline this
|
||||
--
|
||||
ad3 <= wb_in.adr(3);
|
||||
|
||||
-- Wishbone port IN signals
|
||||
user_port0_cmd_valid <= wb_in.cyc and wb_in.stb when state = CMD else '0';
|
||||
user_port0_cmd_we <= wb_in.we when state = CMD else '0';
|
||||
user_port0_wdata_valid <= '1' when state = MWRITE else '0';
|
||||
user_port0_rdata_ready <= '1' when state = MREAD else '0';
|
||||
user_port0_cmd_addr <= wb_in.adr(DRAM_ABITS+3 downto 4);
|
||||
user_port0_wdata_data <= wb_in.dat & wb_in.dat;
|
||||
user_port0_wdata_we <= wb_in.sel & "00000000" when ad3 = '1' else
|
||||
"00000000" & wb_in.sel;
|
||||
|
||||
-- Wishbone OUT signals
|
||||
wb_out.ack <= user_port0_wdata_ready when state = MWRITE else
|
||||
user_port0_rdata_valid when state = MREAD else '0';
|
||||
|
||||
wb_out.dat <= user_port0_rdata_data(127 downto 64) when ad3 = '1' else
|
||||
user_port0_rdata_data(63 downto 0);
|
||||
|
||||
-- We don't do pipelining yet.
|
||||
wb_out.stall <= '0' when wb_in.cyc = '0' else not wb_out.ack;
|
||||
|
||||
-- DRAM user port State machine
|
||||
sm: process(system_clk)
|
||||
begin
|
||||
|
||||
if rising_edge(system_clk) then
|
||||
if system_reset = '1' then
|
||||
state <= CMD;
|
||||
else
|
||||
case state is
|
||||
when CMD =>
|
||||
if (user_port0_cmd_ready and user_port0_cmd_valid) = '1' then
|
||||
state <= MWRITE when wb_in.we = '1' else MREAD;
|
||||
end if;
|
||||
when MWRITE =>
|
||||
if user_port0_wdata_ready = '1' then
|
||||
state <= CMD;
|
||||
end if;
|
||||
when MREAD =>
|
||||
if user_port0_rdata_valid = '1' then
|
||||
state <= CMD;
|
||||
end if;
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
litedram: litedram_core
|
||||
port map(
|
||||
clk => clk_in,
|
||||
rst => rst,
|
||||
pll_locked => pll_locked,
|
||||
ddram_a => ddram_a,
|
||||
ddram_ba => ddram_ba,
|
||||
ddram_ras_n => ddram_ras_n,
|
||||
ddram_cas_n => ddram_cas_n,
|
||||
ddram_we_n => ddram_we_n,
|
||||
ddram_cs_n => ddram_cs_n,
|
||||
ddram_dm => ddram_dm,
|
||||
ddram_dq => ddram_dq,
|
||||
ddram_dqs_p => ddram_dqs_p,
|
||||
ddram_dqs_n => ddram_dqs_n,
|
||||
ddram_clk_p => ddram_clk_p,
|
||||
ddram_clk_n => ddram_clk_n,
|
||||
ddram_cke => ddram_cke,
|
||||
ddram_odt => ddram_odt,
|
||||
ddram_reset_n => ddram_reset_n,
|
||||
init_done => init_done,
|
||||
init_error => init_error,
|
||||
user_clk => system_clk,
|
||||
user_rst => system_reset,
|
||||
wb_ctrl_adr => wb_ctrl_adr,
|
||||
wb_ctrl_dat_w => wb_ctrl_dat_w,
|
||||
wb_ctrl_dat_r => wb_ctrl_dat_r,
|
||||
wb_ctrl_sel => wb_ctrl_sel,
|
||||
wb_ctrl_cyc => wb_ctrl_cyc,
|
||||
wb_ctrl_stb => wb_ctrl_stb,
|
||||
wb_ctrl_ack => wb_ctrl_ack,
|
||||
wb_ctrl_we => wb_ctrl_we,
|
||||
wb_ctrl_cti => "000",
|
||||
wb_ctrl_bte => "00",
|
||||
wb_ctrl_err => open,
|
||||
user_port_native_0_cmd_valid => user_port0_cmd_valid,
|
||||
user_port_native_0_cmd_ready => user_port0_cmd_ready,
|
||||
user_port_native_0_cmd_we => user_port0_cmd_we,
|
||||
user_port_native_0_cmd_addr => user_port0_cmd_addr,
|
||||
user_port_native_0_wdata_valid => user_port0_wdata_valid,
|
||||
user_port_native_0_wdata_ready => user_port0_wdata_ready,
|
||||
user_port_native_0_wdata_we => user_port0_wdata_we,
|
||||
user_port_native_0_wdata_data => user_port0_wdata_data,
|
||||
user_port_native_0_rdata_valid => user_port0_rdata_valid,
|
||||
user_port_native_0_rdata_ready => user_port0_rdata_ready,
|
||||
user_port_native_0_rdata_data => user_port0_rdata_data
|
||||
);
|
||||
|
||||
end architecture behaviour;
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,284 +0,0 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use std.textio.all;
|
||||
|
||||
library work;
|
||||
use work.wishbone_types.all;
|
||||
|
||||
entity litedram_wrapper is
|
||||
generic (
|
||||
DRAM_ABITS : positive;
|
||||
DRAM_ALINES : positive
|
||||
);
|
||||
port(
|
||||
-- LiteDRAM generates the system clock and reset
|
||||
-- from the input clkin
|
||||
clk_in : in std_ulogic;
|
||||
rst : in std_ulogic;
|
||||
system_clk : out std_ulogic;
|
||||
system_reset : out std_ulogic;
|
||||
core_alt_reset : out std_ulogic;
|
||||
pll_locked : out std_ulogic;
|
||||
|
||||
-- Wishbone ports:
|
||||
wb_in : in wishbone_master_out;
|
||||
wb_out : out wishbone_slave_out;
|
||||
wb_ctrl_in : in wb_io_master_out;
|
||||
wb_ctrl_out : out wb_io_slave_out;
|
||||
wb_ctrl_is_csr : in std_ulogic;
|
||||
wb_ctrl_is_init : in std_ulogic;
|
||||
|
||||
-- Init core serial debug
|
||||
serial_tx : out std_ulogic;
|
||||
serial_rx : in std_ulogic;
|
||||
|
||||
-- Misc
|
||||
init_done : out std_ulogic;
|
||||
init_error : out std_ulogic;
|
||||
|
||||
-- DRAM wires
|
||||
ddram_a : out std_ulogic_vector(DRAM_ALINES-1 downto 0);
|
||||
ddram_ba : out std_ulogic_vector(2 downto 0);
|
||||
ddram_ras_n : out std_ulogic;
|
||||
ddram_cas_n : out std_ulogic;
|
||||
ddram_we_n : out std_ulogic;
|
||||
ddram_cs_n : out std_ulogic;
|
||||
ddram_dm : out std_ulogic_vector(1 downto 0);
|
||||
ddram_dq : inout std_ulogic_vector(15 downto 0);
|
||||
ddram_dqs_p : inout std_ulogic_vector(1 downto 0);
|
||||
ddram_dqs_n : inout std_ulogic_vector(1 downto 0);
|
||||
ddram_clk_p : out std_ulogic;
|
||||
ddram_clk_n : out std_ulogic;
|
||||
ddram_cke : out std_ulogic;
|
||||
ddram_odt : out std_ulogic;
|
||||
ddram_reset_n : out std_ulogic
|
||||
);
|
||||
end entity litedram_wrapper;
|
||||
|
||||
architecture behaviour of litedram_wrapper is
|
||||
|
||||
component litedram_core port (
|
||||
clk : in std_ulogic;
|
||||
rst : in std_ulogic;
|
||||
pll_locked : out std_ulogic;
|
||||
ddram_a : out std_ulogic_vector(DRAM_ALINES-1 downto 0);
|
||||
ddram_ba : out std_ulogic_vector(2 downto 0);
|
||||
ddram_ras_n : out std_ulogic;
|
||||
ddram_cas_n : out std_ulogic;
|
||||
ddram_we_n : out std_ulogic;
|
||||
ddram_cs_n : out std_ulogic;
|
||||
ddram_dm : out std_ulogic_vector(1 downto 0);
|
||||
ddram_dq : inout std_ulogic_vector(15 downto 0);
|
||||
ddram_dqs_p : inout std_ulogic_vector(1 downto 0);
|
||||
ddram_dqs_n : inout std_ulogic_vector(1 downto 0);
|
||||
ddram_clk_p : out std_ulogic;
|
||||
ddram_clk_n : out std_ulogic;
|
||||
ddram_cke : out std_ulogic;
|
||||
ddram_odt : out std_ulogic;
|
||||
ddram_reset_n : out std_ulogic;
|
||||
init_done : out std_ulogic;
|
||||
init_error : out std_ulogic;
|
||||
user_clk : out std_ulogic;
|
||||
user_rst : out std_ulogic;
|
||||
wb_ctrl_adr : in std_ulogic_vector(29 downto 0);
|
||||
wb_ctrl_dat_w : in std_ulogic_vector(31 downto 0);
|
||||
wb_ctrl_dat_r : out std_ulogic_vector(31 downto 0);
|
||||
wb_ctrl_sel : in std_ulogic_vector(3 downto 0);
|
||||
wb_ctrl_cyc : in std_ulogic;
|
||||
wb_ctrl_stb : in std_ulogic;
|
||||
wb_ctrl_ack : out std_ulogic;
|
||||
wb_ctrl_we : in std_ulogic;
|
||||
wb_ctrl_cti : in std_ulogic_vector(2 downto 0);
|
||||
wb_ctrl_bte : in std_ulogic_vector(1 downto 0);
|
||||
wb_ctrl_err : out std_ulogic;
|
||||
user_port_native_0_cmd_valid : in std_ulogic;
|
||||
user_port_native_0_cmd_ready : out std_ulogic;
|
||||
user_port_native_0_cmd_we : in std_ulogic;
|
||||
user_port_native_0_cmd_addr : in std_ulogic_vector(DRAM_ABITS-1 downto 0);
|
||||
user_port_native_0_wdata_valid : in std_ulogic;
|
||||
user_port_native_0_wdata_ready : out std_ulogic;
|
||||
user_port_native_0_wdata_we : in std_ulogic_vector(15 downto 0);
|
||||
user_port_native_0_wdata_data : in std_ulogic_vector(127 downto 0);
|
||||
user_port_native_0_rdata_valid : out std_ulogic;
|
||||
user_port_native_0_rdata_ready : in std_ulogic;
|
||||
user_port_native_0_rdata_data : out std_ulogic_vector(127 downto 0)
|
||||
);
|
||||
end component;
|
||||
|
||||
signal user_port0_cmd_valid : std_ulogic;
|
||||
signal user_port0_cmd_ready : std_ulogic;
|
||||
signal user_port0_cmd_we : std_ulogic;
|
||||
signal user_port0_cmd_addr : std_ulogic_vector(DRAM_ABITS-1 downto 0);
|
||||
signal user_port0_wdata_valid : std_ulogic;
|
||||
signal user_port0_wdata_ready : std_ulogic;
|
||||
signal user_port0_wdata_we : std_ulogic_vector(15 downto 0);
|
||||
signal user_port0_wdata_data : std_ulogic_vector(127 downto 0);
|
||||
signal user_port0_rdata_valid : std_ulogic;
|
||||
signal user_port0_rdata_ready : std_ulogic;
|
||||
signal user_port0_rdata_data : std_ulogic_vector(127 downto 0);
|
||||
|
||||
signal ad3 : std_ulogic;
|
||||
|
||||
signal wb_ctrl_adr : std_ulogic_vector(29 downto 0);
|
||||
signal wb_ctrl_dat_w : std_ulogic_vector(31 downto 0);
|
||||
signal wb_ctrl_dat_r : std_ulogic_vector(31 downto 0);
|
||||
signal wb_ctrl_sel : std_ulogic_vector(3 downto 0);
|
||||
signal wb_ctrl_cyc : std_ulogic;
|
||||
signal wb_ctrl_stb : std_ulogic;
|
||||
signal wb_ctrl_ack : std_ulogic;
|
||||
signal wb_ctrl_we : std_ulogic;
|
||||
|
||||
signal wb_init_in : wb_io_master_out;
|
||||
signal wb_init_out : wb_io_slave_out;
|
||||
|
||||
type state_t is (CMD, MWRITE, MREAD);
|
||||
signal state : state_t;
|
||||
|
||||
begin
|
||||
|
||||
-- alternate core reset address set when DRAM is not initialized.
|
||||
core_alt_reset <= not init_done;
|
||||
|
||||
-- Init code BRAM memory slave
|
||||
init_ram_0: entity work.dram_init_mem
|
||||
port map(
|
||||
clk => system_clk,
|
||||
wb_in => wb_init_in,
|
||||
wb_out => wb_init_out
|
||||
);
|
||||
|
||||
--
|
||||
-- Control bus wishbone: This muxes the wishbone to the CSRs
|
||||
-- and an internal small one to the init BRAM
|
||||
--
|
||||
|
||||
-- Init DRAM wishbone IN signals
|
||||
wb_init_in.adr <= wb_ctrl_in.adr;
|
||||
wb_init_in.dat <= wb_ctrl_in.dat;
|
||||
wb_init_in.sel <= wb_ctrl_in.sel;
|
||||
wb_init_in.we <= wb_ctrl_in.we;
|
||||
wb_init_in.stb <= wb_ctrl_in.stb;
|
||||
wb_init_in.cyc <= wb_ctrl_in.cyc and wb_ctrl_is_init;
|
||||
|
||||
-- DRAM CSR IN signals
|
||||
wb_ctrl_adr <= x"0000" & wb_ctrl_in.adr(15 downto 2);
|
||||
wb_ctrl_dat_w <= wb_ctrl_in.dat;
|
||||
wb_ctrl_sel <= wb_ctrl_in.sel;
|
||||
wb_ctrl_we <= wb_ctrl_in.we;
|
||||
wb_ctrl_cyc <= wb_ctrl_in.cyc and wb_ctrl_is_csr;
|
||||
wb_ctrl_stb <= wb_ctrl_in.stb and wb_ctrl_is_csr;
|
||||
|
||||
-- Ctrl bus wishbone OUT signals
|
||||
wb_ctrl_out.ack <= wb_ctrl_ack when wb_ctrl_is_csr = '1'
|
||||
else wb_init_out.ack;
|
||||
wb_ctrl_out.dat <= wb_ctrl_dat_r when wb_ctrl_is_csr = '1'
|
||||
else wb_init_out.dat;
|
||||
wb_ctrl_out.stall <= wb_init_out.stall when wb_ctrl_is_init else
|
||||
'0' when wb_ctrl_in.cyc = '0' else not wb_ctrl_ack;
|
||||
|
||||
--
|
||||
-- Data bus wishbone to LiteDRAM native port
|
||||
--
|
||||
-- Address bit 3 selects the top or bottom half of the data
|
||||
-- bus (64-bit wishbone vs. 128-bit DRAM interface)
|
||||
--
|
||||
-- XXX TODO: Figure out how to pipeline this
|
||||
--
|
||||
ad3 <= wb_in.adr(3);
|
||||
|
||||
-- Wishbone port IN signals
|
||||
user_port0_cmd_valid <= wb_in.cyc and wb_in.stb when state = CMD else '0';
|
||||
user_port0_cmd_we <= wb_in.we when state = CMD else '0';
|
||||
user_port0_wdata_valid <= '1' when state = MWRITE else '0';
|
||||
user_port0_rdata_ready <= '1' when state = MREAD else '0';
|
||||
user_port0_cmd_addr <= wb_in.adr(DRAM_ABITS+3 downto 4);
|
||||
user_port0_wdata_data <= wb_in.dat & wb_in.dat;
|
||||
user_port0_wdata_we <= wb_in.sel & "00000000" when ad3 = '1' else
|
||||
"00000000" & wb_in.sel;
|
||||
|
||||
-- Wishbone OUT signals
|
||||
wb_out.ack <= user_port0_wdata_ready when state = MWRITE else
|
||||
user_port0_rdata_valid when state = MREAD else '0';
|
||||
|
||||
wb_out.dat <= user_port0_rdata_data(127 downto 64) when ad3 = '1' else
|
||||
user_port0_rdata_data(63 downto 0);
|
||||
|
||||
-- We don't do pipelining yet.
|
||||
wb_out.stall <= '0' when wb_in.cyc = '0' else not wb_out.ack;
|
||||
|
||||
-- DRAM user port State machine
|
||||
sm: process(system_clk)
|
||||
begin
|
||||
|
||||
if rising_edge(system_clk) then
|
||||
if system_reset = '1' then
|
||||
state <= CMD;
|
||||
else
|
||||
case state is
|
||||
when CMD =>
|
||||
if (user_port0_cmd_ready and user_port0_cmd_valid) = '1' then
|
||||
state <= MWRITE when wb_in.we = '1' else MREAD;
|
||||
end if;
|
||||
when MWRITE =>
|
||||
if user_port0_wdata_ready = '1' then
|
||||
state <= CMD;
|
||||
end if;
|
||||
when MREAD =>
|
||||
if user_port0_rdata_valid = '1' then
|
||||
state <= CMD;
|
||||
end if;
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
litedram: litedram_core
|
||||
port map(
|
||||
clk => clk_in,
|
||||
rst => rst,
|
||||
pll_locked => pll_locked,
|
||||
ddram_a => ddram_a,
|
||||
ddram_ba => ddram_ba,
|
||||
ddram_ras_n => ddram_ras_n,
|
||||
ddram_cas_n => ddram_cas_n,
|
||||
ddram_we_n => ddram_we_n,
|
||||
ddram_cs_n => ddram_cs_n,
|
||||
ddram_dm => ddram_dm,
|
||||
ddram_dq => ddram_dq,
|
||||
ddram_dqs_p => ddram_dqs_p,
|
||||
ddram_dqs_n => ddram_dqs_n,
|
||||
ddram_clk_p => ddram_clk_p,
|
||||
ddram_clk_n => ddram_clk_n,
|
||||
ddram_cke => ddram_cke,
|
||||
ddram_odt => ddram_odt,
|
||||
ddram_reset_n => ddram_reset_n,
|
||||
init_done => init_done,
|
||||
init_error => init_error,
|
||||
user_clk => system_clk,
|
||||
user_rst => system_reset,
|
||||
wb_ctrl_adr => wb_ctrl_adr,
|
||||
wb_ctrl_dat_w => wb_ctrl_dat_w,
|
||||
wb_ctrl_dat_r => wb_ctrl_dat_r,
|
||||
wb_ctrl_sel => wb_ctrl_sel,
|
||||
wb_ctrl_cyc => wb_ctrl_cyc,
|
||||
wb_ctrl_stb => wb_ctrl_stb,
|
||||
wb_ctrl_ack => wb_ctrl_ack,
|
||||
wb_ctrl_we => wb_ctrl_we,
|
||||
wb_ctrl_cti => "000",
|
||||
wb_ctrl_bte => "00",
|
||||
wb_ctrl_err => open,
|
||||
user_port_native_0_cmd_valid => user_port0_cmd_valid,
|
||||
user_port_native_0_cmd_ready => user_port0_cmd_ready,
|
||||
user_port_native_0_cmd_we => user_port0_cmd_we,
|
||||
user_port_native_0_cmd_addr => user_port0_cmd_addr,
|
||||
user_port_native_0_wdata_valid => user_port0_wdata_valid,
|
||||
user_port_native_0_wdata_ready => user_port0_wdata_ready,
|
||||
user_port_native_0_wdata_we => user_port0_wdata_we,
|
||||
user_port_native_0_wdata_data => user_port0_wdata_data,
|
||||
user_port_native_0_rdata_valid => user_port0_rdata_valid,
|
||||
user_port_native_0_rdata_ready => user_port0_rdata_ready,
|
||||
user_port_native_0_rdata_data => user_port0_rdata_data
|
||||
);
|
||||
|
||||
end architecture behaviour;
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,123 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use std.textio.all;
|
||||
|
||||
library work;
|
||||
use work.wishbone_types.all;
|
||||
use work.utils.all;
|
||||
|
||||
entity dram_init_mem is
|
||||
generic (
|
||||
EXTRA_PAYLOAD_FILE : string := "";
|
||||
EXTRA_PAYLOAD_SIZE : integer := 0
|
||||
);
|
||||
port (
|
||||
clk : in std_ulogic;
|
||||
wb_in : in wb_io_master_out;
|
||||
wb_out : out wb_io_slave_out
|
||||
);
|
||||
end entity dram_init_mem;
|
||||
|
||||
architecture rtl of dram_init_mem is
|
||||
|
||||
constant INIT_RAM_SIZE : integer := 16384;
|
||||
constant RND_PAYLOAD_SIZE : integer := round_up(EXTRA_PAYLOAD_SIZE, 8);
|
||||
constant TOTAL_RAM_SIZE : integer := INIT_RAM_SIZE + RND_PAYLOAD_SIZE;
|
||||
constant INIT_RAM_ABITS : integer := log2ceil(TOTAL_RAM_SIZE);
|
||||
constant INIT_RAM_FILE : string := "litedram/generated/sim/litedram_core.init";
|
||||
|
||||
type ram_t is array(0 to (TOTAL_RAM_SIZE / 4) - 1) of std_logic_vector(31 downto 0);
|
||||
|
||||
-- XXX FIXME: Have a single init function called twice with
|
||||
-- an offset as argument
|
||||
procedure init_load_payload(ram: inout ram_t; filename: string) is
|
||||
file payload_file : text open read_mode is filename;
|
||||
variable ram_line : line;
|
||||
variable temp_word : std_logic_vector(63 downto 0);
|
||||
begin
|
||||
for i in 0 to RND_PAYLOAD_SIZE-1 loop
|
||||
exit when endfile(payload_file);
|
||||
readline(payload_file, ram_line);
|
||||
hread(ram_line, temp_word);
|
||||
ram((INIT_RAM_SIZE/4) + i*2) := temp_word(31 downto 0);
|
||||
ram((INIT_RAM_SIZE/4) + i*2+1) := temp_word(63 downto 32);
|
||||
end loop;
|
||||
assert endfile(payload_file) report "Payload too big !" severity failure;
|
||||
end procedure;
|
||||
|
||||
impure function init_load_ram(name : string) return ram_t is
|
||||
file ram_file : text open read_mode is name;
|
||||
variable temp_word : std_logic_vector(63 downto 0);
|
||||
variable temp_ram : ram_t := (others => (others => '0'));
|
||||
variable ram_line : line;
|
||||
begin
|
||||
report "Payload size:" & integer'image(EXTRA_PAYLOAD_SIZE) &
|
||||
" rounded to:" & integer'image(RND_PAYLOAD_SIZE);
|
||||
report "Total RAM size:" & integer'image(TOTAL_RAM_SIZE) &
|
||||
" bytes using " & integer'image(INIT_RAM_ABITS) &
|
||||
" address bits";
|
||||
for i in 0 to (INIT_RAM_SIZE/8)-1 loop
|
||||
exit when endfile(ram_file);
|
||||
readline(ram_file, ram_line);
|
||||
hread(ram_line, temp_word);
|
||||
temp_ram(i*2) := temp_word(31 downto 0);
|
||||
temp_ram(i*2+1) := temp_word(63 downto 32);
|
||||
end loop;
|
||||
if RND_PAYLOAD_SIZE /= 0 then
|
||||
init_load_payload(temp_ram, EXTRA_PAYLOAD_FILE);
|
||||
end if;
|
||||
return temp_ram;
|
||||
end function;
|
||||
|
||||
impure function init_zero return ram_t is
|
||||
variable temp_ram : ram_t := (others => (others => '0'));
|
||||
begin
|
||||
return temp_ram;
|
||||
end function;
|
||||
|
||||
impure function initialize_ram(filename: string) return ram_t is
|
||||
begin
|
||||
report "Opening file " & filename;
|
||||
if filename'length = 0 then
|
||||
return init_zero;
|
||||
else
|
||||
return init_load_ram(filename);
|
||||
end if;
|
||||
end function;
|
||||
signal init_ram : ram_t := initialize_ram(INIT_RAM_FILE);
|
||||
|
||||
attribute ram_style : string;
|
||||
attribute ram_style of init_ram: signal is "block";
|
||||
|
||||
signal obuf : std_ulogic_vector(31 downto 0);
|
||||
signal oack : std_ulogic;
|
||||
begin
|
||||
|
||||
init_ram_0: process(clk)
|
||||
variable adr : integer;
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
oack <= '0';
|
||||
if (wb_in.cyc and wb_in.stb) = '1' then
|
||||
adr := to_integer((unsigned(wb_in.adr(INIT_RAM_ABITS-1 downto 2))));
|
||||
if wb_in.we = '0' then
|
||||
obuf <= init_ram(adr);
|
||||
else
|
||||
for i in 0 to 3 loop
|
||||
if wb_in.sel(i) = '1' then
|
||||
init_ram(adr)(((i + 1) * 8) - 1 downto i * 8) <=
|
||||
wb_in.dat(((i + 1) * 8) - 1 downto i * 8);
|
||||
end if;
|
||||
end loop;
|
||||
end if;
|
||||
oack <= '1';
|
||||
end if;
|
||||
wb_out.ack <= oack;
|
||||
wb_out.dat <= obuf;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
wb_out.stall <= '0';
|
||||
|
||||
end architecture rtl;
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -0,0 +1,163 @@
|
||||
-- Synchronous FIFO with a protocol similar to AXI
|
||||
--
|
||||
-- The outputs are generated combinationally from the inputs
|
||||
-- in order to allow for back-to-back transfers with the type
|
||||
-- of flow control used by busses lite AXI, pipelined WB or
|
||||
-- LiteDRAM native port when the FIFO is full.
|
||||
--
|
||||
-- That means that care needs to be taken by the user not to
|
||||
-- generate the inputs combinationally from the outputs otherwise
|
||||
-- it would create a logic loop.
|
||||
--
|
||||
-- If breaking that loop is required, a stash buffer could be
|
||||
-- added to break the flow control "loop" between the read and
|
||||
-- the write port.
|
||||
--
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
|
||||
library work;
|
||||
use work.utils.all;
|
||||
|
||||
entity sync_fifo is
|
||||
generic(
|
||||
-- Fifo depth in entries
|
||||
DEPTH : natural := 64;
|
||||
|
||||
-- Fifo width in bits
|
||||
WIDTH : natural := 32;
|
||||
|
||||
-- When INIT_ZERO is set, the memory is pre-initialized to 0's
|
||||
INIT_ZERO : boolean := false
|
||||
);
|
||||
port(
|
||||
-- Control lines:
|
||||
clk : in std_ulogic;
|
||||
reset : in std_ulogic;
|
||||
|
||||
-- Write port
|
||||
wr_ready : out std_ulogic;
|
||||
wr_valid : in std_ulogic;
|
||||
wr_data : in std_ulogic_vector(WIDTH - 1 downto 0);
|
||||
|
||||
-- Read port
|
||||
rd_ready : in std_ulogic;
|
||||
rd_valid : out std_ulogic;
|
||||
rd_data : out std_ulogic_vector(WIDTH - 1 downto 0)
|
||||
);
|
||||
end entity sync_fifo;
|
||||
|
||||
architecture behaviour of sync_fifo is
|
||||
|
||||
subtype data_t is std_ulogic_vector(WIDTH - 1 downto 0);
|
||||
type memory_t is array(0 to DEPTH - 1) of data_t;
|
||||
|
||||
function init_mem return memory_t is
|
||||
variable m : memory_t;
|
||||
begin
|
||||
if INIT_ZERO then
|
||||
for i in 0 to DEPTH - 1 loop
|
||||
m(i) := (others => '0');
|
||||
end loop;
|
||||
end if;
|
||||
return m;
|
||||
end function;
|
||||
|
||||
signal memory : memory_t := init_mem;
|
||||
|
||||
subtype index_t is integer range 0 to DEPTH - 1;
|
||||
signal rd_idx : index_t;
|
||||
signal rd_next : index_t;
|
||||
signal wr_idx : index_t;
|
||||
signal wr_next : index_t;
|
||||
|
||||
function next_index(idx : index_t) return index_t is
|
||||
variable r : index_t;
|
||||
begin
|
||||
if ispow2(DEPTH) then
|
||||
r := (idx + 1) mod DEPTH;
|
||||
else
|
||||
r := idx + 1;
|
||||
if r = DEPTH then
|
||||
r := 0;
|
||||
end if;
|
||||
end if;
|
||||
return r;
|
||||
end function;
|
||||
|
||||
type op_t is (OP_POP, OP_PUSH);
|
||||
signal op_prev : op_t := OP_POP;
|
||||
signal op_next : op_t;
|
||||
|
||||
signal full, empty : std_ulogic;
|
||||
signal push, pop : std_ulogic;
|
||||
begin
|
||||
|
||||
-- Current state at last clock edge
|
||||
empty <= '1' when rd_idx = wr_idx and op_prev = OP_POP else '0';
|
||||
full <= '1' when rd_idx = wr_idx and op_prev = OP_PUSH else '0';
|
||||
|
||||
-- We can accept new data if we aren't full or we are but
|
||||
-- the read port is going to accept data this cycle
|
||||
wr_ready <= rd_ready or not full;
|
||||
|
||||
-- We can provide data if we aren't empty or we are but
|
||||
-- the write port is going to provide data this cycle
|
||||
rd_valid <= wr_valid or not empty;
|
||||
|
||||
-- Internal control signals
|
||||
push <= wr_ready and wr_valid;
|
||||
pop <= rd_ready and rd_valid;
|
||||
|
||||
-- Next state
|
||||
rd_next <= next_index(rd_idx) when pop = '1' else rd_idx;
|
||||
wr_next <= next_index(wr_idx) when push = '1' else wr_idx;
|
||||
with push & pop select op_next <=
|
||||
OP_PUSH when "10",
|
||||
OP_POP when "01",
|
||||
op_prev when others;
|
||||
|
||||
-- Read port output
|
||||
rd_data <= memory(rd_idx) when empty = '0' else wr_data;
|
||||
|
||||
-- Read counter
|
||||
reader: process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if reset = '1' then
|
||||
rd_idx <= 0;
|
||||
else
|
||||
rd_idx <= rd_next;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- Write counter and memory write
|
||||
producer: process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if reset = '1' then
|
||||
wr_idx <= 0;
|
||||
else
|
||||
wr_idx <= wr_next;
|
||||
|
||||
if push = '1' then
|
||||
memory(wr_idx) <= wr_data;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- Previous op latch used for generating empty/full
|
||||
op: process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if reset = '1' then
|
||||
op_prev <= OP_POP;
|
||||
else
|
||||
op_prev <= op_next;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end architecture behaviour;
|
Loading…
Reference in New Issue