1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-01-20 17:47:33 +00:00
Gehstock.Mist_FPGA/common/Memory/dpSDRAM256Mb.vhd
2019-07-22 23:42:05 +02:00

373 lines
12 KiB
VHDL

-------------------------------------------------------------------------------
--
-- Copyright (c) 2016, Fabio Belavenuto (belavenuto@gmail.com)
--
-- All rights reserved
--
-- Redistribution and use in source and synthezised forms, with or without
-- modification, are permitted provided that the following conditions are met:
--
-- Redistributions of source code must retain the above copyright notice,
-- this list of conditions and the following disclaimer.
--
-- Redistributions in synthesized form must reproduce the above copyright
-- notice, this list of conditions and the following disclaimer in the
-- documentation and/or other materials provided with the distribution.
--
-- Neither the name of the author nor the names of other contributors may
-- be used to endorse or promote products derived from this software without
-- specific prior written permission.
--
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-- POSSIBILITY OF SUCH DAMAGE.
--
-- Please report bugs to the author, but before you do so, please
-- make sure that this is not a derivative work and that
-- you have the latest version of this file.
--
-------------------------------------------------------------------------------
--
-- Emulacao memoria dual-port para SDRAMs
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity dpSDRAM256Mb is
generic (
freq_g : integer := 100
);
port (
clock_i : in std_logic;
reset_i : in std_logic;
refresh_i : in std_logic := '1';
-- Port 0
port0_cs_i : in std_logic;
port0_oe_i : in std_logic;
port0_we_i : in std_logic;
port0_addr_i : in std_logic_vector(24 downto 0);
port0_data_i : in std_logic_vector( 7 downto 0);
port0_data_o : out std_logic_vector( 7 downto 0);
-- Port 1
port1_cs_i : in std_logic;
port1_oe_i : in std_logic;
port1_we_i : in std_logic;
port1_addr_i : in std_logic_vector(24 downto 0);
port1_data_i : in std_logic_vector( 7 downto 0);
port1_data_o : out std_logic_vector( 7 downto 0);
-- SDRAM in board
mem_cke_o : out std_logic;
mem_cs_n_o : out std_logic;
mem_ras_n_o : out std_logic;
mem_cas_n_o : out std_logic;
mem_we_n_o : out std_logic;
mem_udq_o : out std_logic;
mem_ldq_o : out std_logic;
mem_ba_o : out std_logic_vector( 1 downto 0);
mem_addr_o : out std_logic_vector(12 downto 0);
mem_data_io : inout std_logic_vector(15 downto 0)
);
end entity;
architecture Behavior of dpSDRAM256Mb is
constant SdrCmd_de_c : std_logic_vector(3 downto 0) := "1111"; -- deselect
constant SdrCmd_xx_c : std_logic_vector(3 downto 0) := "0111"; -- no operation
constant SdrCmd_rd_c : std_logic_vector(3 downto 0) := "0101"; -- read
constant SdrCmd_wr_c : std_logic_vector(3 downto 0) := "0100"; -- write
constant SdrCmd_ac_c : std_logic_vector(3 downto 0) := "0011"; -- activate
constant SdrCmd_pr_c : std_logic_vector(3 downto 0) := "0010"; -- precharge all
constant SdrCmd_re_c : std_logic_vector(3 downto 0) := "0001"; -- refresh
constant SdrCmd_ms_c : std_logic_vector(3 downto 0) := "0000"; -- mode regiser set
-- SD-RAM control signals
signal SdrCmd_s : std_logic_vector(3 downto 0);
signal SdrBa_s : std_logic_vector(1 downto 0);
signal SdrUdq_s : std_logic;
signal SdrLdq_s : std_logic;
signal SdrAdr_s : std_logic_vector(12 downto 0);
signal SdrDat_s : std_logic_vector(15 downto 0);
signal ram0_req_s : std_logic;
signal ram0_ack_s : std_logic;
signal ram0_addr_s : std_logic_vector(24 downto 0);
signal ram0_din_s : std_logic_vector( 7 downto 0);
signal ram0_dout_s : std_logic_vector( 7 downto 0);
signal ram0_we_s : std_logic;
signal ram1_req_s : std_logic;
signal ram1_ack_s : std_logic;
signal ram1_addr_s : std_logic_vector(24 downto 0);
signal ram1_din_s : std_logic_vector( 7 downto 0);
signal ram1_dout_s : std_logic_vector( 7 downto 0);
signal ram1_we_s : std_logic;
begin
-- Detectar pedido na porta 0
process (reset_i, clock_i)
variable pcs_v : std_logic_vector(1 downto 0);
variable acesso_v : std_logic;
begin
if reset_i = '1' then
port0_data_o <= (others => '1');
ram0_we_s <= '0';
ram0_req_s <= '0';
pcs_v := "00";
elsif rising_edge(clock_i) then
if ram0_req_s = '1' and ram0_ack_s = '1' then
if ram0_we_s = '0' then
port0_data_o <= ram0_dout_s;
end if;
ram0_req_s <= '0';
end if;
if pcs_v = "01" then
ram0_addr_s <= port0_addr_i;
ram0_req_s <= '1';
if port0_we_i = '1' then
ram0_din_s <= port0_data_i;
ram0_we_s <= '1';
else
ram0_we_s <= '0';
end if;
end if;
acesso_v := port0_cs_i and (port0_oe_i or port0_we_i);
pcs_v := pcs_v(0) & acesso_v;
end if;
end process;
-- Detectar pedido na porta 1
process (reset_i, clock_i)
variable pcs_v : std_logic_vector(1 downto 0);
variable acesso_v : std_logic;
begin
if reset_i = '1' then
port1_data_o <= (others => '1');
ram1_we_s <= '0';
ram1_req_s <= '0';
pcs_v := "00";
elsif rising_edge(clock_i) then
if ram1_req_s = '1' and ram1_ack_s = '1' then
if ram1_we_s = '0' then
port1_data_o <= ram1_dout_s;
end if;
ram1_req_s <= '0';
end if;
if pcs_v = "01" then
ram1_addr_s <= port1_addr_i;
ram1_req_s <= '1';
if port1_we_i = '1' then
ram1_din_s <= port1_data_i;
ram1_we_s <= '1';
else
ram1_we_s <= '0';
end if;
end if;
acesso_v := port1_cs_i and (port1_oe_i or port1_we_i);
pcs_v := pcs_v(0) & acesso_v;
end if;
end process;
----------------------------
process (clock_i)
type typSdrRoutine_t is ( SdrRoutine_Null, SdrRoutine_Init, SdrRoutine_Idle, SdrRoutine_RefreshAll, SdrRoutine_ReadOne, SdrRoutine_WriteOne );
variable SdrRoutine_v : typSdrRoutine_t := SdrRoutine_Null;
variable SdrRoutineSeq_v : unsigned(7 downto 0) := X"00";
variable refreshDelayCounter_v : unsigned(23 downto 0) := x"000000";
variable SdrRefreshCounter_v : unsigned(15 downto 0) := X"0000";
variable SdrPort_v : std_logic := '0';
variable SdrAddress_v : std_logic_vector(24 downto 0);
begin
if rising_edge(clock_i) then
ram0_ack_s <= '0';
ram1_ack_s <= '0';
case SdrRoutine_v is
when SdrRoutine_Null =>
SdrCmd_s <= SdrCmd_xx_c;
SdrDat_s <= (others => 'Z');
if refreshDelayCounter_v = 0 then
SdrRoutine_v := SdrRoutine_Init;
end if;
when SdrRoutine_Init =>
if SdrRoutineSeq_v = X"0" then
SdrCmd_s <= SdrCmd_pr_c;
SdrAdr_s <= (others => '1');
SdrBa_s <= "00";
SdrUdq_s <= '1';
SdrLdq_s <= '1';
SdrRoutineSeq_v := SdrRoutineSeq_v + 1;
elsif SdrRoutineSeq_v = X"04" or SdrRoutineSeq_v = X"0C" then
SdrCmd_s <= SdrCmd_re_c;
SdrRoutineSeq_v := SdrRoutineSeq_v + 1;
elsif SdrRoutineSeq_v = X"14" then
SdrCmd_s <= SdrCmd_ms_c;
SdrAdr_s <= "000" & "1" & "00" & "010" & "0" & "000"; -- Single, Standard, CAS Latency=2, WT=0(seq), BL=1
SdrRoutineSeq_v := SdrRoutineSeq_v + 1;
elsif SdrRoutineSeq_v = X"17" then
SdrCmd_s <= SdrCmd_xx_c;
SdrRoutineSeq_v := X"00";
SdrRoutine_v := SdrRoutine_Idle;
else
SdrCmd_s <= SdrCmd_xx_c;
SdrRoutineSeq_v := SdrRoutineSeq_v + 1;
end if;
when SdrRoutine_Idle =>
SdrCmd_s <= SdrCmd_xx_c;
SdrDat_s <= (others => 'Z');
if ram0_req_s = '1' and ram0_ack_s = '0' then
SdrPort_v := '0';
SdrAddress_v := ram0_addr_s;
if ram0_we_s = '1' then
SdrRoutine_v := SdrRoutine_WriteOne;
else
SdrRoutine_v := SdrRoutine_ReadOne;
end if;
elsif ram1_req_s = '1' and ram1_ack_s = '0' then
SdrPort_v := '1';
SdrAddress_v := ram1_addr_s;
if ram1_we_s = '1' then
SdrRoutine_v := SdrRoutine_WriteOne;
else
SdrRoutine_v := SdrRoutine_ReadOne;
end if;
elsif SdrRefreshCounter_v < 8192 and refresh_i = '1' then
SdrRoutine_v := SdrRoutine_RefreshAll;
SdrRefreshCounter_v := SdrRefreshCounter_v + 1;
end if;
when SdrRoutine_RefreshAll =>
if SdrRoutineSeq_v = X"00" then
SdrCmd_s <= SdrCmd_re_c;
SdrRoutineSeq_v := SdrRoutineSeq_v + 1;
elsif SdrRoutineSeq_v = X"06" then
SdrCmd_s <= SdrCmd_xx_c;
SdrRoutineSeq_v := X"00";
SdrRoutine_v := SdrRoutine_Idle;
else
SdrCmd_s <= SdrCmd_xx_c;
SdrRoutineSeq_v := SdrRoutineSeq_v + 1;
end if;
when SdrRoutine_ReadOne =>
if SdrRoutineSeq_v = X"00" then
SdrCmd_s <= SdrCmd_ac_c;
SdrBa_s <= SdrAddress_v(24 downto 23);
SdrAdr_s <= SdrAddress_v(22 downto 10); -- Row (13 bits)
SdrRoutineSeq_v := SdrRoutineSeq_v + 1;
elsif SdrRoutineSeq_v = X"02" then
SdrCmd_s <= SdrCmd_rd_c;
SdrAdr_s(12 downto 9) <= "0010"; -- A10 = '1' => Auto Pre-charge
SdrAdr_s(8 downto 0) <= SdrAddress_v(9 downto 1);
SdrRoutineSeq_v := SdrRoutineSeq_v + 1;
SdrUdq_s <= '0';
SdrLdq_s <= '0';
elsif SdrRoutineSeq_v = X"05" then
if SdrPort_v = '0' then
if SdrAddress_v(0) = '0' then
ram0_dout_s <= mem_data_io(7 downto 0);
else
ram0_dout_s <= mem_data_io(15 downto 8);
end if;
ram0_ack_s <= '1';
else
if SdrAddress_v(0) = '0' then
ram1_dout_s <= mem_data_io(7 downto 0);
else
ram1_dout_s <= mem_data_io(15 downto 8);
end if;
ram1_ack_s <= '1';
end if;
SdrCmd_s <= SdrCmd_xx_c;
SdrRoutineSeq_v := SdrRoutineSeq_v + 1;
elsif SdrRoutineSeq_v = X"06" then
SdrRoutineSeq_v := X"00";
SdrRoutine_v := SdrRoutine_Idle;
else
SdrCmd_s <= SdrCmd_xx_c;
SdrRoutineSeq_v := SdrRoutineSeq_v + 1;
end if;
when SdrRoutine_WriteOne =>
if SdrRoutineSeq_v = X"00" then
SdrCmd_s <= SdrCmd_ac_c;
SdrBa_s <= SdrAddress_v(24 downto 23);
SdrAdr_s <= SdrAddress_v(22 downto 10);
SdrRoutineSeq_v := SdrRoutineSeq_v + 1;
elsif SdrRoutineSeq_v = X"02" then
SdrCmd_s <= SdrCmd_wr_c;
SdrAdr_s(12 downto 9) <= "0010"; -- A10 = '1' => Auto Pre-charge
SdrAdr_s(8 downto 0) <= SdrAddress_v(9 downto 1);
SdrUdq_s <= not SdrAddress_v(0);
SdrLdq_s <= SdrAddress_v(0);
if SdrPort_v = '0' then
SdrDat_s <= ram0_din_s & ram0_din_s;
else
SdrDat_s <= ram1_din_s & ram1_din_s;
end if;
SdrRoutineSeq_v := SdrRoutineSeq_v + 1;
elsif SdrRoutineSeq_v = X"03" then
if SdrPort_v = '0' then
ram0_ack_s <= '1';
else
ram1_ack_s <= '1';
end if;
SdrCmd_s <= SdrCmd_xx_c;
SdrDat_s <= (others => 'Z');
SdrRoutineSeq_v := SdrRoutineSeq_v + 1;
elsif SdrRoutineSeq_v = X"05" then
SdrRoutineSeq_v := X"00";
SdrRoutine_v := SdrRoutine_Idle;
else
SdrCmd_s <= SdrCmd_xx_c;
SdrRoutineSeq_v := SdrRoutineSeq_v + 1;
end if;
end case;
refreshDelayCounter_v := refreshDelayCounter_v + 1;
if refreshDelayCounter_v >= ( freq_g * 1000 * 64 ) then
refreshDelayCounter_v := x"000000";
SdrRefreshCounter_v := x"0000";
end if;
end if;
end process;
mem_cke_o <= '1';
mem_cs_n_o <= SdrCmd_s(3);
mem_ras_n_o <= SdrCmd_s(2);
mem_cas_n_o <= SdrCmd_s(1);
mem_we_n_o <= SdrCmd_s(0);
mem_udq_o <= SdrUdq_s;
mem_ldq_o <= SdrLdq_s;
mem_ba_o <= SdrBa_s;
mem_addr_o <= SdrAdr_s;
mem_data_io <= SdrDat_s;
end architecture;