------------------------------------------------------------------------------ -- This file is a part of the GRLIB VHDL IP LIBRARY -- Copyright (C) 2003 - 2008, Gaisler Research -- Copyright (C) 2008 - 2012, Aeroflex Gaisler -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ------------------------------------------------------------------------------- -- Entity: ahb2mig_sp605 -- File: ahb2mig_sp605.vhd -- Author: Jiri Gaisler - Aeroflex Gaisler AB -- -- This is a AHB-2.0 interface for the Xilinx Spartan-6 MIG. -- One bidir 32-bit port is used for the main AHB bus, while -- a second read-only port can be enabled for a VGA frame buffer. ------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; library grlib; use grlib.amba.all; use grlib.stdlib.all; use grlib.devices.all; entity ahb2mig_sp605 is generic( hindex : integer := 0; haddr : integer := 0; hmask : integer := 16#f00#; pindex : integer := 0; paddr : integer := 0; pmask : integer := 16#fff#; vgamst : integer := 0; vgaburst : integer := 0 ); port( mcb3_dram_dq : inout std_logic_vector(15 downto 0); mcb3_dram_a : out std_logic_vector(12 downto 0); mcb3_dram_ba : out std_logic_vector(2 downto 0); mcb3_dram_ras_n : out std_logic; mcb3_dram_cas_n : out std_logic; mcb3_dram_we_n : out std_logic; mcb3_dram_odt : out std_logic; mcb3_dram_reset_n : out std_logic; mcb3_dram_cke : out std_logic; mcb3_dram_dm : out std_logic; mcb3_dram_udqs : inout std_logic; mcb3_dram_udqs_n : inout std_logic; mcb3_rzq : inout std_logic; mcb3_zio : inout std_logic; mcb3_dram_udm : out std_logic; mcb3_dram_dqs : inout std_logic; mcb3_dram_dqs_n : inout std_logic; mcb3_dram_ck : out std_logic; mcb3_dram_ck_n : out std_logic; ahbso : out ahb_slv_out_type; ahbsi : in ahb_slv_in_type; ahbmi : out ahb_mst_in_type; ahbmo : in ahb_mst_out_type; apbi : in apb_slv_in_type; apbo : out apb_slv_out_type; calib_done : out std_logic; rst_n_syn : in std_logic; rst_n_async : in std_logic; clk_amba : in std_logic; clk_mem_p : in std_logic; clk_mem_n : in std_logic; clk_125 : out std_logic; clk_50 : out std_logic ); end ; architecture rtl of ahb2mig_sp605 is type bstate_type is (idle, start, read1); constant hconfig : ahb_config_type := ( 0 => ahb_device_reg ( VENDOR_GAISLER, GAISLER_MIGDDR2, 0, 0, 0), 4 => ahb_membar(haddr, '1', '1', hmask), -- 5 => ahb_iobar(ioaddr, iomask), others => zero32); constant pconfig : apb_config_type := ( 0 => ahb_device_reg ( VENDOR_GAISLER, GAISLER_MIGDDR2, 0, 0, 0), 1 => apb_iobar(paddr, pmask)); type reg_type is record bstate : bstate_type; cmd_bl : std_logic_vector(5 downto 0); wr_count : std_logic_vector(6 downto 0); rd_cnt : std_logic_vector(5 downto 0); hready : std_logic; hsel : std_logic; hwrite : std_logic; htrans : std_logic_vector(1 downto 0); hburst : std_logic_vector(2 downto 0); hsize : std_logic_vector(2 downto 0); hrdata : std_logic_vector(31 downto 0); haddr : std_logic_vector(31 downto 0); hmaster : std_logic_vector(3 downto 0); end record; type mcb_type is record cmd_en : std_logic; cmd_instr : std_logic_vector(2 downto 0); cmd_empty : std_logic; cmd_full : std_logic; cmd_bl : std_logic_vector(5 downto 0); cmd_byte_addr : std_logic_vector(29 downto 0); wr_full : std_logic; wr_empty : std_logic; wr_underrun : std_logic; wr_error : std_logic; wr_mask : std_logic_vector(3 downto 0); wr_en : std_logic; wr_data : std_logic_vector(31 downto 0); wr_count : std_logic_vector(6 downto 0); rd_data : std_logic_vector(31 downto 0); rd_full : std_logic; rd_empty : std_logic; rd_count : std_logic_vector(6 downto 0); rd_overflow : std_logic; rd_error : std_logic; rd_en : std_logic; end record; type reg2_type is record bstate : bstate_type; cmd_bl : std_logic_vector(5 downto 0); rd_cnt : std_logic_vector(5 downto 0); hready : std_logic; hsel : std_logic; hrdata : std_logic_vector(31 downto 0); haddr : std_logic_vector(31 downto 0); end record; type p2_if_type is record cmd_en : std_logic; cmd_instr : std_logic_vector(2 downto 0); cmd_bl : std_logic_vector(5 downto 0); cmd_empty : std_logic; cmd_full : std_logic; rd_en : std_logic; rd_data : std_logic_vector(31 downto 0); rd_full : std_logic; rd_empty : std_logic; rd_count : std_logic_vector(6 downto 0); rd_overflow : std_logic; rd_error : std_logic; end record; signal r, rin : reg_type; signal r2, r2in : reg2_type; signal i : mcb_type; signal p2 : p2_if_type; begin comb: process( rst_n_syn, r, ahbsi, i ) variable v : reg_type; variable wmask : std_logic_vector(3 downto 0); variable wr_en : std_logic; variable cmd_en : std_logic; variable cmd_instr : std_logic_vector(2 downto 0); variable rd_en : std_logic; variable cmd_bl : std_logic_vector(5 downto 0); variable hwdata : std_logic_vector(31 downto 0); variable readdata : std_logic_vector(31 downto 0); begin v := r; wr_en := '0'; cmd_en := '0'; cmd_instr := "000"; rd_en := '0'; if (ahbsi.hready = '1') then if (ahbsi.hsel(hindex) and ahbsi.htrans(1)) = '1' then v.hsel := '1'; v.hburst := ahbsi.hburst; v.hwrite := ahbsi.hwrite; v.hsize := ahbsi.hsize; v.hmaster := ahbsi.hmaster; v.hready := '0'; if ahbsi.htrans(0) = '0' then v.haddr := ahbsi.haddr; end if; else v.hsel := '0'; v.hready := '1'; end if; v.htrans := ahbsi.htrans; end if; hwdata := ahbsi.hwdata(15 downto 0) & ahbsi.hwdata(31 downto 16); case r.hsize(1 downto 0) is when "00" => wmask := not decode(r.haddr(1 downto 0)); case r.haddr(1 downto 0) is when "00" => wmask := "1101"; when "01" => wmask := "1110"; when "10" => wmask := "0111"; when others => wmask := "1011"; end case; when "01" => wmask := not decode(r.haddr(1 downto 0)); wmask(3) := wmask(2); wmask(1) := wmask(0); when others => wmask := "0000"; end case; i.wr_mask <= wmask; cmd_bl := r.cmd_bl; case r.bstate is when idle => if v.hsel = '1' then v.bstate := start; v.hready := ahbsi.hwrite and not i.cmd_full and not i.wr_full; v.haddr := ahbsi.haddr; end if; v.cmd_bl := (others => '0'); when start => if r.hwrite = '1' then v.haddr := r.haddr; if r.hready = '1' then v.cmd_bl := r.cmd_bl + 1; v.hready := '1'; wr_en := '1'; if (ahbsi.htrans /= "11") then if v.hsel = '1' then if (ahbsi.hwrite = '0') or (i.wr_count >= "0000100") then v.hready := '0'; else v.hready := '1'; end if; else v.bstate := idle; end if; v.cmd_bl := (others => '0'); v.haddr := ahbsi.haddr; cmd_en := '1'; elsif (i.cmd_full = '1') then v.hready := '0'; elsif (i.wr_count >= "0101111") then v.hready := '0'; cmd_en := '1'; v.cmd_bl := (others => '0'); v.haddr := ahbsi.haddr; end if; else if (i.cmd_full = '0') and (i.wr_count <= "0001111") then v.hready := '1'; end if; end if; else if i.cmd_full = '0' then cmd_en := '1'; cmd_instr(0) := '1'; v.cmd_bl := "000" & not r.haddr(4 downto 2); cmd_bl := v.cmd_bl; v.bstate := read1; end if; end if; when read1 => v.hready := '0'; if (r.rd_cnt = "000000") then -- flush data from previous line if (i.rd_empty = '0') or ((r.hready = '1') and (ahbsi.htrans /= "11")) then v.hrdata(31 downto 0) := i.rd_data(15 downto 0) & i.rd_data(31 downto 16); v.hready := '1'; if (i.rd_empty = '0') then v.cmd_bl := r.cmd_bl - 1; rd_en := '1'; end if; if (r.cmd_bl = "000000") or (ahbsi.htrans /= "11") then if (ahbsi.hsel(hindex) = '1') and (ahbsi.htrans = "10") and (r.hready = '1') then v.bstate := start; v.hready := ahbsi.hwrite and not i.cmd_full and not i.wr_full; v.cmd_bl := (others => '0'); else v.bstate := idle; end if; if (i.rd_empty = '1') then v.rd_cnt := r.cmd_bl + 1; else v.rd_cnt := r.cmd_bl; end if; end if; end if; end if; when others => end case; readdata := (others => '0'); -- case apbi.paddr(5 downto 2) is -- when "0000" => readdata(nbits-1 downto 0) := r.din2; -- when "0001" => readdata(nbits-1 downto 0) := r.dout; -- when others => -- end case; readdata(20 downto 0) := i.rd_error & i.rd_overflow & i.wr_error & i.wr_underrun & i.cmd_full & i.rd_full & i.rd_empty & i.wr_full & i.wr_empty & r.rd_cnt & r.cmd_bl; if (r.rd_cnt /= "000000") and (i.rd_empty = '0') then rd_en := '1'; v.rd_cnt := r.rd_cnt - 1; end if; if rst_n_syn = '0' then v.rd_cnt := "000000"; v.bstate := idle; v.hready := '1'; end if; rin <= v; apbo.prdata <= readdata; i.rd_en <= rd_en; i.wr_en <= wr_en; i.cmd_bl <= cmd_bl; i.cmd_en <= cmd_en; i.cmd_instr <= cmd_instr; i.wr_data <= hwdata; end process; i.cmd_byte_addr <= r.haddr(29 downto 2) & "00"; ahbso.hready <= r.hready; ahbso.hresp <= "00"; --r.hresp; ahbso.hrdata <= r.hrdata; ahbso.hconfig <= hconfig; ahbso.hirq <= (others => '0'); ahbso.hindex <= hindex; ahbso.hsplit <= (others => '0'); ahbso.hcache <= '1'; apbo.pindex <= pindex; apbo.pconfig <= pconfig; apbo.pirq <= (others => '0'); regs : process(clk_amba) begin if rising_edge(clk_amba) then r <= rin; end if; end process; port2 : if vgamst /= 0 generate comb2: process( rst_n_syn, r2, ahbmo, p2 ) variable v2 : reg2_type; variable cmd_en : std_logic; variable rd_en : std_logic; begin v2 := r2; cmd_en := '0'; rd_en := '0'; case r2.bstate is when idle => if ahbmo.htrans(1) = '1' then v2.bstate := start; v2.hready := '0'; v2.haddr := ahbmo.haddr; else v2.hready := '1'; end if; v2.cmd_bl := (others => '0'); when start => if p2.cmd_full = '0' then cmd_en := '1'; v2.cmd_bl := conv_std_logic_vector(vgaburst-1, 6); v2.bstate := read1; end if; when read1 => v2.hready := '0'; if (r2.rd_cnt = "000000") then -- flush data from previous line if (p2.rd_empty = '0') or ((r2.hready = '1') and (ahbmo.htrans /= "11")) then v2.hrdata(31 downto 0) := p2.rd_data(15 downto 0) & p2.rd_data(31 downto 16); v2.hready := '1'; if (p2.rd_empty = '0') then v2.cmd_bl := r2.cmd_bl - 1; rd_en := '1'; end if; if (r2.cmd_bl = "000000") or (ahbmo.htrans /= "11") then if (ahbmo.htrans = "10") and (r2.hready = '1') then v2.bstate := start; v2.hready := '0'; v2.cmd_bl := (others => '0'); else v2.bstate := idle; end if; if (p2.rd_empty = '1') then v2.rd_cnt := r2.cmd_bl + 1; else v2.rd_cnt := r2.cmd_bl; end if; end if; end if; end if; when others => end case; if (r2.rd_cnt /= "000000") and (p2.rd_empty = '0') then rd_en := '1'; v2.rd_cnt := r2.rd_cnt - 1; end if; v2.haddr(1 downto 0) := "00"; if rst_n_syn = '0' then v2.rd_cnt := "000000"; v2.bstate := idle; v2.hready := '1'; end if; r2in <= v2; p2.rd_en <= rd_en; p2.cmd_bl <= v2.cmd_bl; p2.cmd_en <= cmd_en; p2.cmd_instr <= "001"; end process; ahbmi.hrdata <= r2.hrdata; ahbmi.hresp <= "00"; ahbmi.hgrant <= (others => '1'); ahbmi.hready <= r2.hready; ahbmi.hcache <= '0'; ahbmi.hirq <= (others => '0'); ahbmi.testen <= '0'; ahbmi.testrst <= '0'; ahbmi.scanen <= '0'; ahbmi.testoen <= '0'; regs : process(clk_amba) begin if rising_edge(clk_amba) then r2 <= r2in; end if; end process; end generate; noport2 : if vgamst = 0 generate p2.cmd_en <= '0'; p2.rd_en <= '0'; end generate; MCB_inst : entity work.mig_38 generic map( C3_P0_MASK_SIZE => 4, C3_P0_DATA_PORT_SIZE => 32, C3_P1_MASK_SIZE => 4, C3_P1_DATA_PORT_SIZE => 32, -- C3_MEMCLK_PERIOD => 5000, C3_RST_ACT_LOW => 1, C3_INPUT_CLK_TYPE => "DIFFERENTIAL", C3_CALIB_SOFT_IP => "TRUE", -- pragma translate_off C3_SIMULATION => "TRUE", -- pragma translate_on C3_MEM_ADDR_ORDER => "BANK_ROW_COLUMN", C3_NUM_DQ_PINS => 16, C3_MEM_ADDR_WIDTH => 13, C3_MEM_BANKADDR_WIDTH => 3 ) port map ( mcb3_dram_dq => mcb3_dram_dq, mcb3_dram_a => mcb3_dram_a, mcb3_dram_ba => mcb3_dram_ba, mcb3_dram_ras_n => mcb3_dram_ras_n, mcb3_dram_cas_n => mcb3_dram_cas_n, mcb3_dram_we_n => mcb3_dram_we_n, mcb3_dram_odt => mcb3_dram_odt, mcb3_dram_reset_n => mcb3_dram_reset_n, mcb3_dram_cke => mcb3_dram_cke, mcb3_dram_dm => mcb3_dram_dm, mcb3_dram_udqs => mcb3_dram_udqs, mcb3_dram_udqs_n => mcb3_dram_udqs_n, mcb3_rzq => mcb3_rzq, mcb3_zio => mcb3_zio, mcb3_dram_udm => mcb3_dram_udm, c3_sys_clk_p => clk_mem_p, c3_sys_clk_n => clk_mem_n, c3_sys_rst_i => rst_n_async, c3_calib_done => calib_done, c3_clk0 => open, c3_rst0 => open, mcb3_dram_dqs => mcb3_dram_dqs, mcb3_dram_dqs_n => mcb3_dram_dqs_n, mcb3_dram_ck => mcb3_dram_ck, mcb3_dram_ck_n => mcb3_dram_ck_n, c3_p0_cmd_clk => clk_amba, c3_p0_cmd_en => i.cmd_en, c3_p0_cmd_instr => i.cmd_instr, c3_p0_cmd_bl => i.cmd_bl, c3_p0_cmd_byte_addr => i.cmd_byte_addr, c3_p0_cmd_empty => i.cmd_empty, c3_p0_cmd_full => i.cmd_full, c3_p0_wr_clk => clk_amba, c3_p0_wr_en => i.wr_en, c3_p0_wr_mask => i.wr_mask, c3_p0_wr_data => i.wr_data, c3_p0_wr_full => i.wr_full, c3_p0_wr_empty => i.wr_empty, c3_p0_wr_count => i.wr_count, c3_p0_wr_underrun => i.wr_underrun, c3_p0_wr_error => i.wr_error, c3_p0_rd_clk => clk_amba, c3_p0_rd_en => i.rd_en, c3_p0_rd_data => i.rd_data, c3_p0_rd_full => i.rd_full, c3_p0_rd_empty => i.rd_empty, c3_p0_rd_count => i.rd_count, c3_p0_rd_overflow => i.rd_overflow, c3_p0_rd_error => i.rd_error, c3_p2_cmd_clk => clk_amba, c3_p2_cmd_en => p2.cmd_en, c3_p2_cmd_instr => p2.cmd_instr, c3_p2_cmd_bl => p2.cmd_bl, c3_p2_cmd_byte_addr => r2.haddr(29 downto 0), c3_p2_cmd_empty => p2.cmd_empty, c3_p2_cmd_full => p2.cmd_full, c3_p2_rd_clk => clk_amba, c3_p2_rd_en => p2.rd_en, c3_p2_rd_data => p2.rd_data, c3_p2_rd_full => p2.rd_full, c3_p2_rd_empty => p2.rd_empty, c3_p2_rd_count => p2.rd_count, c3_p2_rd_overflow => p2.rd_overflow, c3_p2_rd_error => p2.rd_error, clk_125 => clk_125, clk_50 => clk_50 ); end;