------------------------------------------------------------------------------ -- This file is a part of the GRLIB VHDL IP LIBRARY -- Copyright (C) 2003 - 2008, Gaisler Research -- Copyright (C) 2008 - 2014, Aeroflex Gaisler -- Copyright (C) 2015 - 2017, Cobham 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: ddr2spax -- File: ddr2spax.vhd -- Author: Magnus Hjorth - Aeroflex Gaisler -- Description: DDR2 memory controller with asynch AHB interface -- Based on ddr2sp(16/32/64)a, generalized and expanded -------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; library grlib; use grlib.stdlib.all; use grlib.amba.all; use grlib.devices.all; library gaisler; use gaisler.ddrpkg.all; use gaisler.ddrintpkg.all; entity ddr2spax_ddr is generic ( ddrbits : integer := 32; burstlen : integer := 8; MHz : integer := 100; TRFC : integer := 130; col : integer := 9; Mbyte : integer := 8; pwron : integer := 0; oepol : integer := 0; readdly : integer := 1; odten : integer := 0; octen : integer := 0; -- dqsgating : integer := 0; nosync : integer := 0; dqsgating : integer := 0; eightbanks : integer range 0 to 1 := 0; -- Set to 1 if 8 banks instead of 4 dqsse : integer range 0 to 1 := 0; -- single ended DQS ddr_syncrst: integer range 0 to 1 := 0; chkbits : integer := 0; bigmem : integer range 0 to 1 := 0; raspipe : integer range 0 to 1 := 0; hwidthen : integer range 0 to 1 := 0; phytech : integer := 0; hasdqvalid : integer := 0; rstdel : integer := 200; phyptctrl : integer := 0; scantest : integer := 0; dis_caslat : integer := 0; dis_init : integer := 0; cke_rst : integer := 0 ); port ( ddr_rst : in std_ulogic; clk_ddr : in std_ulogic; request : in ddr_request_type; start_tog: in std_logic; response : out ddr_response_type; sdi : in ddrctrl_in_type; sdo : out ddrctrl_out_type; wbraddr : out std_logic_vector(log2((16*burstlen)/ddrbits) downto 0); wbrdata : in std_logic_vector(2*(ddrbits+chkbits)-1 downto 0); rbwaddr : out std_logic_vector(log2((16*burstlen)/ddrbits)-1 downto 0); rbwdata : out std_logic_vector(2*(ddrbits+chkbits)-1 downto 0); rbwrite : out std_logic; hwidth : in std_ulogic; reqsel : in std_ulogic; frequest : in ddr_request_type; response2: out ddr_response_type; testen : in std_ulogic; testrst : in std_ulogic; testoen : in std_ulogic ); end ddr2spax_ddr; architecture rtl of ddr2spax_ddr is 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"; function tosl(x: integer) return std_logic is begin if x /= 0 then return '1'; else return '0'; end if; end tosl; function zerov(w: integer) return std_logic_vector is constant r: std_logic_vector(w-1 downto 0) := (others => '0'); begin return r; end zerov; constant l2blen: integer := log2(burstlen)+log2(32); constant l2ddrw: integer := log2(ddrbits*2); constant oepols: std_logic := tosl(oepol); -- Write buffer dimensions -- Write buffer is addressable down to 32-bit level on write (AHB) side. constant wbuf_rabits: integer := 1+l2blen-l2ddrw; -- log2((burstlen*32)/(2*ddrbits)); constant wbuf_rdbits: integer := 2*ddrbits; -- Read buffer dimensions constant rbuf_wabits: integer := l2blen-l2ddrw; -- log2((burstlen*32)/(2*ddrbits)); constant rbuf_wdbits: integer := 2*(ddrbits+chkbits); -- 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(3 downto 0); trcd : std_logic_vector(2 downto 0); -- tRCD : 2-9 clock cycles trfc : std_logic_vector(7 downto 0); trp : std_logic_vector(2 downto 0); -- precharge to activate: 2-9 clock cycles refresh : std_logic_vector(11 downto 0); renable : std_ulogic; dllrst : std_ulogic; refon : std_ulogic; cke : std_ulogic; cal_en : std_logic_vector(7 downto 0); cal_inc : std_logic_vector(7 downto 0); cbcal_en : std_logic_vector(3 downto 0); cbcal_inc : std_logic_vector(3 downto 0); cal_pll : std_logic_vector(1 downto 0); -- *** ??? pll_reconf cal_rst : std_logic; readdly : std_logic_vector(3 downto 0); twr : std_logic_vector(4 downto 0); emr : std_logic_vector(1 downto 0); -- selects EM register ocd : std_ulogic; -- enable/disable ocd dqsctrl : std_logic_vector(7 downto 0); eightbanks : std_ulogic; caslat : std_logic_vector(1 downto 0); -- CAS latency 3-6 odten : std_logic_vector(1 downto 0); tras : std_logic_vector(4 downto 0); -- RAS-to-Precharge minimum trtp : std_ulogic; regmem : std_ulogic; -- Registered memory (1 cycle extra latency) strength : std_ulogic; -- Drive strength 1=reduced, 0=normal end record; constant ddr_burstlen: integer := (burstlen*32)/(2*ddrbits); constant l2ddr_burstlen: integer := l2blen-l2ddrw; type ddrstate is (dsidle,dsrascas,dscaslat,dsreaddly,dsdata,dsdone,dsagain,dsreg,dsrefresh,dspreall); type ddrcmdstate is (dcrstdel,dcoff,dcinit1,dcinit2,dcinit3,dcinit4,dcinit5,dcinit6,dcinit7,dcinit8,dcon); type ddr_reg_type is record s : ddrstate; cmds : ddrcmdstate; response : ddr_response_type; response1 : ddr_response_type; response2 : ddr_response_type; response_prev : ddr_response_type; cfg : sdram_cfg_type; rowsel : std_logic_vector(2 downto 0); endaddr : std_logic_vector(l2blen-4 downto 2); addrlo : std_logic_vector(l2ddrw-4 downto 0); col : std_logic_vector(13 downto 0); hwrite : std_logic; hsize : std_logic_vector(2 downto 0); ctr : std_logic_vector(7 downto 0); casctr : std_logic_vector(l2ddr_burstlen-1 downto 0); datacas : std_logic; prectr : std_logic_vector(5 downto 0); rastimer : std_logic_vector(4 downto 0); tras_met : std_logic; pchpend : std_logic; refctr : std_logic_vector(16 downto 0); refpend : std_logic; pastlast : std_logic; sdo_csn : std_logic_vector(1 downto 0); sdo_wen : std_ulogic; wen_prev : std_ulogic; sdo_rasn : std_ulogic; rasn_pre : std_ulogic; sdo_casn : std_ulogic; sdo_dqm : std_logic_vector(15 downto 0); dqm_prev : std_logic_vector(15 downto 0); twr_plus_cl : std_logic_vector(5 downto 0); request_row : std_logic_vector(14 downto 0); request_bank : std_logic_vector(2 downto 0); request_cs : std_logic_vector(0 downto 0); row : std_logic_vector(14 downto 0); setrow : std_logic; samerow : std_logic; start_tog_prev: std_logic; sdo_bdrive : std_ulogic; sdo_qdrive : std_ulogic; sdo_nbdrive : std_ulogic; sdo_address : std_logic_vector(14 downto 0); sdo_address_prev: std_logic_vector(14 downto 0); sdo_ba : std_logic_vector(2 downto 0); sdo_data : std_logic_vector(sdo.data'length-1 downto 0); sdo_cb : std_logic_vector(sdo.cb'length-1 downto 0); sdo_odt : std_logic; sdo_oct : std_logic; rbwrite : std_logic; rbwdata : std_logic_vector(rbuf_wdbits-1 downto 0); ramaddr : std_logic_vector(rbuf_wabits-1 downto 0); ramaddr_prev : std_logic_vector(rbuf_wabits-1 downto 0); mr_twr : std_logic_vector(2 downto 0); mr_tcl : std_logic_vector(2 downto 0); read_pend : std_logic_vector(15 downto 0); req1,req2 : ddr_request_type; start1,start2 : std_logic; hwidth1 : std_logic; hwidth : std_logic; hwcas : std_logic; hwctr : std_logic; end record; signal dr,ndr : ddr_reg_type; signal muxsel2,muxsel1,muxsel0: std_ulogic; signal muxin4: std_logic_vector(31 downto 0); signal muxout4: std_logic_vector(3 downto 0); signal start_tog_delta1,start_tog_delta2: std_logic; signal arst: std_ulogic; attribute syn_keep: boolean; attribute syn_keep of muxsel2:signal is true; attribute syn_keep of muxsel1:signal is true; attribute syn_keep of muxsel0:signal is true; begin arst <= testrst when (scantest/=0 and ddr_syncrst=0) and testen='1' else ddr_rst; start_tog_delta1 <= start_tog; start_tog_delta2 <= start_tog_delta1; muxsel2 <= dr.rowsel(2); muxsel1 <= dr.rowsel(1); muxsel0 <= dr.rowsel(0); muxproc : process(muxin4,muxsel2,muxsel1,muxsel0) begin muxout4(3) <= genmux((muxsel2 & muxsel1 & muxsel0),muxin4(31 downto 24)); muxout4(2) <= genmux((muxsel2 & muxsel1 & muxsel0),muxin4(23 downto 16)); muxout4(1) <= genmux((muxsel2 & muxsel1 & muxsel0),muxin4(15 downto 8)); muxout4(0) <= genmux((muxsel2 & muxsel1 & muxsel0),muxin4(7 downto 0)); end process; ddrcomb : process(ddr_rst,sdi,request,frequest,start_tog_delta2,dr,wbrdata,muxout4,hwidth,reqsel,testen,testoen) constant plmemwrite: boolean := false; constant plmemread: boolean := false; variable dv: ddr_reg_type; variable o: ddrctrl_out_type; variable bdrive,qdrive: std_logic; variable vreq,vreqf: ddr_request_type; variable resp,resp2: ddr_response_type; variable vstart: std_logic; variable acsn: std_logic_vector(1 downto 0); variable arow: std_logic_vector(14 downto 0); variable acol: std_logic_vector(13 downto 0); variable abank: std_logic_vector(2 downto 0); variable aendaddr: std_logic_vector(l2blen-4 downto 2); variable aloa: std_logic_vector(l2ddrw-4 downto 0); variable rbw: std_logic; variable rbwd: std_logic_vector(rbuf_wdbits-1 downto 0); variable rbwa: std_logic_vector(rbuf_wabits-1 downto 0); variable wbra: std_logic_vector(wbuf_rabits-1 downto 0); variable regdata: std_logic_vector(31 downto 0); variable regsd1 : std_logic_vector(31 downto 0); -- data from registers variable regsd2 : std_logic_vector(31 downto 0); -- data from registers variable regsd3 : std_logic_vector(31 downto 0); -- data from registers variable regsd4 : std_logic_vector(31 downto 0); -- data from registers variable regsd5 : std_logic_vector(31 downto 0); -- data from registers variable mr : std_logic_vector(14 downto 0); -- DDR2 Mode register variable mask: std_logic_vector(15 downto 0); variable hio1: std_logic; variable w5: std_logic; variable precharge_next: std_logic; variable precharge_notras: std_logic; variable goto_caslat: std_logic; variable block_precharge: std_logic; variable regt0,regt1: std_logic_vector(ddrbits-1 downto 0); variable addrtemp3,addrtemp2,addrtemp1,addrtemp0: std_logic_vector(7 downto 0); variable expcsize: std_logic_vector(2 downto 0); variable caslat_reg: std_logic_vector(2 downto 0); variable addrlo32, endaddr32: std_logic_vector(3 downto 2); variable endaddr43: std_logic_vector(4 downto 3); variable endaddr42: std_logic_vector(4 downto 2); variable inc_rctr: std_logic; begin dv := dr; o := ddrctrl_out_none; o.sdcke := (others => dr.cfg.cke); o.sdcsn := dr.sdo_csn; o.sdwen := dr.wen_prev; o.rasn := dr.sdo_rasn and dr.rasn_pre; o.casn := dr.sdo_casn and dr.datacas; o.dqm := dr.dqm_prev; o.bdrive := dr.sdo_bdrive; o.qdrive := dr.sdo_qdrive; o.nbdrive := dr.sdo_nbdrive; o.address := dr.sdo_address; o.data := dr.sdo_data; o.ba := dr.sdo_ba; o.cal_en := dr.cfg.cal_en; o.cal_inc := dr.cfg.cal_inc; o.cal_pll := dr.cfg.cal_pll; o.cal_rst := dr.cfg.cal_rst; o.odt := (others => dr.sdo_odt); o.oct := dr.sdo_oct; o.cb := dr.sdo_cb; o.cbcal_en := dr.cfg.cbcal_en; o.cbcal_inc := dr.cfg.cbcal_inc; resp := ddr_response_none; resp2 := ddr_response_none; rbw := dr.rbwrite; rbwd := dr.rbwdata; rbwa := (others => '0'); w5 := '0'; wbra := dr.response.done_tog & dr.ramaddr; dv.ramaddr_prev := dr.ramaddr; dv.dqm_prev := dr.sdo_dqm; dv.wen_prev := dr.sdo_wen; dv.response_prev := dr.response; dv.sdo_address_prev := dr.sdo_address; dv.cfg.cal_en := (others => '0'); dv.cfg.cal_inc := (others => '0'); dv.cfg.cal_pll := (others => '0'); dv.cfg.cal_rst := '0'; dv.cfg.cbcal_en := (others => '0'); dv.cfg.cbcal_inc := (others => '0'); dv.sdo_data := (others => '0'); dv.sdo_data(2*ddrbits-1 downto ddrbits) := wbrdata(2*ddrbits+chkbits-1 downto ddrbits+chkbits); dv.sdo_data(ddrbits-1 downto 0) := wbrdata(ddrbits-1 downto 0); dv.sdo_cb := (others => '0'); if chkbits > 0 then dv.sdo_cb(2*chkbits-1 downto chkbits) := wbrdata(2*ddrbits+2*chkbits-1 downto 2*ddrbits+chkbits); dv.sdo_cb(chkbits-1 downto 0) := wbrdata(ddrbits+chkbits-1 downto ddrbits); end if; if hwidthen/=0 and dr.hwidth='1' and dr.hwctr='1' then dv.sdo_data(ddrbits-1 downto 0) := dr.sdo_data(2*ddrbits-1 downto ddrbits); if chkbits > 0 then dv.sdo_cb(chkbits-1 downto 0) := dr.sdo_cb(2*chkbits-1 downto chkbits); end if; end if; if not (hwidthen/=0 and hasdqvalid/=0 and sdi.datavalid='0') then dv.rbwdata(2*ddrbits+chkbits-1 downto ddrbits+chkbits) := sdi.data(2*ddrbits-1 downto ddrbits); dv.rbwdata(ddrbits-1 downto 0) := sdi.data(ddrbits-1 downto 0); if chkbits > 0 then dv.rbwdata(2*ddrbits+2*chkbits-1 downto 2*ddrbits+chkbits) := sdi.cb(2*chkbits-1 downto chkbits); dv.rbwdata(ddrbits+chkbits-1 downto ddrbits) := sdi.cb(chkbits-1 downto 0); end if; -- Half-width input data muxing if hwidthen/=0 and dr.hwidth='1' and dr.hwctr='1' then dv.rbwdata(2*ddrbits+chkbits-1 downto 2*ddrbits+chkbits-ddrbits/2) := dr.rbwdata(2*ddrbits+chkbits-ddrbits/2-1 downto ddrbits+chkbits); dv.rbwdata(2*ddrbits+chkbits-ddrbits/2-1 downto ddrbits+chkbits) := dr.rbwdata(ddrbits/2-1 downto 0); dv.rbwdata(ddrbits-1 downto ddrbits/2) := sdi.data(ddrbits+ddrbits/2-1 downto ddrbits); if chkbits > 0 then dv.rbwdata(2*ddrbits+2*chkbits-1 downto 2*ddrbits+2*chkbits-chkbits/2) := dr.rbwdata(2*ddrbits+2*chkbits-chkbits/2-1 downto 2*ddrbits+chkbits); dv.rbwdata(2*ddrbits+2*chkbits-chkbits/2-1 downto 2*ddrbits+chkbits) := dr.rbwdata(ddrbits+chkbits/2-1 downto ddrbits); dv.rbwdata(ddrbits+chkbits-1 downto ddrbits+chkbits/2) := sdi.cb(chkbits+chkbits/2-1 downto chkbits); end if; end if; end if; -- hwidth input should be constant but sample it for robustness -- then sample in one more stage to allow replication if necessary dv.hwidth1 := hwidth; dv.hwidth := dr.hwidth1; if hwidthen=0 then dv.hwidth:='0'; end if; -- Synchronize 1/2 stages dv.req1 := request; dv.req2 := dr.req1; dv.start1 := start_tog_delta2; dv.start2 := dr.start1; vstart := dr.start2; vreq := dr.req2; vreqf := dr.req1; if nosync /= 0 then vstart:=start_tog_delta2; vreq:=request; vreqf:=request; end if; if nosync > 1 then vreqf:=frequest; end if; dv.start_tog_prev := vstart; regsd1 := (others => '0'); regsd1(31 downto 15) := dr.cfg.refon & dr.cfg.ocd & dr.cfg.emr & dr.cfg.bsize(3) & dr.cfg.trcd(0) & dr.cfg.bsize(2 downto 0) & dr.cfg.csize & dr.cfg.command & dr.cfg.dllrst & dr.cfg.renable & dr.cfg.cke; regsd1(11 downto 0) := dr.cfg.refresh; regsd2 := (others => '0'); regsd2(25 downto 18) := std_logic_vector(to_unsigned(phytech,8)); if bigmem /= 0 then regsd2(17):='1'; end if; if chkbits > 0 then regsd2(16):='1'; end if; regsd2(15 downto 0) := "1" & std_logic_vector(to_unsigned(log2(ddrbits/8),3)) & std_logic_vector(to_unsigned(MHz,12)); if dr.hwidth='1' then regsd2(14 downto 12) := std_logic_vector(to_unsigned(log2((ddrbits/2)/8),3)); end if; regsd3 := (others => '0'); regsd3(17 downto 16) := dr.cfg.readdly(1 downto 0); regsd3(22 downto 18) := dr.cfg.trfc(4 downto 0); regsd3(27 downto 23) := dr.cfg.twr; regsd3(28) := dr.cfg.trp(0); regsd4 := (others => '0'); regsd4(23 downto 22) := dr.cfg.readdly(3 downto 2); regsd4(21) := dr.cfg.regmem; regsd4(13 downto 0) := dr.cfg.trtp & "00" & dr.cfg.caslat & dr.cfg.eightbanks & dr.cfg.dqsctrl; regsd5 := (others => '0'); regsd5(30 downto 28) := dr.cfg.trp; regsd5(25 downto 18) := dr.cfg.trfc; regsd5(17 downto 16) := dr.cfg.odten; regsd5(15) := dr.cfg.strength; regsd5(10 downto 8) := dr.cfg.trcd; regsd5(4 downto 0) := dr.cfg.tras; case ddrbits is when 16 => o.regwdata := dr.sdo_data(31 downto 0) & dr.sdo_data(31 downto 0); when 32 => o.regwdata := dr.sdo_data(31 downto 0) & dr.sdo_data(63 downto 32); when 64 => o.regwdata := dr.sdo_data(31 downto 0) & dr.sdo_data(63 downto 32); when others => o.regwdata := dr.sdo_data(2*ddrbits-7*32-1 downto 2*ddrbits-8*32) & dr.sdo_data(2*ddrbits-6*32-1 downto 2*ddrbits-7*32); end case; if dr.cfg.regmem='1' then caslat_reg := std_logic_vector(unsigned('0' & dr.cfg.caslat)+1); else caslat_reg := '0' & dr.cfg.caslat; end if; -- Mode register dv.mr_twr := std_logic_vector(unsigned(dr.cfg.twr(2 downto 0))-3); if dv.mr_twr="110" or dv.mr_twr="111" or dv.mr_twr="000" then dv.mr_twr := "101"; end if; dv.mr_tcl := std_logic_vector(unsigned('0' & dr.cfg.caslat)+3); mr := (others => '0'); mr(12) := '0'; -- Power down exit time mr(11 downto 9) := dr.mr_twr; -- WR-1 mr(8) := dr.cfg.dllrst; -- DLL Reset mr(7) := '0'; -- Test mode mr(6 downto 4) := dr.mr_tcl; -- CL mr(3) := '0'; -- Burst type, 0=seq 1=interl mr(2 downto 0) := "010"; -- Burst len 010=4, 011=8 -- Calculate address parts from a2ds.haddr and a2ds.startword expcsize := dr.hwidth & dr.cfg.csize; case expcsize is when "011" => arow := vreqf.startaddr(l2ddrw+22 downto l2ddrw+8); when "111" | "010" => arow := vreqf.startaddr(l2ddrw+21 downto l2ddrw+7); when "110" | "001" => arow := vreqf.startaddr(l2ddrw+20 downto l2ddrw+6); when "101" | "000" => arow := vreqf.startaddr(l2ddrw+19 downto l2ddrw+5); when others => arow := vreqf.startaddr(l2ddrw+18 downto l2ddrw+4); end case; dv.rowsel := dr.cfg.bsize(2 downto 0); if bigmem /= 0 and dr.cfg.bsize(3 downto 1)="000" then dv.rowsel := "010"; end if; if bigmem = 0 and dr.cfg.bsize(3)='1' then dv.rowsel := "111"; end if; addrtemp3 := vreqf.startaddr(30 downto 23); --CS addrtemp2 := vreqf.startaddr(29 downto 22); --BA2/1 addrtemp1 := vreqf.startaddr(28 downto 21); --BA1/0 addrtemp0 := vreqf.startaddr(27 downto 20); --BA0/- if bigmem=1 then addrtemp3(1 downto 0) := "0" & vreqf.startaddr(31); addrtemp2(1 downto 0) := vreqf.startaddr(31 downto 30); addrtemp1(1 downto 0) := vreqf.startaddr(30 downto 29); addrtemp0(1 downto 0) := vreqf.startaddr(29 downto 28); end if; muxin4 <= addrtemp3 & addrtemp2 & addrtemp1 & addrtemp0; abank := muxout4(2 downto 0); if dr.cfg.eightbanks='0' then abank := '0' & abank(2) & abank(1); end if; acol := vreqf.startaddr(log2(ddrbits/8)+13 downto log2(ddrbits/8)); if ddrbits=16 then acol(0):='0'; end if; -- Always align to at least 32 bits acsn(0) := muxout4(3); acsn(1) := not acsn(0); dv.setrow := '0'; if dr.setrow='1' then dv.row := dr.sdo_address_prev; end if; dv.samerow := '0'; if abank=dr.sdo_ba and acsn=dr.sdo_csn and arow=dr.row then dv.samerow := '1'; end if; dv.request_row := arow; dv.request_cs := acsn(0 downto 0); dv.request_bank := abank; hio1 := vreqf.hio; if raspipe /= 0 then vstart := dr.start_tog_prev; arow := dr.request_row; acsn := (not dr.request_cs) & dr.request_cs; abank := dr.request_bank; hio1 := vreq.hio; end if; aendaddr := vreq.endaddr(log2(4*burstlen)-1 downto 2); if vreq.hsize(1 downto 0)="11" and vreq.hio='0' then aendaddr(2):='1'; end if; if ahbdw > 64 and vreqf.hsize(2)='1' then aendaddr(3 downto 2) := "11"; if ahbdw > 128 and vreqf.hsize(0)='1' then aendaddr(4) := '1'; end if; end if; aloa(l2ddrw-4 downto 0) := vreq.startaddr(l2ddrw-4 downto 0); if ddrbits > 32 then addrlo32 := dr.addrlo(3 downto 2); elsif ddrbits > 16 then addrlo32 := '0' & dr.addrlo(2); else addrlo32 := "00"; end if; endaddr32 := dr.endaddr(3 downto 2); endaddr43 := dr.endaddr(4 downto 3); endaddr42 := dr.endaddr(4 downto 2); -- Calculate data mask mask := (others => dr.pastlast); -- Set mask bits for null; when 32 => if dr.addrlo(2)='1' then mask(7 downto 0) := mask(7 downto 0) or x"F0"; end if; when 64 => case addrlo32 is when "00" => null; when "01" => mask := mask or x"F000"; when "10" => mask := mask or x"FF00"; when others => mask := mask or x"FFF0"; end case; when others => null; end case; end if; -- Last access if dr.ramaddr = dr.endaddr(log2(4*burstlen)-1 downto log2(2*ddrbits/8)) then if hwidthen=0 or dr.hwidth='0' or dr.hwctr='1' then dv.pastlast := '1'; end if; case ddrbits is when 16 => null; when 32 => if dr.endaddr(2)='0' then mask(7 downto 0) := mask(7 downto 0) or x"0F"; end if; when 64 => case endaddr32 is when "00" => mask := mask or x"0FFF"; when "01" => mask := mask or x"00FF"; when "10" => mask := mask or x"000F"; when others => null; end case; when others => null; end case; end if; -- Before first if dr.col(1)='1' and dr.ctr(0)='1' and dr.ctr(dr.ctr'high downto 1)=zerov(dr.ctr'length-1) then mask := mask or x"FFFF"; end if; dv.sdo_rasn := '1'; dv.sdo_casn := '1'; dv.sdo_wen := '1'; dv.sdo_odt := '0'; dv.sdo_oct := '0'; dv.rbwrite := '0'; dv.ctr := std_logic_vector(unsigned(dr.ctr)+1); if hwidthen/=0 and dr.hwidth='1' and dr.s=dsdata then dv.hwctr := not dr.hwctr; if dr.hwctr='0' then dv.ctr := dr.ctr; end if; end if; dv.rastimer := std_logic_vector(unsigned(dr.rastimer)+1); if dr.rastimer=dr.cfg.tras then dv.tras_met := '1'; end if; -- Calculate whether we would precharge the next cycle if Tras=0 precharge_notras := '0'; if dr.casctr=zerov(dr.casctr'length) and dr.prectr="000000" and dr.pchpend='1' then precharge_notras := '1'; end if; -- Calculate whether we should precharge the next cycle precharge_next := precharge_notras and dr.tras_met; block_precharge := '0'; inc_rctr := '0'; goto_caslat := '0'; case dr.s is when dsidle => dv.ctr := (others => '0'); dv.hwctr := '0'; dv.sdo_bdrive := not oepols; dv.sdo_qdrive := not oepols; dv.sdo_nbdrive := not oepols; dv.col := acol; dv.sdo_csn := (others => '1'); dv.rastimer := (others => '0'); dv.tras_met := '0'; dv.response.rctr_gray := "0000"; if dr.refpend='1' and dr.cfg.refon='1' then -- Periodic refresh dv.sdo_csn := (others => '0'); dv.sdo_rasn := '0'; dv.sdo_casn := '0'; dv.refpend := '0'; dv.s := dsrefresh; elsif vstart /= dr.response.done_tog and (dr.cmds=dcon or (dr.cmds=dcoff and dr.cfg.renable='0')) then -- R/W data dv.sdo_rasn := '0' or hio1; dv.sdo_csn := acsn; dv.sdo_address := arow; dv.sdo_ba := abank; dv.s := dsrascas; elsif dr.cfg.command /= "000" then -- Command dv.sdo_csn := (others => '0'); if dr.cfg.command(2 downto 1)="11" then dv.sdo_wen:='0'; dv.sdo_casn:='0'; dv.sdo_rasn:='0'; dv.sdo_ba := "00" & dr.cfg.command(0); if dr.cfg.command(0)='0' or dr.cfg.emr="00" then dv.sdo_ba := "000"; dv.sdo_address := mr; else dv.sdo_ba := "0" & dr.cfg.emr; if dr.cfg.emr="01" then dv.sdo_address := "0000"&conv_std_logic(dqsse=1)&dr.cfg.ocd&dr.cfg.ocd&dr.cfg.ocd & dr.cfg.odten(1)&"000"& dr.cfg.odten(0) & dr.cfg.strength & "0"; else dv.sdo_address := (others => '0'); end if; end if; else dv.sdo_wen := dr.cfg.command(2); dv.sdo_casn := dr.cfg.command(1); dv.sdo_rasn := dr.cfg.command(0); dv.sdo_address(10) := '1'; -- print("X Command: " & tost(dr.cfg.command) & " -> casn:" & tost(dv.sdo_casn) & ",rasn:" & tost(dv.sdo_rasn) & ",wen:" & tost(dv.sdo_wen)); end if; dv.cfg.command := "000"; if dr.cfg.command=CMD_REF then dv.s := dsrefresh; end if; if dr.cfg.command=CMD_PRE then dv.s := dspreall; end if; end if; when dsrascas => if dr.ctr(2 downto 0)="000" then -- pragma translate_off assert dr.ctr="00000000" severity failure; -- pragma translate_on -- dv.row := dr.sdo_address; dv.setrow := '1'; end if; dv.hwrite := vreq.hwrite; dv.hsize := vreq.hsize; dv.endaddr := aendaddr; dv.addrlo := aloa; dv.sdo_address := dr.col(13 downto 10) & '0' & dr.col(9 downto 1) & '0'; if dr.hwidth='1' then dv.sdo_address := dr.col(12 downto 9) & '0' & dr.col(8 downto 1) & "00"; end if; if vreq.hio='1' and dr.ctr(0)='1' then dv.s := dsreg; dv.ctr := (others => '0'); dv.hwctr := '0'; elsif vreq.hio='0' and dr.ctr(2 downto 0)=dr.cfg.trcd then goto_caslat := '1'; end if; when dscaslat => dv.sdo_odt := dr.hwrite; dv.sdo_oct := not dr.hwrite; dv.pastlast := '0'; if (dis_caslat = 0 and dr.ctr(2 downto 0)=caslat_reg) or (dis_caslat /= 0 and dr.hwrite='0' and dr.ctr(2 downto 0)="000" ) or (dis_caslat /= 0 and dr.hwrite='1' and dr.ctr(2 downto 0)=std_logic_vector(unsigned(sdi.regrdata(2 downto 0)) -1)) then if dr.hwrite='1' then dv.s := dsdata; else dv.s := dsreaddly; end if; dv.ctr := (others => '0'); dv.hwctr := '0'; dv.sdo_qdrive := not (dr.hwrite xor oepols); dv.sdo_nbdrive := not (dr.hwrite xor oepols); end if; when dsreaddly => dv.sdo_odt := dr.hwrite; dv.sdo_oct := not dr.hwrite; dv.pastlast := '0'; if dr.ctr(3 downto 0)=dr.cfg.readdly then dv.s := dsdata; dv.ctr := (others => '0'); dv.hwctr := '0'; end if; when dsdata => inc_rctr := '0'; dv.sdo_odt := dr.hwrite; dv.sdo_oct := not dr.hwrite; dv.rbwrite := '1'; dv.sdo_dqm := mask; dv.sdo_bdrive := not (dr.hwrite xor oepols); dv.sdo_qdrive := not (dr.hwrite xor oepols); dv.sdo_nbdrive := not (dr.hwrite xor oepols); -- If-case to handle pausing for half-width mode if hwidthen=0 or dr.hwidth='0' or dr.hwctr='1' then inc_rctr := '1'; -- The first request may be on a 2-odd column to get the first data first -- Make sure following requests are on even mult of 4xcolumns if dr.ctr(0)='1' then dv.col(1) := '0'; end if; -- Make sure we don't advance read counter for the unwanted 3:rd/4:th -- word in the burst in this case if dr.ctr(0)='1' and dr.col(1)='1' then inc_rctr := '0'; end if; -- Toggle done and change state after completed burst if dr.ctr(log2(ddr_burstlen)-1 downto 0)=(not zerov(l2ddr_burstlen)) then dv.sdo_nbdrive := not oepols; dv.s := dsdone; dv.response.done_tog := not dr.response.done_tog; end if; end if; -- Stall if not ready yet if hasdqvalid/=0 and sdi.datavalid='0' and dr.hwrite='0' then dv.ctr := dr.ctr; dv.hwctr := dr.hwctr; dv.response := dr.response; dv.s := dsdata; dv.col(1) := dr.col(1); dv.rbwrite := '0'; inc_rctr := '0'; end if; if inc_rctr='1' and dr.hwrite='0' then dv.response.rctr_gray(l2ddr_burstlen-1 downto 0) := nextgray(dr.response.rctr_gray(l2ddr_burstlen-1 downto 0)); end if; when dsdone => dv.response.rctr_gray := "0000"; dv.sdo_bdrive := not oepols; if dr.ctr(0)='1' then dv.sdo_qdrive := not oepols; end if; if dr.pchpend='0' and dr.prectr=zerov(dr.prectr'length) then dv.s := dsidle; end if; -- Short circuit if request on same row and waiting for Tras to expire if precharge_notras='1' and precharge_next='0' and dr.start_tog_prev /= dr.response.done_tog and dr.samerow='1' and vreq.hio='0' then dv.col := acol; dv.endaddr := aendaddr; dv.addrlo := aloa; dv.hwrite := vreq.hwrite; dv.hsize := vreq.hsize; dv.s := dsagain; dv.sdo_qdrive := not oepols; end if; when dsagain => block_precharge := '1'; dv.sdo_address := dr.col(13 downto 10) & '0' & dr.col(9 downto 1) & '0'; goto_caslat := '1'; when dsreg => -- This code assumes ddrbits>=16, needs to be changed slightly to support -- smaller widths dv.rbwrite := '1'; -- DDR2CFG1-5,PHYCFG read regt0 := (others => '0'); regt1 := (others => '0'); case ddrbits is when 16 => case endaddr42 is when "000" => regt0 := regsd1(31 downto 16); regt1 := regsd1(15 downto 0); when "001" => regt0 := regsd2(31 downto 16); regt1 := regsd2(15 downto 0); when "010" => regt0 := regsd3(31 downto 16); regt1 := regsd3(15 downto 0); when "011" => regt0 := regsd4(31 downto 16); regt1 := regsd4(15 downto 0); when "100" | "101" => regt0 := regsd5(31 downto 16); regt1 := regsd5(15 downto 0); when "110" => regt0 := sdi.regrdata(31 downto 16); regt1 := sdi.regrdata(15 downto 0); when others => regt0 := sdi.regrdata(63 downto 48); regt1 := sdi.regrdata(47 downto 32); end case; when 32 => case endaddr43 is when "00" => regt0 := regsd1; regt1 := regsd2; when "01" => regt0 := regsd3; regt1 := regsd4; when "10" => regt0 := regsd5; regt1 := regsd2; when others => regt0 := sdi.regrdata(31 downto 0); regt1 := sdi.regrdata(63 downto 32); end case; when 64 => case dr.endaddr(4) is when '0' => regt0 := regsd1 & regsd2; regt1 := regsd3 & regsd4; when others => regt0 := regsd5 & regsd2; regt1 := sdi.regrdata(31 downto 0) & sdi.regrdata(63 downto 32); end case; when 128 => regt0 := regsd1 & regsd2 & regsd3 & regsd4; regt1 := regsd5 & regsd2 & sdi.regrdata(31 downto 0) & sdi.regrdata(63 downto 32); when others => regt0(ddrbits-1 downto ddrbits-255) := regsd1 & regsd2 & regsd3 & regsd4 & regsd5 & x"00000000" & sdi.regrdata(31 downto 0) & sdi.regrdata(63 downto 32); end case; dv.rbwdata(ddrbits*2+chkbits-1 downto ddrbits+chkbits) := regt0; dv.rbwdata(ddrbits-1 downto 0) := regt1; -- Note write data is two cycles behind regt0 := dr.sdo_data(ddrbits*2-1 downto ddrbits); regt1 := dr.sdo_data(ddrbits-1 downto 0); if dr.hwrite='1' and dr.ctr(2 downto 0)="010" then w5 := '0'; case ddrbits is when 16 => case endaddr42 is when "000" => regsd1 := regt0 & regt1; when "001" => regsd2 := regt0 & regt1; when "010" => regsd3 := regt0 & regt1; when "011" => regsd4 := regt0 & regt1; when "100" => regsd5 := regt0 & regt1; w5 := '1'; when "110" => o.regwrite(0) := '1'; when "111" => o.regwrite(1) := '1'; when others => null; end case; when 32 => case endaddr42 is when "000" => regsd1 := regt0; when "001" => regsd2 := regt1; when "010" => regsd3 := regt0; when "011" => regsd4 := regt1; when "100" => regsd5 := regt0; w5 := '1'; when "110" => o.regwrite(0) := '1'; when "111" => o.regwrite(1) := '1'; when others => null; end case; when 64 => case endaddr42 is when "000" => regsd1 := regt0(63 downto 32); when "001" => regsd2 := regt0(31 downto 0); when "010" => regsd3 := regt1(63 downto 32); when "011" => regsd4 := regt1(31 downto 0); when "100" => regsd5 := regt0(63 downto 32); w5 := '1'; when "110" => o.regwrite(0) := '1'; when "111" => o.regwrite(1) := '1'; when others => null; end case; when 128 => case endaddr42 is when "000" => regsd1 := regt0(127 downto 96); when "001" => regsd2 := regt0(95 downto 64); when "010" => regsd3 := regt0(63 downto 32); when "011" => regsd4 := regt0(31 downto 0); when "100" => regsd5 := regt1(127 downto 96); w5 := '1'; when "110" => o.regwrite(0) := '1'; when "111" => o.regwrite(1) := '1'; when others => null; end case; when others => case endaddr42 is when "000" => regsd1 := regt0(ddrbits-1 downto ddrbits-32); when "001" => regsd2 := regt0(ddrbits-33 downto ddrbits-64); when "010" => regsd3 := regt0(ddrbits-65 downto ddrbits-96); when "011" => regsd4 := regt0(ddrbits-97 downto ddrbits-128); when "100" => regsd5 := regt0(ddrbits-129 downto ddrbits-160); w5 := '1'; when "110" => o.regwrite(0) := '1'; when "111" => o.regwrite(1) := '1'; when others => null; end case; end case; -- Update lsb aliases for expanded fields in ddr2cfg5 if w5='1' then regsd3(28) := regsd5(28); -- TRP regsd3(22 downto 18) := regsd5(22 downto 18); -- TRFC regsd1(26) := regsd5(8); -- TRCD end if; end if; if (dr.hwrite='1' and dr.ctr(2 downto 1)="11") or dr.hwrite='0' then dv.s := dsidle; dv.response.done_tog := not dr.response.done_tog; end if; dv.cfg := (refon => regsd1(31), ocd => regsd1(30), emr => regsd1(29 downto 28), trcd => regsd5(10 downto 9) & regsd1(26), bsize => regsd1(27) & regsd1(25 downto 23), csize => regsd1(22 downto 21), command => regsd1(20 downto 18), dllrst => regsd1(17), renable => regsd1(16), cke => regsd1(15), refresh => regsd1(11 downto 0), cal_pll => regsd3(30 downto 29), cal_rst => regsd3(31), trp => regsd5(30 downto 29) & regsd3(28), twr => regsd3(27 downto 23), trfc => regsd5(25 downto 23) & regsd3(22 downto 18), readdly => regsd4(23 downto 22) & regsd3(17 downto 16), cal_inc => regsd3(15 downto 8), cal_en => regsd3(7 downto 0), eightbanks => regsd4(8), dqsctrl => regsd4(7 downto 0), caslat => regsd4(10 downto 9), odten => regsd5(17 downto 16), tras => regsd5(4 downto 0), strength => regsd5(15), trtp => regsd4(13), cbcal_inc => regsd4(31 downto 28), cbcal_en => regsd4(27 downto 24), regmem => regsd4(21) ); when dsrefresh => if dr.ctr(7 downto 0)=dr.cfg.trfc then dv.s := dsidle; end if; when dspreall => -- Wait for tRP (eightbanks=0) or tRP+1 (eightbanks=1) if dr.ctr(3 downto 0)=std_logic_vector(("0" & unsigned(dr.cfg.trp)) + (2+eightbanks)) then dv.s := dsidle; end if; end case; if goto_caslat='1' then dv.s := dscaslat; -- Set counter to -4 for read and -1 for write to compensate -- write-read diff and pipelining. -- Only need lowest three bits so set highest 3 to '0' as usual dv.ctr(5 downto 3) := "000"; dv.ctr(2 downto 0) := "100"; if vreq.hwrite='1' then dv.ctr(2 downto 0) := "111"; end if; dv.casctr := std_logic_vector(to_unsigned(ddr_burstlen/2, dv.casctr'length)); dv.hwcas := '0'; dv.pchpend := '1'; end if; -- CAS and precharge handling -- FSM above sets up casctr and pchpend if dis_caslat /= 0 then dv.twr_plus_cl := std_logic_vector(("0" & unsigned(dr.cfg.twr)) + ("000" & unsigned(sdi.regrdata(2 downto 0))) - 1); -- should be -2 instead of -1 but AFI might delay write data for an additional clock cycle, requiring an additional twr clock cycle else dv.twr_plus_cl := std_logic_vector(("0" & unsigned(dr.cfg.twr)) + ("0000" & unsigned(dr.cfg.caslat))); end if; if dr.prectr /= zerov(dr.prectr'length) then dv.prectr := std_logic_vector(unsigned(dr.prectr)-1); end if; dv.read_pend := '0' & dr.read_pend(dr.read_pend'high downto 1); dv.datacas := '1'; if dr.casctr /= zerov(dr.casctr'length) then if dr.datacas='1' then dv.datacas := '0'; -- dv.sdo_casn := '0'; dv.sdo_wen := not dr.hwrite; if dr.hwrite='0' then if dis_caslat /= 0 then dv.read_pend(4 downto 3) := "11"; else case dr.cfg.caslat is when "00" => dv.read_pend(4 downto 3) := "11"; when "01" => dv.read_pend(5 downto 4) := "11"; when "10" => dv.read_pend(6 downto 5) := "11"; when others => dv.read_pend(7 downto 6) := "11"; end case; end if; end if; elsif dr.hwidth='1' then dv.hwcas := not dr.hwcas; if dr.hwcas='1' then dv.casctr := std_logic_vector(unsigned(dr.casctr)-1); if l2blen-l2ddrw > 1 then dv.sdo_address(l2blen-l2ddrw+1 downto 3) := std_logic_vector(unsigned(dr.sdo_address(l2blen-l2ddrw+1 downto 3)+1)); end if; dv.sdo_address(2) := '0'; else dv.sdo_address(2) := not dr.sdo_address(2); end if; else dv.casctr := std_logic_vector(unsigned(dr.casctr)-1); if l2blen-l2ddrw > 1 then dv.sdo_address(l2blen-l2ddrw downto 2) := std_logic_vector(unsigned(dr.sdo_address(l2blen-l2ddrw downto 2)+1)); end if; dv.sdo_address(1) := '0'; end if; -- Set up precharge counter (will not run until casctr=0) if dr.hwrite='0' then dv.prectr := "00000" & dr.cfg.trtp; else dv.prectr := dr.twr_plus_cl; end if; end if; o.read_pend := dv.read_pend(7 downto 0); dv.rasn_pre := '1'; if precharge_next='1' and block_precharge='0' then dv.pchpend := '0'; dv.sdo_wen := '0'; -- dv.sdo_rasn := '0'; dv.rasn_pre := '0'; dv.prectr := "000" & dr.cfg.trp; end if; -- Refresh and init handling dv.refctr := std_logic_vector(unsigned(dr.refctr)+1); case dr.cmds is when dcrstdel => if dr.refctr=std_logic_vector(to_unsigned(MHz*rstdel, dr.refctr'length)) then dv.cmds := dcoff; end if; -- Bypass reset delay by writing anything to regsd2 if dr.start_tog_prev='1' and vreq.hio='1' and vreq.hwrite='1' and vreq.endaddr(4 downto 2)="001" then dv.cmds := dcoff; end if; when dcoff => -- Wait for renable to be set high and phy to be locked dv.refctr := (others => '0'); if dr.cfg.renable='1' then dv.cfg.cke := '1'; dv.cfg.dllrst := '1'; dv.cfg.ocd := '0'; dv.cmds := dcinit1; elsif dis_init /= 0 then dv.cmds := dcon; end if; when dcinit1 => -- Wait >=400 ns if dr.refctr=std_logic_vector(to_unsigned((MHz*4+9)/10, dr.refctr'length)) then dv.cmds := dcinit2; dv.cfg.command := CMD_PRE; dv.cfg.emr := "00"; end if; when dcinit2 => -- MR order 2,3,1,0 -- 2xcycles per command if dr.cfg.command="000" then dv.cfg.command := CMD_EMR; dv.cfg.emr := (not dr.cfg.emr(0)) & dr.cfg.emr(1); -- 00->10->11->01->00 if dr.cfg.emr="01" then dv.cmds := dcinit3; dv.refctr := (others => '0'); end if; end if; when dcinit3 => if dr.cfg.command="000" then dv.cfg.command := CMD_PRE; dv.cmds := dcinit4; end if; when dcinit4 => if dr.cfg.command="000" then dv.cfg.command := CMD_REF; dv.cmds := dcinit5; end if; when dcinit5 => if dr.cfg.command="000" then dv.cfg.command := CMD_REF; dv.cmds := dcinit6; end if; when dcinit6 => if dr.cfg.command="000" then dv.cfg.command := CMD_EMR; dv.cfg.emr := "00"; dv.cfg.dllrst := '0'; dv.cmds := dcinit7; dv.refctr := (others => '0'); end if; when dcinit7 => if dr.refctr(7 downto 0)=std_logic_vector(to_unsigned(200,8)) then dv.cfg.command := CMD_EMR; dv.cfg.emr := "01"; dv.cfg.ocd := '1'; dv.cmds := dcinit8; end if; when dcinit8 => if dr.cfg.command="000" then if dr.cfg.ocd='1' then dv.cfg.ocd := '0'; dv.cfg.command := CMD_EMR; else dv.cmds := dcon; dv.cfg.renable := '0'; end if; end if; dv.refctr := (others => '0'); when dcon => if dr.cfg.cke='0' then dv.cmds := dcoff; elsif dr.cfg.renable='1' then dv.cmds := dcinit2; dv.refctr := (others => '0'); elsif dr.refctr(11 downto 0)=dr.cfg.refresh then dv.refpend := '1'; dv.refctr := (others => '0'); end if; end case; if dis_init /= 0 then dv.cfg.renable := '0'; end if; -- Calculate next address dv.ramaddr(0) := dv.ctr(0) xor dv.col(1); if rbuf_wabits > 1 then dv.ramaddr(rbuf_wabits-1 downto 1) := std_logic_vector(unsigned(dr.col(rbuf_wabits downto 2)) + unsigned(dv.ctr(rbuf_wabits-1 downto 1))); end if; -- print("col: " & tost(dr.col) & ", dv.ctr: " & tost(dv.ctr) & ", res: " & tost(dv.ramaddr)); if eightbanks=0 then dv.cfg.eightbanks:='0'; end if; rbwd := dv.rbwdata; rbwa := dr.ramaddr; rbw := dv.rbwrite; if plmemwrite then rbwd := dr.rbwdata; rbwa := dr.ramaddr_prev; rbw := dr.rbwrite; end if; if not plmemread then o.dqm := dr.sdo_dqm; o.sdwen := dr.sdo_wen; o.data := dv.sdo_data; o.cb := dv.sdo_cb; end if; -- half-width output data muxing, placed after (potential) pipeline regs. if hwidthen/=0 and dr.hwidth='1' then if dr.hwctr='1' then o.data(ddrbits/2-1 downto 0) := o.data(2*ddrbits-ddrbits/2-1 downto ddrbits); o.data(2*ddrbits-ddrbits/2-1 downto ddrbits) := o.data(2*ddrbits-1 downto 2*ddrbits-ddrbits/2); if chkbits > 0 then o.cb(chkbits/2-1 downto 0) := o.cb(2*chkbits-chkbits/2-1 downto chkbits); o.cb(2*chkbits-chkbits/2-1 downto chkbits) := o.cb(2*chkbits-1 downto 2*chkbits-chkbits/2); end if; o.dqm(ddrbits/16-1 downto 0) := o.dqm(ddrbits/4-ddrbits/16-1 downto ddrbits/8); o.dqm(ddrbits/4-ddrbits/16-1 downto ddrbits/8) := o.dqm(ddrbits/4-1 downto ddrbits/4-ddrbits/16); else o.data(2*ddrbits-ddrbits/2-1 downto ddrbits) := o.data(ddrbits-1 downto ddrbits/2); if chkbits > 0 then o.cb(2*chkbits-chkbits/2-1 downto chkbits) := o.cb(chkbits-1 downto chkbits/2); end if; o.dqm(ddrbits/4-ddrbits/16-1 downto ddrbits/8) := o.dqm(ddrbits/8-1 downto ddrbits/16); end if; end if; if ddr_rst='0' then dv.s := dsidle; dv.cmds := dcrstdel; dv.response := ddr_response_none; dv.casctr := (others => '0'); dv.refctr := (others => '0'); dv.pchpend := '0'; dv.refpend := '0'; dv.rbwrite := '0'; dv.ctr := (others => '0'); dv.hwctr := '0'; dv.sdo_nbdrive := not oepols; dv.sdo_csn := (others => '1'); dv.rastimer := (others => '0'); dv.tras_met := '0'; dv.cfg.command := "000"; dv.cfg.emr := "00"; dv.cfg.csize := conv_std_logic_vector(col-9, 2); dv.cfg.bsize := conv_std_logic_vector(log2(Mbyte/8), 4); dv.cfg.refon := '0'; dv.cfg.trfc := conv_std_logic_vector(TRFC*MHz/1000-2, 8); dv.cfg.refresh := conv_std_logic_vector(7800*MHz/1000, 12); dv.cfg.twr := conv_std_logic_vector((15 * MHz + 999) / 1000 + 3, 5); dv.sdo_dqm := (others => '1'); dv.cfg.dllrst := '0'; dv.cfg.cke := std_logic(to_unsigned(cke_rst, 1)(0)); dv.cfg.ocd := '0'; dv.cfg.readdly := conv_std_logic_vector(readdly, 4); dv.cfg.eightbanks := conv_std_logic_vector(eightbanks, 1)(0); dv.cfg.odten := std_logic_vector(to_unsigned(odten,2)); dv.cfg.dqsctrl := (others => '0'); dv.cfg.strength := '0'; if pwron = 1 and dis_init = 0 then dv.cfg.renable := '1'; else dv.cfg.renable:='0'; end if; -- Default to min 15 ns tRCD, 15 ns tRP, min(7.5 ns,2*tCK) tRTP -- Use CL=3 for DDR2-400/533, 4 for DDR2-667, 5 for DDR2-800 dv.cfg.trcd := "000"; dv.cfg.trp := "000"; dv.cfg.trtp := '0'; dv.cfg.caslat := "00"; dv.cfg.regmem := '0'; if MHz > 130 then dv.cfg.trcd := "001"; dv.cfg.trp := "001"; end if; if MHz > 200 then -- Will work up to 600 MHz, then trcd/trp needs to be expanded dv.cfg.trcd := std_logic_vector(to_unsigned((15 * MHz + 999) / 1000 - 2, 3)); dv.cfg.trp := std_logic_vector(to_unsigned((15 * MHz + 999) / 1000 - 2, 3)); end if; if MHz > 267 then -- Works up to 400 MHz, then trtp will need to be expanded dv.cfg.trtp := '1'; dv.cfg.caslat := "01"; end if; if MHz > 334 then dv.cfg.caslat := "10"; end if; dv.cfg.cal_rst := '1'; -- Reset input delays dv.sdo_ba := (others => '0'); dv.sdo_address := (others => '0'); -- Default to min 45 ns tRAS dv.cfg.tras := std_logic_vector(to_unsigned((45*MHz+999)/1000 - 2, 5)); dv.read_pend := (others => '0'); if ddr_syncrst /= 0 then dv.sdo_bdrive := not oepols; dv.sdo_qdrive := not oepols; dv.sdo_odt := '0'; if phyptctrl /= 0 then o.sdcke := "00"; o.bdrive := not oepols; o.qdrive := not oepols; o.odt := (others => '0'); end if; end if; end if; if dr.cfg.odten="00" then dv.sdo_odt := '0'; end if; if octen=0 then dv.sdo_oct := '0'; end if; for x in 0 to chkbits/4-1 loop o.cbdqm(x) := o.dqm(x*ddrbits/chkbits); end loop; if vreq.maskdata='1' then o.dqm := (others => '1'); end if; if vreq.maskcb='1' then o.cbdqm := (others => '1'); end if; if dr.cfg.command /= "000" then -- print("Command: " & tost(dr.cfg.command) & " -> casn:" & tost(dv.sdo_casn) & ",rasn:" & tost(dv.sdo_rasn) & ",wen:" & tost(dv.sdo_wen)); end if; -- Dynamic nosync handling (nosync=2) if plmemwrite then dv.response1 := dr.response; dv.response2 := dr.response; else dv.response1 := dv.response; dv.response2 := dv.response; end if; if reqsel='1' then dv.response1 := ddr_response_none; end if; if reqsel='0' then dv.response2 := ddr_response_none; end if; if nosync > 1 then resp := dr.response1; elsif plmemwrite then resp := dr.response_prev; else resp := dr.response; end if; resp2 := dr.response2; if scantest/=0 and phyptctrl/=0 then if testen='1' then o.bdrive := testoen; o.qdrive := testoen; end if; end if; rbwdata <= rbwd; rbwaddr <= rbwa; rbwrite <= rbw; wbraddr <= wbra; sdo <= o; response <= resp; response2 <= resp2; ndr <= dv; end process; ddrregs: process(clk_ddr,arst) begin if rising_edge(clk_ddr) then dr <= ndr; end if; if ddr_syncrst=0 and arst='0' then dr.cfg.cke <= std_logic(to_unsigned(cke_rst, 1)(0)); dr.sdo_bdrive <= not oepols; dr.sdo_qdrive <= not oepols; dr.sdo_odt <= '0'; end if; end process; end;