mirror of
https://github.com/lcbcFoo/ReonV.git
synced 2025-04-25 05:57:06 -04:00
1147 lines
40 KiB
VHDL
1147 lines
40 KiB
VHDL
------------------------------------------------------------------------------
|
|
-- 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: ddr1spax_ddr
|
|
-- File: ddr1spax_ddr.vhd
|
|
-- Author: Magnus Hjorth - Aeroflex Gaisler
|
|
-- Description: Merged 16/32/64-bit DDR/mobile-DDR backend
|
|
-- Based on ddrsp*a and ddr2spax_ddr
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- Added features from the original ddrspa:
|
|
-- * Separated AHB,DDR parts of controller like for DDR2SPA
|
|
-- * 64/32/16 bit interfaces in the same entity
|
|
-- * Checkbit support for use with ft_ddr2spax_ahb front-end.
|
|
-- * Extended timing fields plus tRAS setting to meet DDR400 timing.
|
|
-- * Configurable burst length
|
|
-- * Support for PHY:s with read data valid signaling and extra latency
|
|
-- Incompatibility/differences to the original ddrspa:
|
|
-- * The mobile DDR had an undocumented feature that tRFC was extended with 8
|
|
-- cycles if the TRP bit was set. This is replaced by the extended
|
|
-- timing fields.
|
|
-- * ddrsp16a used a separate read-clock supplied only from the Spartan PHY.
|
|
-- * Reads/writes are made as multiple length-2 burst commands.
|
|
|
|
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 ddr1spax_ddr is
|
|
generic (
|
|
ddrbits : integer := 32;
|
|
burstlen : integer := 8;
|
|
MHz : integer := 100;
|
|
col : integer := 9;
|
|
Mbyte : integer := 8;
|
|
pwron : integer := 0;
|
|
oepol : integer := 0;
|
|
mobile : integer := 0;
|
|
confapi : integer := 0;
|
|
conf0 : integer := 0;
|
|
conf1 : integer := 0;
|
|
nosync : integer := 0;
|
|
ddr_syncrst: integer range 0 to 1 := 0;
|
|
chkbits : integer := 0;
|
|
hasdqvalid : integer := 0;
|
|
readdly : integer := 0;
|
|
regoutput : integer := 1;
|
|
ddr400 : integer := 1;
|
|
rstdel : integer := 200;
|
|
phyptctrl : integer := 0;
|
|
scantest : 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;
|
|
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 ddr1spax_ddr;
|
|
|
|
architecture rtl of ddr1spax_ddr is
|
|
|
|
constant l2blen: integer := log2(burstlen)+log2(32);
|
|
constant l2ddrw: integer := log2(ddrbits*2);
|
|
constant l2ddr_burstlen: integer := l2blen-l2ddrw;
|
|
|
|
-- 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);
|
|
|
|
type ddrstate is (dsidle,dsact1,dsact2,dsact3,dswr1,dswr2,dswr3,dswr4,dswr5,dswr6,
|
|
dsrd1,dsrd2,dsrd3,dsrd4,dsreg1,dsreg2,dscmd1,dscmd2,dspdown1,dspdown2,dsref1,
|
|
dssrr1,dssrr2);
|
|
type ddrinitstate is (disrstdel,disidle,disrun,disfinished);
|
|
|
|
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(4 downto 0);
|
|
trp : std_logic_vector(1 downto 0); -- 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; -- Mobile SD support, Mobile SD enabled
|
|
txsr : std_logic_vector(5 downto 0); -- Exit Self Refresh timing
|
|
txp : std_logic_vector(1 downto 0); -- 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
|
|
tras : std_logic_vector(1 downto 0); -- tRAS minimum (6-9 cycles)
|
|
twr : std_logic; -- tWR write recovery, 2/3 cycles
|
|
end record;
|
|
|
|
type ddr_reg_type is record
|
|
s : ddrstate;
|
|
initstate : ddrinitstate;
|
|
cfg : sdram_cfg_type;
|
|
resp,resp2 : ddr_response_type;
|
|
req1,req2 : ddr_request_type;
|
|
start1,start2 : std_logic;
|
|
start3 : std_logic;
|
|
ramaddr : std_logic_vector(rbuf_wabits-1 downto 0);
|
|
readpipe : std_logic_vector(4+readdly downto 0);
|
|
initpos : std_logic_vector(2 downto 0);
|
|
cmdctr : std_logic_vector(7 downto 0);
|
|
readdone : std_logic;
|
|
refctr : std_logic_vector(17 downto 0);
|
|
refpend : std_logic;
|
|
idlectr : std_logic_vector(3 downto 0);
|
|
pdowns : std_logic_vector(1 downto 0);
|
|
sdo_casn : std_logic;
|
|
sdo_rasn : std_logic;
|
|
sdo_wen : std_logic;
|
|
sdo_csn : std_logic_vector(1 downto 0);
|
|
sdo_ba : std_logic_vector(1 downto 0);
|
|
sdo_address : std_logic_vector(14 downto 0);
|
|
sdo_data : std_logic_vector(2*ddrbits-1 downto 0);
|
|
sdo_dqm : std_logic_vector(ddrbits/4-1 downto 0);
|
|
sdo_cb : std_logic_vector(2*chkbits downto 0);
|
|
sdo_ck : std_logic_vector(2 downto 0);
|
|
sdo_bdrive : std_logic;
|
|
sdo_qdrive : std_logic;
|
|
end record;
|
|
|
|
signal dr,ndr: ddr_reg_type;
|
|
|
|
constant onev: std_logic_vector(15 downto 0) := x"FFFF";
|
|
constant zerov: std_logic_vector(15 downto 0) := x"0000";
|
|
|
|
signal arst : std_ulogic;
|
|
begin
|
|
|
|
arst <= testrst when (scantest/=0 and ddr_syncrst=0) and testen='1' else ddr_rst;
|
|
|
|
ddrcomb: process(ddr_rst,sdi,request,frequest,start_tog,dr,wbrdata,testen,testoen,reqsel)
|
|
|
|
variable dv: ddr_reg_type;
|
|
variable o: ddrctrl_out_type;
|
|
variable rbw: std_logic;
|
|
variable rbwd: std_logic_vector(2*(ddrbits+chkbits)-1 downto 0);
|
|
|
|
variable vstart, vstartd, vdone, incdone: std_logic;
|
|
variable vrctr: std_logic_vector(3 downto 0);
|
|
variable vreq,vreqf: ddr_request_type;
|
|
variable regsd1 : std_logic_vector(31 downto 0);
|
|
variable regsd2 : std_logic_vector(31 downto 0);
|
|
variable regsd3 : std_logic_vector(31 downto 0);
|
|
variable lastreadcmd: std_logic;
|
|
variable lastwrite : std_logic;
|
|
variable vmaskfirst, vmasklast: std_logic_vector(ddrbits/4-1 downto 0);
|
|
variable ea: std_logic_vector(3 downto 2);
|
|
variable inc_sdoaddr, inc_ramaddr: std_logic;
|
|
variable datavalid: std_logic;
|
|
variable vcsf: std_logic_vector(1 downto 0);
|
|
variable vrowf: std_logic_vector(14 downto 0);
|
|
variable vbankf: std_logic_vector(1 downto 0);
|
|
variable vcol,vcoladdr: std_logic_vector(14 downto 1);
|
|
variable seqin,seqout: std_logic_vector(3 downto 0);
|
|
variable regrdata: std_logic_vector(2*ddrbits-1 downto 0);
|
|
variable regad: std_logic_vector(2 downto 0);
|
|
variable wrdreg1,wrdreg2,wrdreg3: std_logic_vector(31 downto 0);
|
|
variable reqselv: std_logic_vector(3 downto 0);
|
|
begin
|
|
---------------------------------------------------------------------------
|
|
-- Init vars
|
|
---------------------------------------------------------------------------
|
|
dv := dr;
|
|
o := ddrctrl_out_none;
|
|
o.bdrive := '1'; o.qdrive := '1';
|
|
vdone := dr.resp.done_tog or dr.resp2.done_tog;
|
|
vrctr := dr.resp.rctr_gray or dr.resp2.rctr_gray;
|
|
|
|
incdone := '0';
|
|
lastreadcmd := '0';
|
|
lastwrite := '0';
|
|
reqselv := reqsel & reqsel & reqsel & reqsel;
|
|
|
|
-- Config registers
|
|
regsd1 := (others => '0');
|
|
regsd1(31 downto 15) := dr.cfg.refon & dr.cfg.trp(0) & dr.cfg.trfc(2 downto 0) &
|
|
dr.cfg.trcd & dr.cfg.bsize & 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(8 downto 0) := conv_std_logic_vector(MHz, 9);
|
|
regsd2(14 downto 12) := conv_std_logic_vector(log2(ddrbits/8),3);
|
|
if mobile/=0 then regsd2(15):='1'; end if;-- Mobile DDR support
|
|
regsd2(19 downto 16) := conv_std_logic_vector(confapi, 4);
|
|
regsd3 := (others => '0');
|
|
regsd3(31) := dr.cfg.mobileen; -- Mobile DDR enable
|
|
regsd3(30) := dr.cfg.cl;
|
|
regsd3(24 downto 19) := dr.cfg.tcke & dr.cfg.txsr(3 downto 0) & dr.cfg.txp(0);
|
|
regsd3(18 downto 16) := dr.cfg.pmode;
|
|
regsd3( 7 downto 0) := dr.cfg.ds(2 downto 0) & dr.cfg.tcsr(1 downto 0)
|
|
& dr.cfg.pasr(2 downto 0);
|
|
-- Extended timing fields for DDR400
|
|
if ddr400 /= 0 then
|
|
regsd2(20) := '1'; -- Ext. fields available
|
|
regsd3(29 downto 28) := dr.cfg.tras;
|
|
regsd3(27 downto 26) := dr.cfg.txsr(5 downto 4);
|
|
regsd3(25) := dr.cfg.txp(1);
|
|
regsd3(11) := dr.cfg.twr;
|
|
regsd3(10) := dr.cfg.trp(1);
|
|
regsd3(9 downto 8) := dr.cfg.trfc(4 downto 3);
|
|
end if;
|
|
|
|
-- Data path
|
|
rbw := '0';
|
|
rbwd := (others => '0');
|
|
rbwd(ddrbits-1 downto 0) := sdi.data(ddrbits-1 downto 0);
|
|
rbwd(2*ddrbits+chkbits-1 downto ddrbits+chkbits) :=
|
|
sdi.data(2*ddrbits-1 downto ddrbits);
|
|
if chkbits > 0 then
|
|
rbwd(ddrbits+chkbits-1 downto ddrbits) := sdi.cb(chkbits-1 downto 0);
|
|
rbwd(2*(ddrbits+chkbits)-1 downto 2*ddrbits+chkbits) :=
|
|
sdi.cb(2*chkbits-1 downto chkbits);
|
|
end if;
|
|
dv.sdo_data(ddrbits-1 downto 0) := wbrdata(ddrbits-1 downto 0);
|
|
dv.sdo_data(2*ddrbits-1 downto ddrbits) :=
|
|
wbrdata(2*ddrbits+chkbits-1 downto ddrbits+chkbits);
|
|
dv.sdo_cb(chkbits) := '0'; -- dummy bit just to ensure length>0
|
|
if chkbits > 0 then
|
|
dv.sdo_cb(chkbits-1 downto 0) := wbrdata(ddrbits+chkbits-1 downto ddrbits);
|
|
dv.sdo_cb(2*chkbits-1 downto chkbits) :=
|
|
wbrdata(2*(ddrbits+chkbits)-1 downto 2*ddrbits+chkbits);
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------
|
|
-- Request handling logic
|
|
---------------------------------------------------------------------------
|
|
|
|
-- Sync request inputs
|
|
dv.req1 := request;
|
|
dv.req2 := dr.req1;
|
|
dv.start1 := start_tog;
|
|
dv.start2 := dr.start1;
|
|
dv.start3 := dr.start2;
|
|
vstart := dr.start2;
|
|
vstartd := dr.start3;
|
|
vreq := dr.req2;
|
|
vreqf := dr.req1;
|
|
if nosync/=0 then
|
|
vstart:=start_tog;
|
|
vstartd:=start_tog;
|
|
vreq:=request;
|
|
vreqf:=request;
|
|
end if;
|
|
if nosync > 1 then
|
|
vreqf := frequest;
|
|
end if;
|
|
|
|
-- Address muxing
|
|
vcsf(0) := genmux(dr.cfg.bsize, vreqf.startaddr(30 downto 23));
|
|
vcsf(1) := not vcsf(0);
|
|
vbankf := genmux(dr.cfg.bsize, vreqf.startaddr(29 downto 22)) &
|
|
genmux(dr.cfg.bsize, vreqf.startaddr(28 downto 21));
|
|
case dr.cfg.csize is
|
|
when "00" => vrowf := vreqf.startaddr(19+l2ddrw downto 5+l2ddrw);
|
|
when "01" => vrowf := vreqf.startaddr(20+l2ddrw downto 6+l2ddrw);
|
|
when "10" => vrowf := vreqf.startaddr(21+l2ddrw downto 7+l2ddrw);
|
|
when others => vrowf := vreqf.startaddr(22+l2ddrw downto 8+l2ddrw);
|
|
end case;
|
|
vcol := vreq.startaddr(l2ddrw+10 downto l2ddrw-3);
|
|
-- vcoladdr==vcol when dr.ramaddr==lsb of vcol
|
|
vcoladdr := vcol(14 downto rbuf_wabits+1) & dr.ramaddr;
|
|
|
|
-- Generate data mask
|
|
-- Mask for 32-bit and larger bursts and single access
|
|
vmaskfirst := (others => '0');
|
|
vmasklast := (others => '0');
|
|
ea := vreq.endaddr(3 downto 2);
|
|
if vreq.hsize(1 downto 0)="11" then ea(2):='1'; end if;
|
|
if vreq.hsize(2)='1' then ea(3 downto 2):="11"; end if;
|
|
case ddrbits is
|
|
when 64 =>
|
|
-- 64-bit DDR width
|
|
case vreq.startaddr(3 downto 2) is
|
|
when "11" => vmaskfirst := "1111111111110000";
|
|
when "10" => vmaskfirst := "1111111100000000";
|
|
when "01" => vmaskfirst := "1111000000000000";
|
|
when others => vmaskfirst := "0000000000000000";
|
|
end case;
|
|
case ea(3 downto 2) is
|
|
when "11" => vmasklast := "0000000000000000";
|
|
when "10" => vmasklast := "0000000000001111";
|
|
when "01" => vmasklast := "0000000011111111";
|
|
when others => vmasklast := "0000111111111111";
|
|
end case;
|
|
if vreq.hsize(2 downto 1)="00" then
|
|
if vreq.startaddr(1)='1' then
|
|
vmaskfirst := vmaskfirst or "1100110011001100";
|
|
else
|
|
vmaskfirst := vmaskfirst or "0011001100110011";
|
|
end if;
|
|
end if;
|
|
if vreq.hsize="000" then
|
|
if vreq.startaddr(0)='1' then
|
|
vmaskfirst := vmaskfirst or "1010101010101010";
|
|
else
|
|
vmaskfirst := vmaskfirst or "0101010101010101";
|
|
end if;
|
|
end if;
|
|
when 32 =>
|
|
-- 32-bit DDR width
|
|
case vreq.startaddr(2) is
|
|
when '1' => vmaskfirst := "11110000";
|
|
when others => vmaskfirst := "00000000";
|
|
end case;
|
|
case ea(2) is
|
|
when '1' => vmasklast := "00000000";
|
|
when others => vmasklast := "00001111";
|
|
end case;
|
|
if vreq.hsize(2 downto 1)="00" then
|
|
if vreq.startaddr(1)='1' then
|
|
vmaskfirst := vmaskfirst or "11001100";
|
|
else
|
|
vmaskfirst := vmaskfirst or "00110011";
|
|
end if;
|
|
end if;
|
|
if vreq.hsize="000" then
|
|
if vreq.startaddr(0)='1' then
|
|
vmaskfirst := vmaskfirst or "10101010";
|
|
else
|
|
vmaskfirst := vmaskfirst or "01010101";
|
|
end if;
|
|
end if;
|
|
|
|
when others =>
|
|
-- 16-bit DDR width
|
|
if vreq.hsize(2 downto 1)="00" then
|
|
if vreq.startaddr(1)='1' then
|
|
vmaskfirst := vmaskfirst or "1100";
|
|
else
|
|
vmaskfirst := vmaskfirst or "0011";
|
|
end if;
|
|
end if;
|
|
if vreq.hsize="000" then
|
|
if vreq.startaddr(0)='1' then
|
|
vmaskfirst := vmaskfirst or "1010";
|
|
else
|
|
vmaskfirst := vmaskfirst or "0101";
|
|
end if;
|
|
end if;
|
|
end case;
|
|
|
|
-- Register read/write data muxing
|
|
regrdata := (others => '0');
|
|
case ddrbits is
|
|
when 64 =>
|
|
regad := vreq.startaddr(4 downto 2);
|
|
regrdata := regsd1 & regsd2 & regsd3 & x"00000000";
|
|
if confapi /= 0 and regad(2)='1' then
|
|
regrdata(95 downto 32) := dr.cfg.conf(31 downto 0) & dr.cfg.conf(63 downto 32);
|
|
end if;
|
|
wrdreg1 := wbrdata(128+chkbits-1 downto 96+chkbits);
|
|
wrdreg2 := wbrdata(96+chkbits-1 downto 64+chkbits);
|
|
wrdreg3 := wbrdata(63 downto 32);
|
|
when 32 =>
|
|
regad := dr.ramaddr(1 downto 0) & vreq.startaddr(2);
|
|
if regad(1)='0' then
|
|
regrdata := regsd1 & regsd2;
|
|
if confapi /= 0 and regad(2)='1' then
|
|
regrdata := regsd1 & dr.cfg.conf(31 downto 0);
|
|
end if;
|
|
else
|
|
regrdata := regsd3 & regsd2;
|
|
if confapi /= 0 and regad(2)='1' then
|
|
regrdata := dr.cfg.conf(63 downto 0);
|
|
end if;
|
|
end if;
|
|
wrdreg1 := wbrdata(64+chkbits-1 downto 32+chkbits);
|
|
wrdreg2 := wbrdata(31 downto 0);
|
|
wrdreg3 := wbrdata(64+chkbits-1 downto 32+chkbits);
|
|
when others =>
|
|
regad := dr.ramaddr(2 downto 0);
|
|
case regad is
|
|
when "000"|"100" => regrdata := regsd1;
|
|
when "001" => regrdata := regsd2;
|
|
when "010" => regrdata := regsd3;
|
|
when "101" =>
|
|
if confapi /= 0 then
|
|
regrdata := dr.cfg.conf(31 downto 0);
|
|
else
|
|
regrdata := regsd2;
|
|
end if;
|
|
when "110" =>
|
|
if confapi /= 0 then
|
|
regrdata := dr.cfg.conf(63 downto 32);
|
|
else
|
|
regrdata := regsd3;
|
|
end if;
|
|
when others => regrdata := regsd3;
|
|
end case;
|
|
wrdreg1 := wbrdata(31+chkbits downto 16+chkbits) & wbrdata(15 downto 0);
|
|
wrdreg2 := wbrdata(31+chkbits downto 16+chkbits) & wbrdata(15 downto 0);
|
|
wrdreg3 := wbrdata(31+chkbits downto 16+chkbits) & wbrdata(15 downto 0);
|
|
end case;
|
|
|
|
---------------------------------------------------------------------------
|
|
-- Main DDR-SDRAM access FSM
|
|
---------------------------------------------------------------------------
|
|
|
|
dv.sdo_ck := "111";
|
|
dv.sdo_rasn := '1';
|
|
dv.sdo_casn := '1';
|
|
dv.sdo_wen := '1';
|
|
dv.sdo_dqm := (others => '1');
|
|
dv.sdo_bdrive := '1';
|
|
dv.sdo_qdrive := '1';
|
|
|
|
inc_sdoaddr := '0';
|
|
inc_ramaddr := '0';
|
|
|
|
dv.readpipe := dr.readpipe(3+readdly downto 0) & '0';
|
|
|
|
datavalid := '0';
|
|
if hasdqvalid/=0 then
|
|
datavalid := sdi.datavalid;
|
|
if dr.s/=dsrd1 and dr.s/=dsrd2 and dr.s/=dsrd3 and dr.s/=dsrd4 and dr.s/=dssrr2 then
|
|
datavalid := '0';
|
|
end if;
|
|
end if;
|
|
if hasdqvalid=0 then
|
|
if dr.cfg.cl='0' then
|
|
datavalid := dr.readpipe(3+readdly);
|
|
else
|
|
datavalid := dr.readpipe(4+readdly);
|
|
end if;
|
|
end if;
|
|
|
|
if datavalid='1' and dr.s/=dsidle then
|
|
inc_ramaddr := '1';
|
|
rbw := '1';
|
|
vrctr(l2ddr_burstlen-1 downto 0) :=
|
|
nextgray(vrctr(l2ddr_burstlen-1 downto 0));
|
|
if dr.ramaddr=onev(dr.ramaddr'length-1 downto 0) then
|
|
dv.readdone := '1';
|
|
incdone:='1';
|
|
vrctr := "0000";
|
|
end if;
|
|
end if;
|
|
|
|
if dr.sdo_address((l2blen-l2ddrw) downto 1)=onev((l2blen-l2ddrw) downto 1) then
|
|
lastreadcmd := '1';
|
|
end if;
|
|
|
|
if dr.ramaddr=vreq.endaddr((l2blen-3)-1 downto (l2ddrw-3)) then
|
|
lastwrite := '1';
|
|
end if;
|
|
|
|
-- Update EMR when ds, tcsr or pasr change
|
|
if dr.cfg.command="000" and
|
|
( dr.cfg.ds(2 downto 0) /= dr.cfg.ds(5 downto 3) or
|
|
dr.cfg.tcsr(1 downto 0) /= dr.cfg.tcsr(3 downto 2) or
|
|
dr.cfg.pasr(2 downto 0) /= dr.cfg.pasr(5 downto 3) ) then
|
|
dv.cfg.command := "111";
|
|
end if;
|
|
|
|
-- Auto-refresh counter
|
|
dv.refctr := std_logic_vector(unsigned(dr.refctr)+1);
|
|
if (dr.refctr(11 downto 0)=dr.cfg.refresh and dr.cfg.refon='1') then
|
|
dv.refpend := '1';
|
|
dv.refctr := (others => '0');
|
|
end if;
|
|
if dr.initstate/=disrstdel and (dr.cfg.refon='0' or dr.cfg.pmode(1)='1') then
|
|
dv.refpend := '0';
|
|
dv.refctr := (others => '0');
|
|
end if;
|
|
|
|
dv.idlectr := "0000";
|
|
dv.pdowns(0) := '0';
|
|
|
|
if not (dr.cmdctr=(dr.cmdctr'range => '0')) and dr.pdowns(0)='0' then
|
|
dv.cmdctr := std_logic_vector(unsigned(dr.cmdctr)-1);
|
|
end if;
|
|
|
|
case dr.s is
|
|
when dsidle =>
|
|
vrctr := "0000";
|
|
dv.sdo_ck := "111";
|
|
if dr.cfg.pmode /= "000" then
|
|
dv.idlectr := std_logic_vector(unsigned(dr.idlectr)+1);
|
|
end if;
|
|
dv.sdo_csn := "11";
|
|
if dr.refpend='1' then
|
|
dv.sdo_csn := "00";
|
|
dv.sdo_rasn := '0';
|
|
dv.sdo_casn := '0';
|
|
dv.s := dsref1;
|
|
dv.refpend := '0';
|
|
elsif vstart /= vdone and dr.cfg.renable='0' then
|
|
-- Transfer
|
|
dv.sdo_csn := vcsf;
|
|
dv.sdo_address := vrowf;
|
|
dv.sdo_ba := vbankf;
|
|
dv.sdo_rasn := '0' or vreqf.hio;
|
|
dv.s := dsact1;
|
|
elsif dr.cfg.command /= "000" then
|
|
dv.s := dscmd1;
|
|
elsif dr.idlectr="1111" then
|
|
dv.s := dspdown1;
|
|
end if;
|
|
|
|
when dsact1 =>
|
|
dv.ramaddr := vcol(rbuf_wabits downto 1);
|
|
if ddr400 /= 0 then
|
|
dv.cmdctr(2 downto 0) := "1" & dr.cfg.tras; -- t(RAS)-2t(CK) = TRAS+6-2 = TRAS+4
|
|
else
|
|
dv.cmdctr(2 downto 0) := "10" & dr.cfg.trcd;
|
|
end if;
|
|
dv.readdone := '0';
|
|
if dr.cfg.trcd='1' then
|
|
dv.s := dsact2;
|
|
else
|
|
dv.s := dsact3;
|
|
end if;
|
|
if vreq.hio='1' then
|
|
dv.s := dsreg1;
|
|
end if;
|
|
|
|
when dsact2 =>
|
|
dv.s := dsact3;
|
|
|
|
when dsact3 =>
|
|
dv.sdo_casn := '0';
|
|
dv.sdo_wen := not vreq.hwrite;
|
|
dv.sdo_qdrive := not vreq.hwrite;
|
|
-- dv.sdo_address := vcol(12 downto 10) & '0' & vcol(9 downto 1) & '0';
|
|
-- Since part of column is stored in ramaddr in dsact1, use that to
|
|
-- reduce fanout on vreq.startaddr
|
|
dv.sdo_address := vcoladdr(13 downto 10) & '0' & vcoladdr(9 downto 1) & '0';
|
|
if vreq.hwrite='1' then
|
|
dv.s := dswr1;
|
|
else
|
|
dv.s := dsrd1;
|
|
dv.readpipe(0) := '1';
|
|
end if;
|
|
|
|
when dswr1 =>
|
|
-- NOP,NOP,[WR]: issue either WR+D or NOP+D
|
|
dv.sdo_bdrive := '0';
|
|
dv.sdo_qdrive := '0';
|
|
inc_sdoaddr := '1';
|
|
inc_ramaddr := '1';
|
|
if lastwrite='1' then
|
|
dv.sdo_dqm := vmaskfirst or vmasklast;
|
|
dv.s := dswr3;
|
|
else
|
|
dv.sdo_casn := '0';
|
|
dv.sdo_wen := '0';
|
|
dv.sdo_dqm := vmaskfirst;
|
|
dv.s := dswr2;
|
|
end if;
|
|
|
|
when dswr2 =>
|
|
dv.sdo_dqm := (others => '0');
|
|
dv.sdo_bdrive := '0';
|
|
dv.sdo_qdrive := '0';
|
|
inc_sdoaddr := '1';
|
|
inc_ramaddr := '1';
|
|
if lastwrite='0' then
|
|
dv.sdo_casn := '0';
|
|
dv.sdo_wen := '0';
|
|
else
|
|
dv.s := dswr3;
|
|
dv.sdo_dqm := vmasklast;
|
|
end if;
|
|
|
|
when dswr3 =>
|
|
-- ...,WR+D,WR+D,[NOP+D]: issue NOP
|
|
dv.sdo_qdrive := '0';
|
|
dv.sdo_dqm := (others => '1');
|
|
dv.s := dswr4;
|
|
incdone := '1';
|
|
|
|
when dswr4 =>
|
|
-- Issue more NOP:s to meet tWR
|
|
dv.idlectr := std_logic_vector(unsigned(dr.idlectr)+1);
|
|
if dr.idlectr(0)=dr.cfg.twr then
|
|
dv.s := dswr5;
|
|
end if;
|
|
|
|
when dswr5 =>
|
|
-- Issue NOP:s until tRAS met.
|
|
if dr.cmdctr(2 downto 0)="000" then
|
|
dv.sdo_rasn := '0';
|
|
dv.sdo_wen := '0';
|
|
dv.s := dswr6;
|
|
end if;
|
|
|
|
when dswr6 =>
|
|
-- PRE: issue one or two NOP:s depending on trp setting
|
|
if dr.idlectr(1 downto 0)=dr.cfg.trp then
|
|
dv.s := dsidle;
|
|
else
|
|
dv.idlectr := std_logic_vector(unsigned(dr.idlectr)+1);
|
|
end if;
|
|
|
|
when dsrd1 =>
|
|
inc_sdoaddr := '1';
|
|
if lastreadcmd='0' then
|
|
dv.sdo_casn := '0';
|
|
dv.readpipe(0):='1';
|
|
elsif dr.cmdctr(2 downto 0)="000" then
|
|
dv.sdo_rasn := '0';
|
|
dv.sdo_wen := '0';
|
|
dv.s := dsrd3;
|
|
else
|
|
dv.s := dsrd2;
|
|
end if;
|
|
|
|
when dsrd2 =>
|
|
if dr.cmdctr(2 downto 0)="000" then
|
|
dv.sdo_rasn := '0';
|
|
dv.sdo_wen := '0';
|
|
dv.s := dsrd3;
|
|
end if;
|
|
|
|
when dsrd3 =>
|
|
if dr.idlectr(1 downto 0)=dr.cfg.trp then
|
|
if dv.readdone='1' then
|
|
dv.s := dsidle;
|
|
else
|
|
dv.s := dsrd4;
|
|
end if;
|
|
else
|
|
dv.idlectr := std_logic_vector(unsigned(dr.idlectr)+1);
|
|
end if;
|
|
|
|
when dsrd4 =>
|
|
if dv.readdone='1' then
|
|
dv.s := dsidle;
|
|
end if;
|
|
|
|
when dsreg1 =>
|
|
rbw := '1';
|
|
rbwd(2*ddrbits+chkbits-1 downto ddrbits+chkbits) := regrdata(2*ddrbits-1 downto ddrbits);
|
|
rbwd(ddrbits-1 downto 0) := regrdata(ddrbits-1 downto 0);
|
|
if vreq.hwrite='1' then
|
|
dv.s := dsreg2;
|
|
elsif regad="100" and dr.cfg.mobileen='1' then
|
|
dv.sdo_address := (others => '0');
|
|
dv.sdo_ba := "01";
|
|
dv.sdo_csn := "10";
|
|
dv.sdo_rasn := '0';
|
|
dv.sdo_casn := '0';
|
|
dv.sdo_wen := '0';
|
|
dv.s := dssrr1;
|
|
dv.cmdctr(0) := '1';
|
|
null;
|
|
else
|
|
incdone := '1';
|
|
dv.s := dsidle;
|
|
end if;
|
|
|
|
when dsreg2 =>
|
|
case regad is
|
|
when "000" =>
|
|
dv.cfg.refon := wrdreg1(31);
|
|
dv.cfg.trp(0) := wrdreg1(30);
|
|
dv.cfg.trfc(2 downto 0) := wrdreg1(29 downto 27);
|
|
dv.cfg.trcd := wrdreg1(26);
|
|
dv.cfg.bsize := wrdreg1(25 downto 23);
|
|
dv.cfg.csize := wrdreg1(22 downto 21);
|
|
dv.cfg.command := wrdreg1(20 downto 18);
|
|
dv.cfg.dllrst := wrdreg1(17);
|
|
dv.cfg.renable := wrdreg1(16);
|
|
dv.cfg.cke := wrdreg1(15);
|
|
dv.cfg.refresh := wrdreg1(11 downto 0);
|
|
when "010" =>
|
|
dv.cfg.mobileen := wrdreg3(31);
|
|
dv.cfg.cl := wrdreg3(30);
|
|
dv.cfg.tcke := wrdreg3(24);
|
|
dv.cfg.txsr(3 downto 0) := wrdreg3(23 downto 20);
|
|
dv.cfg.txp(0) := wrdreg3(19);
|
|
dv.cfg.pmode := wrdreg3(18 downto 16);
|
|
dv.cfg.ds (5 downto 3) := wrdreg3(7 downto 5);
|
|
dv.cfg.tcsr(3 downto 2) := wrdreg3(4 downto 3);
|
|
dv.cfg.pasr(5 downto 3) := wrdreg3(2 downto 0);
|
|
-- Extended DDR400 fields
|
|
dv.cfg.tras := wrdreg3(29 downto 28);
|
|
dv.cfg.txsr(5 downto 4) := wrdreg3(27 downto 26);
|
|
dv.cfg.txp(1) := wrdreg3(25);
|
|
dv.cfg.twr := wrdreg3(11);
|
|
dv.cfg.trp(1) := wrdreg3(10);
|
|
dv.cfg.trfc(4 downto 3) := wrdreg3(9 downto 8);
|
|
when "101" =>
|
|
if confapi /= 0 then
|
|
dv.cfg.conf(31 downto 0) := wrdreg2;
|
|
end if;
|
|
when "110" =>
|
|
if confapi /= 0 then
|
|
dv.cfg.conf(63 downto 32) := wrdreg3;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
incdone := '1';
|
|
dv.s := dsidle;
|
|
|
|
|
|
when dscmd1 =>
|
|
dv.sdo_csn := (others => '0');
|
|
dv.sdo_address(10) := '1';
|
|
dv.cfg.command := "000";
|
|
dv.s := dscmd2;
|
|
case dr.cfg.command is
|
|
when "010" => -- PRECHARGE ALL
|
|
dv.sdo_rasn := '0';
|
|
dv.sdo_wen := '0';
|
|
dv.cmdctr(1 downto 0) := "11";
|
|
when "100" => -- AUTO-REFRESH
|
|
dv.sdo_rasn := '0';
|
|
dv.sdo_casn := '0';
|
|
dv.cmdctr(4 downto 0) := dr.cfg.trfc;
|
|
when "110" => -- MODE REGISTER
|
|
dv.sdo_rasn := '0';
|
|
dv.sdo_casn := '0';
|
|
dv.sdo_wen := '0';
|
|
dv.sdo_ba := "00";
|
|
dv.sdo_address := "00000000" & "01" & dr.cfg.cl & "0001";
|
|
if dr.cfg.mobileen='0' then
|
|
dv.sdo_address(8) := dr.cfg.dllrst;
|
|
end if;
|
|
if dr.cfg.dllrst='1' then
|
|
dv.cmdctr := std_logic_vector(to_unsigned(200,dr.cmdctr'length));
|
|
end if;
|
|
when "111" => -- EXT. MODE REGISTER
|
|
dv.sdo_rasn := '0';
|
|
dv.sdo_casn := '0';
|
|
dv.sdo_wen := '0';
|
|
if dr.cfg.mobileen='1' then
|
|
dv.sdo_ba := "10";
|
|
dv.sdo_address := "0000000" & dr.cfg.ds(5 downto 3) & dr.cfg.tcsr(3 downto 2)
|
|
& dr.cfg.pasr(5 downto 3);
|
|
else
|
|
dv.sdo_ba := "01";
|
|
dv.sdo_address := "000000000000000"; -- bit0=0 -> DLL enable
|
|
end if;
|
|
dv.cfg.pasr(2 downto 0) := dr.cfg.pasr(5 downto 3);
|
|
dv.cfg.ds(2 downto 0) := dr.cfg.ds(5 downto 3);
|
|
dv.cfg.tcsr(1 downto 0) := dr.cfg.tcsr(3 downto 2);
|
|
|
|
when others => null;
|
|
|
|
end case;
|
|
|
|
when dscmd2 =>
|
|
if dr.cmdctr=(dr.cmdctr'range => '0') then
|
|
dv.s := dsidle;
|
|
end if;
|
|
|
|
when dspdown1 =>
|
|
dv.sdo_csn := "00";
|
|
if dr.cfg.pmode(0)='1' or dr.cfg.pmode(1)='1' then
|
|
dv.cfg.cke := '0';
|
|
end if;
|
|
if dr.cfg.pmode(1)='1' then
|
|
dv.sdo_rasn := '0';
|
|
dv.sdo_casn := '0';
|
|
end if;
|
|
if dr.cfg.pmode(2)='1' and dr.cfg.pmode(0)='1' then
|
|
dv.sdo_wen := '0';
|
|
end if;
|
|
if dr.cfg.pmode(0)='1' then
|
|
dv.cmdctr(1 downto 0) := dr.cfg.txp;
|
|
end if;
|
|
if dr.cfg.pmode(1)='1' then
|
|
if dr.cfg.mobileen='1' then
|
|
dv.cmdctr(5 downto 0) := dr.cfg.txsr;
|
|
else
|
|
dv.cmdctr(7 downto 0) := std_logic_vector(to_unsigned(200,8));
|
|
end if;
|
|
end if;
|
|
dv.pdowns(1) := '0';
|
|
dv.s := dspdown2;
|
|
|
|
when dspdown2 =>
|
|
dv.pdowns(0) := '1';
|
|
if dr.pdowns(0)='0' and dr.cmdctr=(dr.cmdctr'range => '0') then
|
|
dv.pdowns(1):='1';
|
|
end if;
|
|
if dr.cfg.pmode(2)='1' and dr.cfg.pmode(0)='0' then
|
|
dv.sdo_ck := "000";
|
|
end if;
|
|
if dr.cfg.pmode(1)='1' then
|
|
dv.refpend := '1';
|
|
end if;
|
|
if (dr.refpend='1' and dr.cfg.pmode(1)='0') or vstart /= vdone then
|
|
if (dr.pdowns(0) or not dr.cfg.tcke)='1' then
|
|
dv.cfg.cke := '1';
|
|
if dr.pdowns(1)='1' then
|
|
dv.s := dsidle;
|
|
else
|
|
dv.s := dscmd2;
|
|
dv.pdowns(0) := '0';
|
|
end if;
|
|
end if;
|
|
end if;
|
|
|
|
when dsref1 =>
|
|
dv.s := dscmd2;
|
|
dv.cmdctr(4 downto 0) := dr.cfg.trfc;
|
|
|
|
when dssrr1 =>
|
|
if dr.cmdctr(0)='0' then
|
|
dv.sdo_casn := '0';
|
|
dv.readpipe(0):='1';
|
|
dv.s := dssrr2;
|
|
end if;
|
|
|
|
when dssrr2 =>
|
|
if datavalid='1' then
|
|
incdone := '1';
|
|
dv.s := dsidle;
|
|
end if;
|
|
|
|
end case;
|
|
|
|
if inc_sdoaddr='1' then
|
|
dv.sdo_address(l2blen-l2ddrw downto 1) :=
|
|
std_logic_vector(unsigned(dr.sdo_address(l2blen-l2ddrw downto 1))+1);
|
|
end if;
|
|
if inc_ramaddr='1' then
|
|
dv.ramaddr := std_logic_vector(unsigned(dr.ramaddr)+1);
|
|
end if;
|
|
|
|
-- Update the done flags
|
|
dv.resp.done_tog := (dr.resp.done_tog xor incdone) and (not reqsel);
|
|
dv.resp.rctr_gray := vrctr and (not reqselv);
|
|
dv.resp2.done_tog := (dr.resp2.done_tog xor incdone) and reqsel;
|
|
dv.resp2.rctr_gray := vrctr and reqselv;
|
|
|
|
---------------------------------------------------------------------------
|
|
-- DDR Init Sequence FSM
|
|
---------------------------------------------------------------------------
|
|
|
|
-- Command sequence lookup table
|
|
seqin := dr.cfg.mobileen & dr.initpos;
|
|
case seqin is
|
|
-- Mobile DDR
|
|
when "1100" => seqout := "0010"; -- PRECHARGE ALL
|
|
when "1011" => seqout := "0100"; -- AUTO REFRESH #1
|
|
when "1010" => seqout := "0100"; -- AUTO REFRESH #2
|
|
when "1001" => seqout := "0110"; -- MODE REG
|
|
when "1000" => seqout := "0111"; -- EXT MODE REG
|
|
-- Normal DDR
|
|
when "0110" => seqout := "0010"; -- PRECHARGE ALL
|
|
when "0101" => seqout := "0111"; -- EXT MODE REG En DLL
|
|
when "0100" => seqout := "1110"; -- MODE REG Rst DLL
|
|
when "0011" => seqout := "0010"; -- PRECHARGE ALL
|
|
when "0010" => seqout := "0100"; -- AUTO REFRESH #1
|
|
when "0001" => seqout := "0100"; -- AUTO REFRESH #2
|
|
when "0000" => seqout := "0110"; -- MODE REG NoRst DLL
|
|
when others => seqout := "0000";
|
|
end case;
|
|
|
|
case dr.initstate is
|
|
|
|
when disrstdel =>
|
|
if dr.refctr=std_logic_vector(to_unsigned(MHz*rstdel,dr.refctr'length)) then
|
|
dv.initstate := disidle;
|
|
if pwron=0 then dv.cfg.renable:='0'; end if;
|
|
end if;
|
|
-- Bypass reset delay by writing anything to regsd2
|
|
if vstartd='1' and (vreq.hio='1' and vreq.hwrite='1' and vreq.endaddr(4 downto 2)="001") then
|
|
dv.initstate := disidle;
|
|
if pwron=0 then dv.cfg.renable:='0'; end if;
|
|
end if;
|
|
|
|
when disidle =>
|
|
if dr.cfg.renable='1' then
|
|
dv.cfg.cke := '1';
|
|
if dr.cfg.cke='1' then
|
|
dv.initpos := "111";
|
|
dv.initstate := disrun;
|
|
end if;
|
|
end if;
|
|
|
|
when disrun =>
|
|
if dr.cfg.command="000" then
|
|
dv.cfg.dllrst := seqout(3);
|
|
dv.cfg.command := seqout(2 downto 0);
|
|
dv.initpos := std_logic_vector(unsigned(dr.initpos)-1);
|
|
if dr.initpos="000" then
|
|
dv.initstate := disfinished;
|
|
end if;
|
|
end if;
|
|
|
|
when disfinished =>
|
|
if dr.cfg.command="000" then
|
|
dv.cfg.renable := '0';
|
|
dv.cfg.refon := '1';
|
|
dv.initstate := disidle;
|
|
end if;
|
|
end case;
|
|
|
|
---------------------------------------------------------------------------
|
|
-- Reset
|
|
---------------------------------------------------------------------------
|
|
if ddr_rst='0' then
|
|
dv.s := dsidle;
|
|
dv.cmdctr := (others => '0');
|
|
dv.refctr := (others => '0');
|
|
dv.resp := ddr_response_none;
|
|
dv.resp2 := ddr_response_none;
|
|
dv.initstate := disrstdel;
|
|
dv.refpend := '0';
|
|
-- Reset cfg record
|
|
dv.cfg.command := "000";
|
|
dv.cfg.csize := conv_std_logic_vector(col-9, 2);
|
|
dv.cfg.bsize := conv_std_logic_vector(log2(Mbyte/8), 3);
|
|
dv.cfg.refon := '0';
|
|
dv.cfg.refresh := conv_std_logic_vector(7800*MHz/1000, 12);
|
|
dv.cfg.dllrst := '0';
|
|
dv.cfg.pasr := (others => '0');
|
|
dv.cfg.tcsr := (others => '0');
|
|
dv.cfg.ds := (others => '0');
|
|
dv.cfg.pmode := (others => '0');
|
|
dv.cfg.txsr := conv_std_logic_vector(120*MHz/1000, 6);
|
|
dv.cfg.txp := "01";
|
|
dv.cfg.cl := '0'; -- CL = 3/2 -- ****
|
|
dv.cfg.tcke := '1';
|
|
if MHz > 100 then
|
|
dv.cfg.trcd := '1';
|
|
else dv.cfg.trcd := '0';
|
|
end if;
|
|
if MHz > 100 then
|
|
dv.cfg.trp := "01";
|
|
else dv.cfg.trp := "00";
|
|
end if;
|
|
dv.cfg.renable := '1'; -- Updated in disrstdel state
|
|
if mobile >= 2 then
|
|
dv.cfg.mobileen := '1'; -- Default: Mobile DDR
|
|
else dv.cfg.mobileen := '0';
|
|
end if;
|
|
if mobile >= 2 then
|
|
dv.cfg.trfc := conv_std_logic_vector(98*MHz/1000-2, 5);
|
|
else dv.cfg.trfc := conv_std_logic_vector(75*MHz/1000-2, 5);
|
|
end if;
|
|
if ddr_syncrst /= 0 then
|
|
dv.sdo_ck := "000";
|
|
if mobile >= 2 then
|
|
dv.cfg.cke := '1';
|
|
else dv.cfg.cke := '0';
|
|
end if;
|
|
end if;
|
|
if confapi /= 0 then
|
|
dv.cfg.conf(31 downto 0) := conv_std_logic_vector(conf0, 32); --x"0000A0A0";
|
|
dv.cfg.conf(63 downto 32) := conv_std_logic_vector(conf1, 32); --x"00060606";
|
|
else
|
|
dv.cfg.conf := (others => '0');
|
|
end if;
|
|
if MHz > 175 then
|
|
dv.cfg.tras := "10";
|
|
elsif MHz > 150 then
|
|
dv.cfg.tras := "01";
|
|
else
|
|
dv.cfg.tras := "00";
|
|
end if;
|
|
if MHz > 133 then
|
|
dv.cfg.twr := '1';
|
|
else
|
|
dv.cfg.twr := '0';
|
|
end if;
|
|
|
|
dv.sdo_csn := "11";
|
|
dv.sdo_dqm := (others => '1');
|
|
dv.sdo_wen := '1';
|
|
dv.sdo_rasn := '1';
|
|
dv.sdo_casn := '1';
|
|
|
|
-- Extra reset for X-sensitive techs
|
|
dv.ramaddr := (others => '0');
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------
|
|
-- Static logic/forced regs, etc
|
|
---------------------------------------------------------------------------
|
|
|
|
-- Force mobile disable/enabled
|
|
if mobile=0 then dv.cfg.mobileen := '0'; end if;
|
|
if mobile=3 then dv.cfg.mobileen := '1'; end if;
|
|
if mobile=0 then
|
|
dv.cfg.pasr := (others => '0');
|
|
dv.cfg.tcsr := (others => '0');
|
|
dv.cfg.ds := (others => '0');
|
|
dv.cfg.pmode := (others => '0');
|
|
dv.cfg.txp := "00";
|
|
dv.cfg.txsr := (others => '0');
|
|
dv.cfg.tcke := '0';
|
|
end if;
|
|
|
|
if ddr400=0 then
|
|
dv.cfg.tras := "00";
|
|
dv.cfg.txsr(5 downto 4) := "00";
|
|
dv.cfg.txp(1) := '0';
|
|
dv.cfg.trp(1) := '0';
|
|
dv.cfg.trfc(4 downto 3) := "00";
|
|
dv.cfg.twr := '0';
|
|
end if;
|
|
|
|
-- Assign sdo
|
|
o.bdrive := '1'; o.qdrive := '1'; --Temp.
|
|
o.sdck := dr.sdo_ck;
|
|
if ddr_syncrst/=0 and phyptctrl/=0 then
|
|
o.sdck := o.sdck and (o.sdck'range => ddr_rst);
|
|
end if;
|
|
|
|
if regoutput /= 0 then
|
|
o.casn := dr.sdo_casn;
|
|
o.rasn := dr.sdo_rasn;
|
|
o.sdwen := dr.sdo_wen;
|
|
o.sdcsn := dr.sdo_csn;
|
|
o.ba := '0' & dr.sdo_ba;
|
|
o.address := dr.sdo_address;
|
|
o.sdcke := (others => dr.cfg.cke);
|
|
if ddr_syncrst /= 0 and phyptctrl /= 0 then
|
|
if ddr_rst='0' then
|
|
if mobile >= 2 then o.sdcke := (others => '1');
|
|
else o.sdcke := (others => '0');
|
|
end if;
|
|
end if;
|
|
end if;
|
|
o.data(2*ddrbits-1 downto 0) := dr.sdo_data;
|
|
o.dqm(ddrbits/4-1 downto 0) := dr.sdo_dqm;
|
|
if chkbits > 0 then
|
|
o.cb(2*chkbits-1 downto 0) := dr.sdo_cb(2*chkbits-1 downto 0);
|
|
end if;
|
|
o.bdrive := dr.sdo_bdrive;
|
|
o.qdrive := dr.sdo_qdrive;
|
|
else
|
|
o.casn := dv.sdo_casn;
|
|
o.rasn := dv.sdo_rasn;
|
|
o.sdwen := dv.sdo_wen;
|
|
o.sdcsn := dv.sdo_csn;
|
|
o.ba := '0' & dv.sdo_ba;
|
|
o.address := dv.sdo_address;
|
|
o.sdcke := (others => dv.cfg.cke);
|
|
o.data(2*ddrbits-1 downto 0) := dv.sdo_data;
|
|
o.dqm(ddrbits/4-1 downto 0) := dv.sdo_dqm;
|
|
if chkbits > 0 then
|
|
o.cb(2*chkbits-1 downto 0) := dv.sdo_cb(2*chkbits-1 downto 0);
|
|
end if;
|
|
o.bdrive := dv.sdo_bdrive;
|
|
o.qdrive := dv.sdo_qdrive;
|
|
end if;
|
|
for x in 7 downto 0 loop
|
|
o.cbdqm(x) := o.dqm(2*x);
|
|
end loop;
|
|
|
|
-- Diag access
|
|
if vreq.maskcb='1' then
|
|
o.cbdqm := (others => '1');
|
|
end if;
|
|
if vreq.maskdata='1' then
|
|
o.dqm := (others => '1');
|
|
end if;
|
|
|
|
if scantest/=0 and phyptctrl/=0 then
|
|
if testen='1' then
|
|
o.bdrive := testoen;
|
|
o.qdrive := testoen;
|
|
end if;
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------
|
|
-- Drive outputs
|
|
---------------------------------------------------------------------------
|
|
ndr <= dv;
|
|
sdo <= o;
|
|
response <= dr.resp;
|
|
response2 <= dr.resp2;
|
|
rbwrite <= rbw;
|
|
rbwaddr <= dr.ramaddr;
|
|
rbwdata <= rbwd;
|
|
wbraddr <= vdone & dv.ramaddr;
|
|
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.sdo_ck <= "000";
|
|
if mobile >= 2 then
|
|
dr.cfg.cke <= '1';
|
|
else dr.cfg.cke <= '0';
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
end;
|
|
|