--------------------------------------------------------------------------- -- (c) 2013 mark watson -- I am happy for anyone to use this for non-commercial use. -- If my vhdl files are used commercially or otherwise sold, -- please contact me for explicit permission at scrameta (gmail). -- This applies for source and binary form and derived works. --------------------------------------------------------------------------- LIBRARY ieee; USE ieee.std_logic_1164.all; use ieee.numeric_std.all; ENTITY sdram_statemachine_mcc IS generic ( ADDRESS_WIDTH : natural := 22; ROW_WIDTH : natural := 12; AP_BIT : natural := 10; COLUMN_WIDTH : natural := 8 ); PORT ( CLK_SYSTEM : IN STD_LOGIC; CLK_SDRAM : IN STD_LOGIC; -- this is a exact multiple of system clock RESET_N : in STD_LOGIC; -- interface as though SRAM - this module can take care of caching/write combining etc etc. For first cut... nothing. TODO: What extra info would help me here? DATA_IN : in std_logic_vector(31 downto 0); ADDRESS_IN : in std_logic_vector(ADDRESS_WIDTH downto 0); -- 1 extra bit for byte alignment READ_EN : in std_logic; -- if no reads pending may be a good time to do a refresh WRITE_EN : in std_logic; REQUEST : in std_logic; -- Toggle this to issue a new request BYTE_ACCESS : in std_logic; -- ldqm/udqm set based on a(0) - if 0=0111, if 1=1011. Data fields valid:7 downto 0. WORD_ACCESS : in std_logic; -- ldqm/udqm set based on a(0) - if 0=0011, if 1=1001. Data fields valid:15 downto 0. LONGWORD_ACCESS : in std_logic; -- a(0) ignored. lqdm/udqm mask is 0000 REFRESH : in std_logic; REPLY : out std_logic; -- This matches the request once complete DATA_OUT : out std_logic_vector(31 downto 0); -- sdram itself SDRAM_ADDR : out std_logic_vector(ROW_WIDTH downto 0); SDRAM_DQ : inout std_logic_vector(15 downto 0); SDRAM_BA0 : out std_logic; SDRAM_BA1 : out std_logic; SDRAM_CS_N : out std_logic; SDRAM_RAS_N : out std_logic; SDRAM_CAS_N : out std_logic; SDRAM_WE_N : out std_logic; SDRAM_ldqm : out std_logic; -- low enable, high disable - for byte addressing - NB, cas latency applies to reads SDRAM_udqm : out std_logic ); END sdram_statemachine_mcc; ARCHITECTURE vhdl OF sdram_statemachine_mcc IS component sdram_ctrl port ( -- //----------------------------- -- // Clock and reset -- //----------------------------- -- input rst, // Global reset -- input clk, // Master clock (72 MHz) -- -- output ram_rdy_n, // SDRAM ready -- output ram_ref, // SDRAM refresh -- output [3:0] ram_cyc, // SDRAM cycles -- output [3:0] ram_ph, // SDRAM phases -- output [8:0] ram_ph_ctr, // Phase counter rst : in std_logic; clk : in std_logic; ram_rdy_n : out std_logic; ram_ref : out std_logic; ram_cyc : out std_logic_vector(3 downto 0); ram_ph : out std_logic_vector(3 downto 0); ram_ph_ctr : out std_logic_vector(8 downto 0); rden_b0 : in std_logic; wren_b0 : in std_logic; addr_b0 : in std_logic_vector(22 downto 2); valid_b0 : out std_logic; fetch_b0 : out std_logic; rdata_b0 : out std_logic_vector(15 downto 0); wdata_b0 : in std_logic_vector(15 downto 0); bena_b0 : in std_logic_vector(1 downto 0); rden_b1 : in std_logic; wren_b1 : in std_logic; addr_b1 : in std_logic_vector(22 downto 2); valid_b1 : out std_logic; fetch_b1 : out std_logic; rdata_b1 : out std_logic_vector(15 downto 0); wdata_b1 : in std_logic_vector(15 downto 0); bena_b1 : in std_logic_vector(1 downto 0); rden_b2 : in std_logic; wren_b2 : in std_logic; addr_b2 : in std_logic_vector(22 downto 2); valid_b2 : out std_logic; fetch_b2 : out std_logic; rdata_b2 : out std_logic_vector(15 downto 0); wdata_b2 : in std_logic_vector(15 downto 0); bena_b2 : in std_logic_vector(1 downto 0); rden_b3 : in std_logic; wren_b3 : in std_logic; addr_b3 : in std_logic_vector(22 downto 2); valid_b3 : out std_logic; fetch_b3 : out std_logic; rdata_b3 : out std_logic_vector(15 downto 0); wdata_b3 : in std_logic_vector(15 downto 0); bena_b3 : in std_logic_vector(1 downto 0); -- //----------------------------- -- // Access bank #0 -- //----------------------------- -- input rden_b0, // Read enable -- input wren_b0, // Write enable -- input [22:2] addr_b0, // Address (up to 8 MB) -- output valid_b0, // Read data valid -- output fetch_b0, // Write data fetch -- output [15:0] rdata_b0, // Read data -- input [15:0] wdata_b0, // Write data -- input [1:0] bena_b0, // Byte enable -- -- //----------------------------- -- // Access bank #1 -- //----------------------------- -- input rden_b1, // Read enable -- input wren_b1, // Write enable -- input [22:2] addr_b1, // Address (up to 8 MB) -- output valid_b1, // Read data valid -- output fetch_b1, // Write data fetch -- output [15:0] rdata_b1, // Read data -- input [15:0] wdata_b1, // Write data -- input [1:0] bena_b1, // Byte enable -- -- //----------------------------- -- // Access bank #2 -- //----------------------------- -- input rden_b2, // Read enable -- input wren_b2, // Write enable -- input [22:2] addr_b2, // Address (up to 8 MB) -- output valid_b2, // Read data valid -- output fetch_b2, // Write data fetch -- output [15:0] rdata_b2, // Read data -- input [15:0] wdata_b2, // Write data -- input [1:0] bena_b2, // Byte enable -- -- //----------------------------- -- // Access bank #3 -- //----------------------------- -- input rden_b3, // Read enable -- input wren_b3, // Write enable -- input [22:2] addr_b3, // Address (up to 8 MB) -- output valid_b3, // Read data valid -- output fetch_b3, // Write data fetch -- output [15:0] rdata_b3, // Read data -- input [15:0] wdata_b3, // Write data -- input [1:0] bena_b3, // Byte enable -- //----------------------------- -- // SDRAM memory signals -- //----------------------------- -- output sdram_cs_n, // SDRAM chip select -- output reg sdram_ras_n, // SDRAM row address strobe -- output reg sdram_cas_n, // SDRAM column address strobe -- output reg sdram_we_n, // SDRAM write enable -- // -- output reg [1:0] sdram_ba, // SDRAM bank address -- output reg [12:0] sdram_addr, // SDRAM address -- // -- output reg [3:0] sdram_dqm_n, // SDRAM DQ masks -- output reg sdram_dq_oe, // SDRAM data output enable -- output reg [31:0] sdram_dq_o, // SDRAM data output -- input [31:0] sdram_dq_i // SDRAM data input sdram_cs_n : out std_logic; sdram_ras_n : out std_logic; sdram_cas_n : out std_logic; sdram_we_n : out std_logic; sdram_ba : out std_logic_vector(1 downto 0); sdram_addr : out std_logic_vector(12 downto 0); sdram_dqm_n : out std_logic_vector(3 downto 0); sdram_dq_oe : out std_logic; sdram_dq_o : out std_logic_vector(31 downto 0); sdram_dq_i : in std_logic_vector(31 downto 0) ); end component; signal SDRAM_CKE_dummy : std_logic; signal sdram_valid_b0_dummy : std_logic; signal sdram_valid_b1_dummy : std_logic; signal sdram_valid_b2_dummy : std_logic; signal sdram_valid_b3_dummy : std_logic; signal sdram_fetch_b0_dummy : std_logic; signal sdram_fetch_b1_dummy : std_logic; signal sdram_fetch_b2_dummy : std_logic; signal sdram_fetch_b3_dummy : std_logic; signal sdram_read_b0_dummy : std_logic_vector(15 downto 0); signal sdram_read_b1_dummy : std_logic_vector(15 downto 0); signal sdram_read_b2_dummy : std_logic_vector(15 downto 0); signal sdram_read_b3_dummy : std_logic_vector(15 downto 0); signal reset : std_logic; signal sdram_ctl_rdy_dummy : std_logic; signal sdram_ctl_ref_dummy : std_logic; signal sdram_ctl_cyc_dummy : std_logic_vector(3 downto 0); signal sdram_ctl_ph_dummy : std_logic_vector(3 downto 0); signal sdram_ctl_ph_ctr_dummy : std_logic_vector(8 downto 0); signal SDRAM_VALID : std_logic; signal SDRAM_FETCH : std_logic; signal SDRAM_dq_oe : std_logic; signal sdram_dq_o : std_logic_vector(31 downto 0); signal sdram_dq_i : std_logic_vector(31 downto 0); signal sdram_dqm_N_temp : std_logic_vector(3 downto 0); signal sdram_ba : std_logic_vector(1 downto 0); signal sdram_enable_byte : std_logic_vector(1 downto 0); signal sdram_reply_reg : std_logic; signal state_reg : std_logic_vector(2 downto 0); signal store_data_in_reg : std_logic_vector(47 downto 0); signal data_out_reg : std_logic_vector(31 downto 0); signal sdram_reply_next : std_logic; signal state_next : std_logic_vector(2 downto 0); signal store_data_in_next : std_logic_vector(47 downto 0); signal data_out_next : std_logic_vector(31 downto 0); constant state_idle : std_logic_vector(2 downto 0) := "000"; constant state_write_wait_1 : std_logic_vector(2 downto 0) := "001"; constant state_write_wait_2 : std_logic_vector(2 downto 0) := "010"; constant state_write_wait_3 : std_logic_vector(2 downto 0) := "111"; constant state_read_wait_1 : std_logic_vector(2 downto 0) := "011"; constant state_read_wait_2 : std_logic_vector(2 downto 0) := "100"; constant state_read_wait_3 : std_logic_vector(2 downto 0) := "101"; constant state_read_wait_4 : std_logic_vector(2 downto 0) := "110"; signal internal_data_in : std_logic_vector(15 downto 0); signal internal_data_out : std_logic_vector(15 downto 0); signal write_en_next : std_logic; signal write_en_reg : std_logic; signal read_en_next : std_logic; signal read_en_reg : std_logic; signal SDRAM_ADDR_temp : std_logic_vector(12 downto 0); begin reset <= not(reset_n); process(clk_system, reset_n) begin if (reset_n = '0') then sdram_reply_reg <= '0'; state_reg <= state_idle; store_data_in_reg <= (others=>'0'); data_out_reg <= (others=>'0'); write_en_reg <= '0'; read_en_reg <= '0'; elsif (clk_system'event and clk_system = '1') then sdram_reply_reg <= sdram_reply_next; state_reg <= state_next; store_data_in_reg <= store_data_in_next; data_out_reg <= data_out_next; write_en_reg <= write_en_next; read_en_reg <= read_en_next; end if; end process; data_out <= data_out_reg; reply <= sdram_reply_reg; process(read_en_reg, write_en_reg, state_reg, request, write_en, store_data_in_reg, internal_data_in, data_in, sdram_reply_reg, byte_access, longword_access, address_in, sdram_valid, sdram_fetch) begin sdram_reply_next <= sdram_reply_reg; state_next <= state_reg; store_data_in_next <= store_data_in_reg; data_out_next <= (others=>'0'); read_en_next <= read_en_reg; write_en_next <= write_en_reg; internal_data_out <= (others=>'0'); sdram_enable_byte <= "11"; case state_reg is when state_idle => sdram_reply_next <= '0'; if (request = '1') then if (write_en = '1') then -- 4 byte write state_next <= state_write_wait_1; write_en_next <= '1'; else -- 8 byte read state_next <= state_read_wait_1; read_en_next <= '1'; -- TODO - read from cached? end if; end if; when state_write_wait_1 => if (sdram_fetch = '1') then state_next <= state_write_wait_2; end if; internal_data_out <= data_in(31 downto 16); when state_write_wait_2 => state_next <= state_write_wait_3; if (byte_access = '1') then internal_data_out <= data_in(7 downto 0)&data_in(7 downto 0); case address_in(1 downto 0) is when "00" => sdram_enable_byte <= "01"; when "01" => sdram_enable_byte <= "10"; when "10" => sdram_enable_byte <= "00"; when "11" => sdram_enable_byte <= "00"; end case; elsif (longword_access = '1') then internal_data_out <= data_in(15 downto 0); end if; sdram_reply_next <= '1'; when state_write_wait_3 => state_next <= state_idle; write_en_next <= '0'; if (byte_access = '1') then internal_data_out <= data_in(7 downto 0)&data_in(7 downto 0); case address_in(1 downto 0) is when "00" => sdram_enable_byte <= "00"; when "01" => sdram_enable_byte <= "00"; when "10" => sdram_enable_byte <= "01"; when "11" => sdram_enable_byte <= "10"; end case; elsif (longword_access = '1') then internal_data_out <= data_in(31 downto 16); end if; sdram_reply_next <= '0'; when state_read_wait_1 => if (sdram_valid = '1') then state_next <= state_read_wait_2; store_data_in_next(15 downto 0) <= internal_data_in; end if; when state_read_wait_2 => state_next <= state_read_wait_3; store_data_in_next(31 downto 16) <= internal_data_in; when state_read_wait_3 => state_next <= state_read_wait_4; store_data_in_next(47 downto 32) <= internal_data_in; when state_read_wait_4 => read_en_next <= '0'; state_next <= state_idle; --store_data_in_next(63 downto 48) <= internal_data_in; sdram_reply_next <= '1'; if (byte_access = '1') then case address_in(2 downto 0) is when "000" => data_out_next(7 downto 0) <= store_data_in_reg(7 downto 0); when "001" => data_out_next(7 downto 0) <= store_data_in_reg(15 downto 8); when "010" => data_out_next(7 downto 0) <= store_data_in_reg(23 downto 16); when "011" => data_out_next(7 downto 0) <= store_data_in_reg(31 downto 24); when "100" => data_out_next(7 downto 0) <= store_data_in_reg(39 downto 32); when "101" => data_out_next(7 downto 0) <= store_data_in_reg(47 downto 40); when "110" => data_out_next(7 downto 0) <= internal_data_in(7 downto 0); when "111" => data_out_next(7 downto 0) <= internal_data_in(15 downto 8); end case; elsif (longword_access = '1') then case address_in(2 downto 0) is -- aligned only! when "000" => data_out_next <= store_data_in_reg(31 downto 0); when "100" => data_out_next <= internal_data_in&store_data_in_reg(47 downto 32); when others => -- NOP end case; end if; end case; end process; sdram_mcc : sdram_ctrl PORT map ( rst => reset, clk => clk_SYSTEM, ram_rdy_n => sdram_ctl_rdy_dummy, ram_ref => sdram_ctl_ref_dummy, ram_cyc => sdram_ctl_cyc_dummy, ram_ph => sdram_ctl_ph_dummy, ram_ph_ctr => sdram_ctl_ph_ctr_dummy, --BYTE_ACCESS : IN STD_LOGIC; --WORD_ACCESS : IN STD_LOGIC; --LONGWORD_ACCESS : IN STD_LOGIC; rden_b0 => READ_EN_reg, wren_b0 => WRITE_EN_reg, addr_b0 => ADDRESS_IN(22 downto 2), valid_b0 => SDRAM_VALID, fetch_b0 => SDRAM_FETCH, rdata_b0 => INTERNAL_DATA_IN(15 downto 0), wdata_b0 => INTERNAL_DATA_OUT(15 downto 0), bena_b0 => sdram_enable_byte, rden_b1 => '0', wren_b1 => '0', addr_b1 => (others=>'0'), valid_b1 => sdram_valid_b1_dummy, fetch_b1 => sdram_fetch_b1_dummy, rdata_b1 => sdram_read_b1_dummy, wdata_b1 => (others=>'0'), bena_b1 => "00", rden_b2 => '0', wren_b2 => '0', addr_b2 => (others=>'0'), valid_b2 => sdram_valid_b2_dummy, fetch_b2 => sdram_fetch_b2_dummy, rdata_b2 => sdram_read_b2_dummy, wdata_b2 => (others=>'0'), bena_b2 => "00", rden_b3 => '0', wren_b3 => '0', addr_b3 => (others=>'0'), valid_b3 => sdram_valid_b3_dummy, fetch_b3 => sdram_fetch_b3_dummy, rdata_b3 => sdram_read_b3_dummy, wdata_b3 => (others=>'0'), bena_b3 => "00", sdram_cs_n => SDRAM_CS_N, sdram_ras_n => SDRAM_RAS_N, sdram_cas_n => SDRAM_CAS_N, sdram_we_n => SDRAM_WE_N, sdram_ba => SDRAM_BA, sdram_addr => SDRAM_ADDR_temp, sdram_dqm_n => sdram_dqm_N_temp, sdram_dq_oe => sdram_dq_oe, sdram_dq_o => sdram_dq_o, sdram_dq_i => sdram_dq_i ); sdram_dq <= sdram_dq_o(15 downto 0) when sdram_dq_oe='1' else (others=>'Z'); sdram_dq_i(15 downto 0) <= sdram_dq; sdram_dq_i(31 downto 16) <= (others=>'0'); SDRAM_LDQM<= sdram_dqm_N_temp(0); SDRAM_UDQM<= sdram_dqm_N_temp(1); SDRAM_BA0 <= sdram_ba(0); SDRAM_BA1 <= sdram_ba(1); SDRAM_ADDR(12) <= '1'; SDRAM_ADDR(11 downto 0) <= SDRAM_ADDR_temp(11 downto 0); end vhdl;