URL
https://opencores.org/ocsvn/mips_enhanced/mips_enhanced/trunk
Subversion Repositories mips_enhanced
[/] [mips_enhanced/] [trunk/] [grlib-gpl-1.0.19-b3188/] [lib/] [gaisler/] [ddr/] [ddrsp16a.vhd] - Rev 2
Compare with Previous | Blame | View Log
------------------------------------------------------------------------------ -- This file is a part of the GRLIB VHDL IP LIBRARY -- Copyright (C) 2003, Gaisler Research -- -- 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: ddrsp16a -- File: ddrsp16a.vhd -- Author: Jiri Gaisler - Gaisler Research -- Description: 16-bit DDR266 memory controller with asych AHB interface ------------------------------------------------------------------------------ library ieee; use ieee.std_logic_1164.all; library grlib; use grlib.amba.all; use grlib.stdlib.all; library gaisler; use grlib.devices.all; use gaisler.memctrl.all; library techmap; use techmap.gencomp.all; entity ddrsp16a is generic ( memtech : integer := 0; hindex : integer := 0; haddr : integer := 0; hmask : integer := 16#f00#; ioaddr : integer := 16#000#; iomask : integer := 16#fff#; MHz : integer := 100; col : integer := 9; Mbyte : integer := 8; fast : integer := 0; pwron : integer := 0; oepol : integer := 0; mobile : integer := 0; confapi : integer := 0; conf0 : integer := 0; conf1 : integer := 0; regoutput : integer := 0 ); port ( rst : in std_ulogic; clk_ddr : in std_ulogic; clk_ahb : in std_ulogic; clkread : in std_ulogic; ahbsi : in ahb_slv_in_type; ahbso : out ahb_slv_out_type; sdi : in sdctrl_in_type; sdo : out sdctrl_out_type ); end; architecture rtl of ddrsp16a is constant REVISION : integer := 0; constant CMD_PRE : std_logic_vector(2 downto 0) := "010"; constant CMD_REF : std_logic_vector(2 downto 0) := "100"; constant CMD_LMR : std_logic_vector(2 downto 0) := "110"; constant CMD_EMR : std_logic_vector(2 downto 0) := "111"; constant PM_PD : std_logic_vector(2 downto 0) := "001"; constant PM_SR : std_logic_vector(2 downto 0) := "010"; constant PM_CKS : std_logic_vector(2 downto 0) := "100"; constant PM_DPD : std_logic_vector(2 downto 0) := "101"; constant abuf : integer := 6; constant hconfig : ahb_config_type := ( 0 => ahb_device_reg ( VENDOR_GAISLER, GAISLER_DDRSP, 0, REVISION, 0), 4 => ahb_membar(haddr, '1', '1', hmask), 5 => ahb_iobar(ioaddr, iomask), others => zero32); type mcycletype is (midle, active, ext, leadout); type ahb_state_type is (midle, rhold, dread, dwrite, whold1, whold2); type sdcycletype is (act1, act2, act3, rd1, rd2, rd2a, rd3, rd3a, rd4, rd5, rd6, rd7, rd8, wr1, wr2, wr3, wr4a, wr4, wr5, sidle, ioreg1, ioreg2, sref, cks, pd, dpd, srr1, srr2, srr3); type icycletype is (iidle, pre, ref1, ref2, emode, lmode, finish); -- sdram configuration register type sdram_cfg_type is record command : std_logic_vector(2 downto 0); csize : std_logic_vector(1 downto 0); bsize : std_logic_vector(2 downto 0); trcd : std_ulogic; -- tCD : 2/3 clock cycles trfc : std_logic_vector(2 downto 0); trp : std_ulogic; -- precharge to activate: 2/3 clock cycles refresh : std_logic_vector(11 downto 0); renable : std_ulogic; dllrst : std_ulogic; refon : std_ulogic; cke : std_ulogic; pasr : std_logic_vector(5 downto 0); -- pasr(2:0) (pasr(5:3) used to detect update) tcsr : std_logic_vector(3 downto 0); -- tcrs(1:0) (tcrs(3:2) used to detect update) ds : std_logic_vector(5 downto 0); -- ds(1:0) (ds(3:2) used to detect update) pmode : std_logic_vector(2 downto 0); -- Power-Saving mode mobileen : std_logic_vector(1 downto 0); -- Mobile SD support, Mobile SD enabled txsr : std_logic_vector(3 downto 0); -- Exit Self Refresh timing txp : std_logic; -- Exit Power-Down timing tcke : std_logic; -- Clock enable timing cl : std_logic; -- CAS latency 2/3 (0/1) conf : std_logic_vector(63 downto 0); -- PHY control end record; type access_param is record haddr : std_logic_vector(31 downto 0); size : std_logic_vector(1 downto 0); hwrite : std_ulogic; hio : std_ulogic; end record; -- local registers type ahb_reg_type is record hready : std_ulogic; hsel : std_ulogic; hio : std_ulogic; startsd : std_ulogic; ready : std_ulogic; ready2 : std_ulogic; write : std_ulogic; state : ahb_state_type; haddr : std_logic_vector(31 downto 0); hrdata : std_logic_vector(31 downto 0); hwdata : std_logic_vector(31 downto 0); hwrite : std_ulogic; htrans : std_logic_vector(1 downto 0); hresp : std_logic_vector(1 downto 0); raddr : std_logic_vector(abuf-1 downto 0); size : std_logic_vector(1 downto 0); acc : access_param; end record; type ddr_reg_type is record startsd : std_ulogic; startsdold : std_ulogic; burst : std_ulogic; hready : std_ulogic; bdrive : std_ulogic; qdrive : std_ulogic; nbdrive : std_ulogic; mstate : mcycletype; sdstate : sdcycletype; cmstate : mcycletype; istate : icycletype; trfc : std_logic_vector(3 downto 0); -- Extend trfc for mobile ddr refresh : std_logic_vector(11 downto 0); sdcsn : std_logic_vector(1 downto 0); sdwen : std_ulogic; rasn : std_ulogic; casn : std_ulogic; dqm : std_logic_vector(3 downto 0); dqm_dly : std_logic_vector(3 downto 0); -- *** ??? delay ctrl wdata : std_logic_vector(31 downto 0); -- *** ??? delay ctrl address : std_logic_vector(15 downto 2); -- memory address ba : std_logic_vector(1 downto 0); waddr : std_logic_vector(abuf-1 downto 0); cfg : sdram_cfg_type; idlecnt : std_logic_vector(3 downto 0); -- Counter, 16 idle clock sycles before entering Power-Saving mode ck : std_logic_vector(2 downto 0); -- Clock stop signal, 0 = clock stoped, 1 = clock running txp : std_logic; tcke : std_logic; sref_tmpcom : std_logic_vector(2 downto 0); -- Save SD command when exit sref extdqs : std_logic; -- Extend dqs postamble sdo_bdrive : std_logic; -- *** ??? delay ctrl sdo_qdrive : std_logic; -- *** ??? delay ctrl ck_dly : std_logic_vector(2 downto 0); -- *** ??? delay ctrl cke_dly : std_logic; -- *** ??? delay ctrl end record; signal vcc, rwrite : std_ulogic; signal r, ri : ddr_reg_type; signal ra, rai : ahb_reg_type; signal rdata, wdata, rwdata, rbdrive, ribdrive : std_logic_vector(31 downto 0); signal waddr2 : std_logic_vector(abuf-1 downto 0); signal ddr_rst : std_logic; signal ddr_rst_gen : std_logic_vector(3 downto 0); attribute syn_preserve : boolean; attribute syn_preserve of rbdrive : signal is true; begin vcc <= '1'; ddr_rst <= (ddr_rst_gen(3) and ddr_rst_gen(2) and ddr_rst_gen(1) and rst); -- Reset signal in DDR clock domain ahb_ctrl : process(rst, ahbsi, r, ra, rdata) variable v : ahb_reg_type; -- local variables for registers variable startsd : std_ulogic; variable dout : std_logic_vector(31 downto 0); begin v := ra; v.hrdata := rdata; v.hresp := HRESP_OKAY; v.write := '0'; v.ready := not (ra.startsd xor r.startsdold); v.ready2 := ra.ready; if ((ahbsi.hready and ahbsi.hsel(hindex)) = '1') then v.htrans := ahbsi.htrans; v.haddr := ahbsi.haddr; v.size := ahbsi.hsize(1 downto 0); v.hwrite := ahbsi.hwrite; if ahbsi.htrans(1) = '1' then v.hio := ahbsi.hmbsel(1); v.hsel := '1'; v.hready := '0'; end if; end if; if ahbsi.hready = '1' then v.hsel := ahbsi.hsel(hindex); end if; -- if (ra.hsel and ra.hio and not ra.hready) = '1' then v.hready := '1'; end if; case ra.state is when midle => if ((v.hsel and v.htrans(1)) = '1') then if v.hwrite = '0' then v.state := rhold; v.startsd := not ra.startsd; else v.state := dwrite; v.hready := '1'; v.write := '1'; end if; end if; v.raddr := ra.haddr(7 downto 2); v.ready := '0'; v.ready2 := '0'; if ahbsi.hready = '1' then v.acc := (v.haddr, v.size, v.hwrite, v.hio); end if; when rhold => v.raddr := ra.haddr(7 downto 2); if ra.ready2 = '1' then v.state := dread; v.hready := '1'; v.raddr := ra.raddr + 1; end if; when dread => v.raddr := ra.raddr + 1; v.hready := '1'; if ((v.hsel and v.htrans(1) and v.htrans(0)) = '0') or (ra.raddr(2 downto 0) = "000") -- then v.state := midle; v.hready := '0'; end if; then v.state := midle; v.hready := not (v.hsel and v.htrans(1)); if (v.hsel and v.htrans(1) and v.hwrite) = '1' then v.state := dwrite; v.hready := '1'; v.write := '1'; v.ready := '0'; v.ready2 := '0'; end if; end if; v.acc := (v.haddr, v.size, v.hwrite, v.hio); when dwrite => v.raddr := ra.haddr(7 downto 2); v.write := '1'; v.hready := '1'; if ((v.hsel and v.htrans(1) and v.htrans(0)) = '0') or ((ra.haddr(4 downto 2) = "111") and (ra.write = '1')) then v.startsd := not ra.startsd; v.state := whold1; v.write := '0'; v.hready := not (v.hsel and v.htrans(1)); -- v.write := '0'; v.hready := '0'; end if; when whold1 => v.state := whold2; v.ready := '0'; when whold2 => if ra.ready = '1' then v.state := midle; v.acc := (v.haddr, v.size, v.hwrite, v.hio); end if; end case; v.hwdata := ahbsi.hwdata; if (ahbsi.hready and ahbsi.hsel(hindex) ) = '1' then if ahbsi.htrans(1) = '0' then v.hready := '1'; end if; end if; -- if (ra.hsel and ra.hio) = '1' then dout := regsd; -- else dout := ra.hrdata(31 downto 0); end if; dout := ra.hrdata(31 downto 0); if rst = '0' then v.hsel := '0'; v.hready := '1'; v.state := midle; v.startsd := '0'; v.hio := '0'; end if; rai <= v; ahbso.hready <= ra.hready; ahbso.hresp <= ra.hresp; ahbso.hrdata <= dout; ahbso.hcache <= not ra.hio; end process; ddr_ctrl : process(ddr_rst, r, ra, sdi, rbdrive, wdata) variable v : ddr_reg_type; -- local variables for registers variable startsd : std_ulogic; variable dataout : std_logic_vector(31 downto 0); -- data from memory variable dqm : std_logic_vector(3 downto 0); variable raddr : std_logic_vector(13 downto 0); variable adec : std_ulogic; variable rams : std_logic_vector(1 downto 0); variable ba : std_logic_vector(1 downto 0); variable haddr : std_logic_vector(31 downto 0); variable hsize : std_logic_vector(1 downto 0); variable hwrite : std_ulogic; variable htrans : std_logic_vector(1 downto 0); variable hready : std_ulogic; variable vbdrive : std_logic_vector(31 downto 0); variable bdrive : std_ulogic; variable writecfg: std_ulogic; variable regsd : std_logic_vector(31 downto 0); -- data from registers variable readdata: std_logic_vector(31 downto 0); -- data from DDR variable arefresh: std_logic; begin -- Variable default settings to avoid latches v := r; v.hready := '0'; writecfg := '0'; vbdrive := rbdrive; readdata := sdi.data(31 downto 0); v.qdrive :='0'; v.txp := '0'; v.tcke := '0'; arefresh := '0'; v.wdata := wdata; -- *** ??? delay ctrl v.dqm_dly := r.dqm; -- *** ??? delay ctrl v.ck_dly := r.ck; -- *** ??? delay ctrl v.cke_dly := r.cfg.cke; -- *** ??? delay ctrl regsd := (others => '0'); if ra.acc.haddr(4 downto 2) = "000" then regsd(31 downto 15) := r.cfg.refon & r.cfg.trp & r.cfg.trfc & r.cfg.trcd & r.cfg.bsize & r.cfg.csize & r.cfg.command & r.cfg.dllrst & r.cfg.renable & r.cfg.cke; regsd(11 downto 0) := r.cfg.refresh; elsif ra.acc.haddr(4 downto 2) = "001" then regsd(8 downto 0) := conv_std_logic_vector(MHz, 9); regsd(14 downto 12) := conv_std_logic_vector(1, 3); regsd(15) := r.cfg.mobileen(1); -- Mobile DDR support regsd(19 downto 16) := conv_std_logic_vector(confapi, 4); elsif ra.acc.haddr(4 downto 2) = "010" then regsd(31 downto 30) := r.cfg.mobileen(0) & r.cfg.cl; -- Mobile DDR enable regsd(24 downto 19) := r.cfg.tcke & r.cfg.txsr & r.cfg.txp; regsd(18 downto 16) := r.cfg.pmode; regsd( 7 downto 0) := r.cfg.ds(2 downto 0) & r.cfg.tcsr(1 downto 0) & r.cfg.pasr(2 downto 0); elsif ra.acc.haddr(4 downto 2) = "101" and confapi /= 0 then regsd(31 downto 0) := r.cfg.conf(31 downto 0); elsif ra.acc.haddr(4 downto 2) = "110" and confapi /= 0 then regsd(31 downto 0) := r.cfg.conf(63 downto 32); end if; -- generate DQM from address and write size case ra.acc.size is when "00" => case ra.acc.haddr(1 downto 0) is when "00" => dqm := "0111"; when "01" => dqm := "1011"; when "10" => dqm := "1101"; when others => dqm := "1110"; end case; when "01" => if ra.acc.haddr(1) = '0' then dqm := "0011"; else dqm := "1100"; end if; when others => dqm := "0000"; end case; v.startsd := ra.startsd; -- main FSM case r.mstate is when midle => if r.startsd = '1' then if (r.sdstate = sidle) and (r.cfg.command = "000") and (r.cmstate = midle) then startsd := '1'; v.mstate := active; end if; end if; when others => null; end case; startsd := r.startsd xor r.startsdold; -- generate row and column address size haddr := ra.acc.haddr; haddr(31 downto 20) := haddr(31 downto 20) and not conv_std_logic_vector(hmask, 12); case r.cfg.csize is when "00" => raddr := haddr(23 downto 10); when "01" => raddr := haddr(24 downto 11); when "10" => raddr := haddr(25 downto 12); when others => raddr := haddr(26 downto 13); end case; -- generate bank address ba := genmux(r.cfg.bsize, haddr(29 downto 22)) & genmux(r.cfg.bsize, haddr(28 downto 21)); -- generate chip select adec := genmux(r.cfg.bsize, haddr(30 downto 23)); rams := adec & not adec; -- sdram access FSM if r.trfc /= "0000" then v.trfc := r.trfc - 1; end if; -- Extend trfc for mobile ddr if r.idlecnt /= "0000" then v.idlecnt := r.idlecnt - 1; end if; case r.sdstate is when sidle => v.extdqs := '1'; if (startsd = '1') and (r.cfg.command = "000") and (r.cmstate = midle) and (r.istate = finish) then v.address := raddr; v.ba := ba; if ra.acc.hio = '0' then v.sdcsn := not rams(1 downto 0); v.rasn := '0'; v.sdstate := act1; elsif ra.acc.haddr(4 downto 2) = "100" and r.cfg.mobileen(0) = '1' then v.sdstate := srr1; else v.sdstate := ioreg1; end if; elsif (r.cfg.command = "000") and (r.cmstate = midle) and (r.istate = finish) and r.idlecnt = "0000" and (r.cfg.mobileen(1) = '1') then case r.cfg.pmode is when PM_SR => v.cfg.cke := '0'; v.sdstate := sref; when PM_CKS => v.ck := (others => '0'); v.sdstate := cks; when PM_PD => v.cfg.cke := '0'; v.sdstate := pd; when PM_DPD => v.cfg.cke := '0'; v.sdstate := dpd; when others => end case; if r.cfg.pmode /= "000" then v.trfc := (r.cfg.trp and r.cfg.mobileen(1)) & r.cfg.trfc; end if; -- Extend trfc for mobile ddr end if; v.waddr := ra.acc.haddr(7 downto 2); when act1 => v.rasn := '1'; v.trfc := (r.cfg.trp and r.cfg.mobileen(1)) & r.cfg.trfc; -- Extend trfc for mobile ddr if r.cfg.trcd = '1' then v.sdstate := act2; else v.sdstate := act3; v.hready := ra.acc.hwrite; end if; v.waddr := ra.acc.haddr(7 downto 2); when act2 => v.sdstate := act3; v.hready := ra.acc.hwrite; when act3 => v.casn := '0'; v.address := ra.acc.haddr(13 downto 11) & '0' & ra.acc.haddr(10 downto 2) & '0'; v.dqm := dqm; if ra.acc.hwrite = '1' then v.waddr := r.waddr + 1; v.sdstate := wr1; v.sdwen := '0'; v.bdrive := '0'; v.qdrive := '1'; if (r.waddr /= ra.raddr) then v.hready := '1'; end if; else v.sdstate := rd1; end if; when wr1 => v.sdwen := '1'; v.casn := '1'; v.qdrive := '1'; v.waddr := r.waddr + 1; v.address(8 downto 3) := r.waddr; if (r.waddr <= ra.raddr) and (r.waddr /= "000000") and (r.hready = '1') then v.extdqs := '0'; v.hready := '1'; if (r.hready = '1') and (r.waddr(1 downto 0) = "00") then v.sdwen := '0'; v.casn := '0'; v.extdqs := '1'; end if; else v.sdstate := wr2; v.dqm := (others => '1'); --v.bdrive := '1'; v.startsdold := r.startsd; end if; when wr2 => v.sdstate := wr3; v.qdrive := '1'; when wr3 => v.sdstate := wr4a; v.qdrive := '1'; when wr4a => v.bdrive := '1'; v.rasn := '0'; v.sdwen := '0'; v.sdstate := wr4; v.qdrive := '1'; when wr4 => v.sdcsn := "11"; v.rasn := '1'; v.sdwen := '1'; --v.qdrive := '0'; if r.extdqs = '1' then v.qdrive := '1'; else v.qdrive := '0'; end if; v.sdstate := wr5; when wr5 => v.sdstate := sidle; v.qdrive := '0'; v.idlecnt := (others => '1'); when rd1 => v.casn := '1'; v.sdstate := rd7; if ra.acc.haddr(4 downto 2) = "011" then v.casn := '0'; v.burst := '1'; v.address(5 downto 3) := "100"; end if; when rd7 => v.casn := '1'; v.sdstate := rd2; if ra.acc.haddr(4 downto 2) = "010" then v.casn := '0'; v.burst := '1'; v.address(5 downto 3) := "100"; end if; when rd2 => --v.casn := '1'; v.sdstate := rd3; v.casn := '1'; if regoutput = 1 then v.sdstate := rd2a; else v.sdstate := rd3; end if; -- delay if registered output if ra.acc.haddr(4 downto 2) = "001" then v.casn := '0'; v.burst := '1'; v.address(5 downto 3) := "100"; end if; when rd2a => -- delay if registered output v.sdstate := rd3; v.hready := '0'; v.casn := '1'; if r.sdwen = '0' then -- ??? this cant be true ??? v.rasn := '1'; v.sdwen := '1'; v.sdcsn := "11"; v.dqm := (others => '1'); elsif ra.acc.haddr(4 downto 2) = "000" then v.casn := '0'; v.burst := '1'; v.address(5) := '1'; --v.waddr := v.address(8 downto 3); -- **** end if; when rd3 => if r.cfg.cl = '0' then -- CL = 2 if fast = 0 then v.startsdold := r.startsd; end if; v.sdstate := rd4; v.hready := '1'; v.casn := '1'; else -- CL = 3 v.sdstate := rd3a; v.hready := '0'; v.casn := '1'; end if; if regoutput = 0 then -- done in rd2a if registered output if r.sdwen = '0' then -- ??? this cant be true ??? v.rasn := '1'; v.sdwen := '1'; v.sdcsn := "11"; v.dqm := (others => '1'); elsif ra.acc.haddr(4 downto 2) = "000" then v.casn := '0'; v.burst := '1'; v.address(5) := '1'; --v.waddr := v.address(8 downto 3); -- **** end if; end if; if v.hready = '1' then v.waddr := r.waddr + 1; end if; when rd3a => if fast = 0 then v.startsdold := r.startsd; end if; v.sdstate := rd4; v.hready := '1'; v.casn := '1'; if v.hready = '1' then v.waddr := r.waddr + 1; end if; if (r.sdcsn /= "11") and (r.waddr(1 downto 0) = "11") and (r.burst = '1') then v.burst := '0'; end if; when rd4 => v.hready := '1'; v.casn := '1'; if (r.sdcsn /= "11") and (r.waddr(1 downto 0) = "11") and (r.burst = '1') then v.burst := '0'; elsif (r.sdcsn = "11") or (r.waddr(1 downto 0) = "11") then v.dqm := (others => '1'); v.burst := '0'; if fast /= 0 then v.startsdold := r.startsd; end if; if (r.sdcsn /= "11") then v.rasn := '0'; v.sdwen := '0'; v.sdstate := rd5; else if r.cfg.trp = '1' then v.sdstate := rd6; else v.sdstate := sidle; v.idlecnt := (others => '1'); end if; end if; end if; if v.hready = '1' then v.waddr := r.waddr + 1; end if; when rd5 => if r.cfg.trp = '1' then v.sdstate := rd6; else v.sdstate := sidle; v.idlecnt := (others => '1'); end if; v.sdcsn := (others => '1'); v.rasn := '1'; v.sdwen := '1'; v.dqm := (others => '1'); when rd6 => v.sdstate := sidle; v.dqm := (others => '1'); v.idlecnt := (others => '1'); v.sdcsn := (others => '1'); v.rasn := '1'; v.sdwen := '1'; when ioreg1 => readdata := regsd; v.sdstate := ioreg2; if ra.acc.hwrite = '0' then v.hready := '1'; end if; when ioreg2 => readdata := regsd; writecfg := ra.acc.hwrite; v.startsdold := r.startsd; case r.cfg.pmode is when PM_SR => v.cfg.cke := '0'; v.sdstate := sref; when PM_CKS => v.ck := (others => '0'); v.sdstate := cks; when PM_PD => v.cfg.cke := '0'; v.sdstate := pd; when PM_DPD => v.cfg.cke := '0'; v.sdstate := dpd; when others => v.sdstate := sidle; v.idlecnt := (others => '1'); end case; if r.cfg.pmode /= "000" and r.cfg.cke = '1' then v.trfc := (r.cfg.trp and r.cfg.mobileen(1)) & r.cfg.trfc; end if; -- Extend trfc for mobile ddr when sref => v.sdcsn := (others => '0'); v.rasn := '0'; v.casn := '0'; if (startsd = '1' and (ra.acc.hio = '0' or ra.acc.haddr(4 downto 2) = "100")) or (r.cfg.command /= "000") or r.cfg.pmode /= PM_SR then if r.trfc = "0000" then v.cfg.cke := '1'; end if; -- Extend trfc for mobile ddr if r.cfg.cke = '1' then v.sdcsn := (others => '0'); v.rasn := '1'; v.casn := '1'; if (r.idlecnt = "0000" and r.cfg.mobileen(0) = '1') -- 120 ns (tXSR) with NOP or (r.refresh(8) = '0' and r.cfg.mobileen(0) = '0') then -- 200 clock cycles v.sdstate := sidle; v.idlecnt := (others => '1'); v.sref_tmpcom := r.cfg.command; v.cfg.command := CMD_REF; end if; else v.idlecnt := r.cfg.txsr; end if; elsif (startsd = '1' and ra.acc.hio = '1') then v.waddr := ra.acc.haddr(7 downto 2); v.sdstate := ioreg1; end if; when cks => if (startsd = '1' and (ra.acc.hio = '0' or ra.acc.haddr(4 downto 2) = "100")) or (r.cfg.command /= "000") or r.cfg.pmode /= PM_CKS then v.ck := (others => '1'); v.sdstate := sidle; v.idlecnt := (others => '1'); elsif (startsd = '1' and ra.acc.hio = '1') then v.waddr := ra.acc.haddr(7 downto 2); v.sdstate := ioreg1; end if; when pd => v.tcke := '1'; if ((startsd = '1' and (ra.acc.hio = '0' or ra.acc.haddr(4 downto 2) = "100")) or (r.cfg.command /= "000") or r.cfg.pmode /= PM_PD) and (r.tcke = '1' or r.cfg.tcke = '0') then v.cfg.cke := '1'; v.txp := r.cfg.cke; if r.cfg.cke = '1' and (r.txp = '1' or r.cfg.txp = '0') then -- 1 - 2 clock cycles v.sdstate := sidle; v.idlecnt := (others => '1'); end if; elsif startsd = '1' and ra.acc.hio = '1' and (r.tcke = '1' or r.cfg.tcke = '0') then v.waddr := ra.acc.haddr(7 downto 2); v.sdstate := ioreg1; end if; when dpd => v.sdcsn := (others => '0'); v.sdwen := '0'; v.rasn := '1'; v.casn := '1'; v.cfg.refon := '0'; if (startsd = '1' and ra.acc.hio = '1') then v.waddr := ra.acc.haddr(7 downto 2); v.sdstate := ioreg1; elsif startsd = '1' then v.startsdold := r.startsd; -- acc all accesses elsif r.cfg.pmode /= PM_DPD then v.cfg.cke := '1'; if r.cfg.cke = '1' then v.sdcsn := (others => '0'); v.sdwen := '1'; v.rasn := '1'; v.casn := '1'; v.sdstate := sidle; v.idlecnt := (others => '1'); end if; end if; when srr1 => -- Load Mode Register "01" v.trfc := "0001"; -- Extend trfc for mobile ddr v.sdcsn := (0 => '0', others => '1'); v.rasn := '0'; v.casn := '0'; v.sdwen := '0'; v.address := (others => '0'); v.ba := "01"; v.sdstate := srr2; when srr2 => -- Read 0 v.sdcsn := (others => '1'); v.rasn := '1'; v.casn := '1'; v.sdwen := '1'; if r.trfc = "0000" then -- Extend trfc for mobile ddr --v.trfc := "011"; -- **** if regoutput = 1 then -- delay if registered output if r.cfg.cl = '1' then v.trfc := "0101"; else v.trfc := "0100"; end if; -- Extend trfc for mobile ddr else if r.cfg.cl = '1' then v.trfc := "0100"; else v.trfc := "0011"; end if; -- Extend trfc for mobile ddr end if; v.sdcsn := (0 => '0', others => '1'); v.casn := '0'; v.sdstate := srr3; end if; when srr3 => -- SRR done v.sdcsn := (others => '1'); v.rasn := '1'; v.casn := '1'; v.sdwen := '1'; if r.trfc = "0000" then -- Extend trfc for mobile ddr v.hready := '1'; v.startsdold := r.startsd; v.sdstate := sidle; v.idlecnt := (others => '1'); end if; when others => v.sdstate := sidle; v.idlecnt := (others => '1'); end case; -- sdram commands case r.cmstate is when midle => if r.sdstate = sidle then case r.cfg.command is when CMD_PRE => -- precharge v.sdcsn := (others => '0'); v.rasn := '0'; v.sdwen := '0'; v.address(12) := '1'; v.cmstate := active; when CMD_REF => -- auto-refresh v.sdcsn := (others => '0'); v.rasn := '0'; v.casn := '0'; v.cmstate := active; when CMD_EMR => -- load-ext-mode-reg v.sdcsn := (others => '0'); v.rasn := '0'; v.casn := '0'; v.sdwen := '0'; v.cmstate := active; --v.ba := "01"; --v.address := "00000000000000"; if r.cfg.mobileen = "11" then v.ba := "10"; v.address := "000000" & r.cfg.ds(2 downto 0) & r.cfg.tcsr(1 downto 0) & r.cfg.pasr(2 downto 0); else v.ba := "01"; v.address := "00000000000000"; end if; when CMD_LMR => -- load-mode-reg v.sdcsn := (others => '0'); v.rasn := '0'; v.casn := '0'; v.sdwen := '0'; v.cmstate := active; v.ba := "00"; v.address := "00000" & r.cfg.dllrst & "0" & "01" & r.cfg.cl & "0011"; when others => null; end case; end if; when active => v.sdcsn := (others => '1'); v.rasn := '1'; v.casn := '1'; v.sdwen := '1'; --v.cfg.command := "000"; v.cfg.command := r.sref_tmpcom; v.sref_tmpcom := "000"; v.cmstate := leadout; v.trfc := (r.cfg.trp and r.cfg.mobileen(1)) & r.cfg.trfc; -- Extend trfc for mobile ddr when others => if r.trfc = "0000" then v.cmstate := midle; end if; -- Extend trfc for mobile ddr end case; -- sdram init case r.istate is when iidle => if r.cfg.renable = '1' then v.cfg.cke := '1'; v.cfg.dllrst := '1'; if r.cfg.cke = '1' then v.istate := pre; v.cfg.command := CMD_PRE; end if; end if; when pre => if r.cfg.command = "000" then if r.cfg.mobileen = "11" then v.cfg.command := CMD_REF; v.istate := ref1; else v.cfg.command := "11" & r.cfg.dllrst; -- CMD_LMR/CMD_EMR if r.cfg.dllrst = '1' then v.istate := emode; else v.istate := lmode; end if; end if; end if; when emode => if r.cfg.command = "000" then if r.cfg.mobileen = "11" then v.istate := finish; --v.cfg.command := CMD_LMR; v.cfg.refon := '1'; v.cfg.renable := '0'; else v.istate := lmode; v.cfg.command := CMD_LMR; end if; end if; when lmode => if r.cfg.command = "000" then if r.cfg.mobileen = "11" then v.cfg.command := CMD_EMR; v.istate := emode; else if r.cfg.dllrst = '1' then if r.refresh(9 downto 8) = "00" then -- > 200 clocks delay v.cfg.command := CMD_PRE; v.istate := ref1; end if; else v.istate := finish; --v.cfg.command := CMD_LMR; v.cfg.refon := '1'; v.cfg.renable := '0'; end if; end if; end if; when ref1 => if r.cfg.command = "000" then v.cfg.command := CMD_REF; v.cfg.dllrst := '0'; v.istate := ref2; end if; when ref2 => if r.cfg.command = "000" then --v.cfg.command := CMD_REF; v.istate := pre; if r.cfg.mobileen = "11" then v.istate := lmode; v.cfg.command := CMD_LMR; else v.cfg.command := CMD_REF; v.istate := pre; end if; end if; when others => --if r.cfg.renable = '1' then if r.cfg.renable = '1' and r.sdstate /= dpd then v.istate := iidle; v.cfg.dllrst := '1'; end if; end case; -- second part of main fsm case r.mstate is when active => if v.hready = '1' then v.mstate := midle; end if; when others => null; end case; -- sdram refresh counter if (((r.cfg.refon = '1') and (r.istate = finish)) or (r.cfg.dllrst = '1')) and (r.cfg.pmode /= PM_SR or r.cfg.mobileen(0) = '0') then v.refresh := r.refresh - 1; if r.cfg.pmode = PM_SR and r.cfg.mobileen(0) = '0' and r.cfg.cke = '0' then v.refresh := (8 => '1', 7 => '1', 6 => '1', 3 => '1', others => '0'); else if (v.refresh(11) and not r.refresh(11)) = '1' then v.refresh := r.cfg.refresh; if r.cfg.dllrst = '0' then v.cfg.command := "100"; arefresh := '1'; end if; end if; end if; end if; -- AHB register access if (ra.acc.hio and ra.acc.hwrite and writecfg) = '1' then if r.waddr(2 downto 0) = "000" then v.cfg.refresh := wdata(11 downto 0); v.cfg.dllrst := wdata(17); v.cfg.command := wdata(20 downto 18); v.cfg.csize := wdata(22 downto 21); v.cfg.bsize := wdata(25 downto 23); v.cfg.trcd := wdata(26); v.cfg.trfc := wdata(29 downto 27); v.cfg.trp := wdata(30); if r.cfg.pmode = "000" then v.cfg.cke := wdata(15); v.cfg.renable := wdata(16); v.cfg.refon := wdata(31); end if; elsif r.waddr(2 downto 0) = "010" then v.cfg.cl := wdata(30); if r.cfg.mobileen(1) = '1' and mobile /= 3 then -- Mobile DDR support v.cfg.mobileen(0) := wdata(31); end if; if r.cfg.mobileen(1) = '1' then v.cfg.pasr(5 downto 3) := wdata( 2 downto 0); v.cfg.tcsr(3 downto 2) := wdata( 4 downto 3); v.cfg.ds(5 downto 3) := wdata( 7 downto 5); v.cfg.pmode := wdata(18 downto 16); v.cfg.txp := wdata(19); v.cfg.txsr := wdata(23 downto 20); v.cfg.tcke := wdata(24); end if; elsif r.waddr(2 downto 0) = "101" and confapi /= 0 then v.cfg.conf(31 downto 0) := wdata(31 downto 0); elsif r.waddr(2 downto 0) = "110" and confapi /= 0 then v.cfg.conf(63 downto 32) := wdata(31 downto 0); end if; end if; -- Disable CS and DPD when Mobile DDR is Disabled if r.cfg.mobileen(0) = '0' then v.cfg.pmode(2) := '0'; end if; -- Update EMR when ds, tcsr or pasr change if r.cfg.command = "000" and arefresh = '0' and r.cfg.mobileen(0) = '1' then if r.cfg.ds(2 downto 0) /= r.cfg.ds(5 downto 3) then v.cfg.command := "111"; v.cfg.ds(2 downto 0) := r.cfg.ds(5 downto 3); end if; if r.cfg.tcsr(1 downto 0) /= r.cfg.tcsr(3 downto 2) then v.cfg.command := "111"; v.cfg.tcsr(1 downto 0) := r.cfg.tcsr(3 downto 2); end if; if r.cfg.pasr(2 downto 0) /= r.cfg.pasr(5 downto 3) then v.cfg.command := "111"; v.cfg.pasr(2 downto 0) := r.cfg.pasr(5 downto 3); end if; end if; v.nbdrive := not v.bdrive; if oepol = 1 then bdrive := r.nbdrive; vbdrive := (others => v.nbdrive); else bdrive := r.bdrive; vbdrive := (others => v.bdrive);end if; -- reset if ddr_rst = '0' then v.sdstate := sidle; v.mstate := midle; v.istate := finish; v.cmstate := midle; v.cfg.command := "000"; v.cfg.csize := conv_std_logic_vector(col-9, 2); v.cfg.bsize := conv_std_logic_vector(log2(Mbyte/8), 3); if MHz > 100 then v.cfg.trcd := '1'; else v.cfg.trcd := '0'; end if; v.cfg.refon := '0'; if mobile >= 2 then -- Extend trfc for mobile ddr if MHz > 100 then v.cfg.trfc := conv_std_logic_vector(98*MHz/1000-10, 3); else v.cfg.trfc := conv_std_logic_vector(98*MHz/1000-2, 3); end if; else v.cfg.trfc := conv_std_logic_vector(75*MHz/1000-2, 3); end if; v.cfg.refresh := conv_std_logic_vector(7800*MHz/1000, 12); v.refresh := (others => '0'); if pwron = 1 then v.cfg.renable := '1'; else v.cfg.renable := '0'; end if; if MHz > 100 then v.cfg.trp := '1'; else v.cfg.trp := '0'; end if; v.dqm := (others => '1'); v.sdwen := '1'; v.rasn := '1'; v.casn := '1'; v.hready := '0'; v.startsd := '0'; v.startsdold := '0'; v.cfg.dllrst := '0'; if mobile >= 2 then v.cfg.cke := '1'; else v.cfg.cke := '0'; end if; v.cfg.pasr := (others => '0'); v.cfg.tcsr := (others => '0'); v.cfg.ds := (others => '0'); v.cfg.pmode := (others => '0'); v.cfg.txsr := conv_std_logic_vector(120*MHz/1000, 4); v.cfg.txp := '1'; v.idlecnt := (others => '1'); v.ck := (others => '1'); if mobile >= 2 then v.cfg.mobileen := "11"; -- Default: Mobile DDR elsif mobile = 1 then v.cfg.mobileen := "10"; -- Mobile DDR support enable else v.cfg.mobileen := "00"; end if; -- Mobile DDR support disable v.sref_tmpcom := "000"; v.cfg.cl := '0'; -- CL = 3/2 -- **** v.cfg.tcke := '1'; if confapi /= 0 then v.cfg.conf(31 downto 0) := conv_std_logic_vector(conf0, 32); --x"0000A0A0"; v.cfg.conf(63 downto 32) := conv_std_logic_vector(conf1, 32);--x"00060606"; end if; end if; if regoutput = 1 then if oepol = 1 then v.sdo_bdrive := r.nbdrive; -- *** ??? delay ctrl else v.sdo_bdrive := r.bdrive; end if; v.sdo_qdrive := not (v.qdrive or r.nbdrive); end if; ri <= v; ribdrive <= vbdrive; rwdata <= readdata; end process; ahbso.hconfig <= hconfig; ahbso.hirq <= (others => '0'); ahbso.hindex <= hindex; ahbregs : process(clk_ahb) begin if rising_edge(clk_ahb) then ra <= rai; end if; end process; ddrregs : process(clk_ddr, rst, ddr_rst) begin if rising_edge(clk_ddr) then r <= ri; rbdrive <= ribdrive; ddr_rst_gen <= ddr_rst_gen(2 downto 0) & '1'; end if; if rst = '0' then ddr_rst_gen <= "0000"; end if; if (ddr_rst = '0') then r.sdcsn <= (others => '1'); r.bdrive <= '1'; r.nbdrive <= '0'; if oepol = 0 then rbdrive <= (others => '1'); else rbdrive <= (others => '0'); end if; --r.cfg.cke <= '0'; if mobile = 2 then r.cfg.cke <= '1'; else r.cfg.cke <= '0'; end if; end if; end process; ddr_read_regs : process(clkread) begin if rising_edge(clkread) then rwrite <= ri.hready; waddr2 <= r.waddr; end if; end process; sdo.address <= '0' & r.address when regoutput = 1 else '0' & ri.address; -- *** ??? delay ctrl sdo.ba <= r.ba when regoutput = 1 else ri.ba; -- *** ??? delay ctrl sdo.bdrive <= r.sdo_bdrive when regoutput = 1 else r.nbdrive when oepol = 1 else r.bdrive; -- *** ??? delay ctrl sdo.qdrive <= r.sdo_qdrive when regoutput = 1 else not (ri.qdrive or r.nbdrive); -- *** ??? delay ctrl sdo.vbdrive <= rbdrive; sdo.sdcsn <= r.sdcsn when regoutput = 1 else ri.sdcsn; -- *** ??? delay ctrl sdo.sdwen <= r.sdwen when regoutput = 1 else ri.sdwen; -- *** ??? delay ctrl sdo.dqm <= "111111111111" & r.dqm_dly when regoutput = 1 else "111111111111" & r.dqm; -- *** ??? delay ctrl sdo.rasn <= r.rasn when regoutput = 1 else ri.rasn; -- *** ??? delay ctrl sdo.casn <= r.casn when regoutput = 1 else ri.casn; -- *** ??? delay ctrl sdo.data <= zero32 & zero32 & zero32 & r.wdata when regoutput = 1 else zero32 & zero32 & zero32 & wdata; -- *** ??? delay ctrl sdo.sdck <= r.ck_dly when regoutput = 1 else r.ck; -- *** ??? delay ctrl sdo.sdcke <= (others => r.cke_dly) when regoutput = 1 else (others => r.cfg.cke); -- *** ??? delay ctrl sdo.moben <= r.cfg.mobileen(0); sdo.conf <= r.cfg.conf; read_buff : syncram_2p generic map (tech => memtech, abits => 6, dbits => 32, sepclk => 1, wrfst => 0) port map ( rclk => clk_ahb, renable => vcc, raddress => rai.raddr, dataout => rdata, wclk => clk_ddr, write => ri.hready, -- dataout => rdata, wclk => clkread, write => rwrite, waddress => r.waddr, datain => rwdata); -- waddress => waddr2, datain => rwdata); write_buff : syncram_2p generic map (tech => memtech, abits => 6, dbits => 32, sepclk => 1, wrfst => 0) port map ( rclk => clk_ddr, renable => vcc, raddress => r.waddr, dataout => wdata, wclk => clk_ahb, write => ra.write, waddress => ra.haddr(7 downto 2), datain => ahbsi.hwdata); -- pragma translate_off bootmsg : report_version generic map ( msg1 => "ddrsp" & tost(hindex) & ": 16-bit DDR266 controller rev " & tost(REVISION) & ", " & tost(Mbyte) & " Mbyte, " & tost(MHz) & " MHz DDR clock"); -- pragma translate_on end;