------------------------------------------------------------------------------
--  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 - 2019, 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: 	ddr_phy
-- File:	ddr_phy.vhd
-- Author:	Jiri Gaisler, Gaisler Research
-- Description:	Wrapper entities for techmap ddrphy/ddr2phy
------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;

library grlib;
use grlib.stdlib.all;
library techmap;
use techmap.gencomp.all;
library gaisler;
use gaisler.ddrpkg.all;

------------------------------------------------------------------
-- DDR1 PHY wrapper -------------------------------------------------------
------------------------------------------------------------------

entity ddrphy_wrap is
  generic (tech : integer := virtex2; MHz : integer := 100; 
	rstdelay : integer := 200; dbits : integer := 16; 
	clk_mul : integer := 2 ; clk_div : integer := 2;
	rskew : integer :=0; mobile : integer := 0;
        scantest : integer := 0; phyiconf : integer := 0);
  port (
    rst       : in  std_ulogic;
    clk       : in  std_logic;          	-- input clock
    clkout    : out std_ulogic;			-- system clock
    clkoutret : in  std_ulogic;
    clkread   : out std_ulogic;			-- read clock
    lock      : out std_ulogic;			-- DCM locked

    ddr_clk 	: out std_logic_vector(2 downto 0);
    ddr_clkb	: out std_logic_vector(2 downto 0);
    ddr_clk_fb_out  : out std_logic;
    ddr_clk_fb  : in std_logic;
    ddr_cke  	: out std_logic_vector(1 downto 0);
    ddr_csb  	: out std_logic_vector(1 downto 0);
    ddr_web  	: out std_ulogic;                       -- ddr write enable
    ddr_rasb  	: out std_ulogic;                       -- ddr ras
    ddr_casb  	: out std_ulogic;                       -- ddr cas
    ddr_dm   	: out std_logic_vector (dbits/8-1 downto 0);    -- ddr dm
    ddr_dqs  	: inout std_logic_vector (dbits/8-1 downto 0);    -- ddr dqs
    ddr_ad      : out std_logic_vector (13 downto 0);   -- ddr address
    ddr_ba      : out std_logic_vector (1 downto 0);    -- ddr bank address
    ddr_dq    	: inout  std_logic_vector (dbits-1 downto 0); -- ddr data
 
    sdi         : out ddrctrl_in_type;
    sdo         : in  ddrctrl_out_type;
    
    testen      : in std_ulogic;
    testrst     : in std_ulogic;
    scanen      : in std_ulogic;
    testoen     : in std_ulogic);
end;

architecture rtl of ddrphy_wrap is

begin

    ddr_phy0 : ddrphy 
     generic map (tech => tech, MHz => MHz, rstdelay => rstdelay
-- reduce 200 us start-up delay during simulation
-- pragma translate_off
	/ 200
-- pragma translate_on
	, dbits => dbits, clk_mul => clk_mul, clk_div => clk_div, 
	rskew => rskew, mobile => mobile, scantest => scantest,
	phyiconf => phyiconf)
     port map (
	rst, clk, clkout, clkoutret, clkread, lock,
	ddr_clk, ddr_clkb, ddr_clk_fb_out, ddr_clk_fb,
	ddr_cke, ddr_csb, ddr_web, ddr_rasb, ddr_casb, 
	ddr_dm, ddr_dqs, ddr_ad, ddr_ba, ddr_dq,
	sdo.address(13 downto 0), sdo.ba(1 downto 0),
	sdi.data(dbits*2-1 downto 0), sdo.data(dbits*2-1 downto 0), 
	sdo.dqm(dbits/4-1 downto 0), sdo.bdrive, sdo.bdrive, sdo.qdrive, 
	sdo.rasn, sdo.casn, sdo.sdwen, sdo.sdcsn, sdo.sdcke, sdo.sdck(2 downto 0), sdo.moben,
        sdi.datavalid, testen, testrst, scanen, testoen);

    drvdata : if dbits < 64 generate
      sdi.data(127 downto dbits*2) <= (others => '0');
    end generate;
    sdi.cb <= (others => '0'); sdi.regrdata <= (others => '0');
    sdi.writereq <= '0';
end;




library ieee;
use ieee.std_logic_1164.all;

library grlib;
use grlib.stdlib.all;
library techmap;
use techmap.gencomp.all;
library gaisler;
use gaisler.ddrpkg.all;

------------------------------------------------------------------
-- DDR1 PHY with checkbits merged on data bus --------------------
------------------------------------------------------------------

entity ddrphy_wrap_cbd is
  generic (tech : integer := virtex2; MHz : integer := 100; 
	rstdelay : integer := 200; dbits : integer := 16;
        chkbits: integer := 0; padbits : integer := 0;
	clk_mul : integer := 2 ; clk_div : integer := 2;
	rskew : integer :=0; mobile : integer := 0;
        abits: integer := 14; nclk: integer := 3; ncs: integer := 2;
        scantest: integer := 0; phyiconf : integer := 0);
  port (
    rst            : in    std_ulogic;
    clk            : in    std_logic;   -- input clock
    clkout         : out   std_ulogic;  -- system clock
    clkoutret      : in    std_ulogic;  -- system clock return
    clkread        : out   std_ulogic;
    lock           : out   std_ulogic;  -- DCM locked

    ddr_clk        : out   std_logic_vector(nclk-1 downto 0);
    ddr_clkb       : out   std_logic_vector(nclk-1 downto 0);
    ddr_clk_fb_out : out   std_logic;
    ddr_clk_fb     : in    std_logic;
    ddr_cke        : out   std_logic_vector(ncs-1 downto 0);
    ddr_csb        : out   std_logic_vector(ncs-1 downto 0);
    ddr_web        : out   std_ulogic;                               -- ddr write enable
    ddr_rasb       : out   std_ulogic;                               -- ddr ras
    ddr_casb       : out   std_ulogic;                               -- ddr cas
    ddr_dm         : out   std_logic_vector ((dbits+padbits+chkbits)/8-1 downto 0);    -- ddr dm
    ddr_dqs        : inout std_logic_vector ((dbits+padbits+chkbits)/8-1 downto 0);    -- ddr dqs
    ddr_ad         : out   std_logic_vector (abits-1 downto 0);           -- ddr address
    ddr_ba         : out   std_logic_vector (1 downto 0); -- ddr bank address
    ddr_dq         : inout std_logic_vector (dbits+padbits+chkbits-1 downto 0);      -- ddr data
    
    sdi            : out   ddrctrl_in_type;
    sdo            : in    ddrctrl_out_type;

    testen      : in std_ulogic;
    testrst     : in std_ulogic;
    scanen      : in std_ulogic;
    testoen     : in std_ulogic);
end;

architecture rtl of ddrphy_wrap_cbd is

  function ddr_widthconv(x: std_logic_vector; ow: integer) return std_logic_vector is
    variable r: std_logic_vector(2*ow-1 downto 0);
    constant iw: integer := x'length/2;
  begin
    r := (others => '0');
    if iw <= ow then
      r(iw+ow-1 downto ow) := x(2*iw-1 downto iw);
      r(iw-1 downto 0) := x(iw-1 downto 0);
    else
      r := x(iw+ow-1 downto iw) & x(ow-1 downto 0);
    end if;
    return r;
  end;

  function sdr_widthconv(x: std_logic_vector; ow: integer) return std_logic_vector is
    variable r: std_logic_vector(ow-1 downto 0);
    constant iw: integer := x'length;
    variable xd : std_logic_vector(iw-1 downto 0);
  begin
    r := (others => '0'); xd := x;
    if iw >= ow then
      r := xd(ow-1 downto 0);
    else
      r(iw-1 downto 0) := xd;
    end if;
    return r;
  end;

  function ddrmerge(a,b: std_logic_vector) return std_logic_vector is
    constant aw: integer := a'length/2;
    constant bw: integer := b'length/2;
  begin
    return a(2*aw-1 downto aw) & b(2*bw-1 downto bw) & a(aw-1 downto 0) & b(bw-1 downto 0);
  end;

  signal dqin: std_logic_vector(2*(chkbits+dbits+padbits)-1 downto 0);
  signal dqout: std_logic_vector(2*(chkbits+dbits+padbits)-1 downto 0);
  signal dqm: std_logic_vector((chkbits+dbits+padbits)/4-1 downto 0);
  signal cal_en: std_logic_vector((chkbits+dbits+padbits)/8-1 downto 0);
  signal cal_inc: std_logic_vector((chkbits+dbits+padbits)/8-1 downto 0);

  signal odt,csn,cke: std_logic_vector(ncs-1 downto 0);
  signal sdck: std_logic_vector(nclk-1 downto 0);
  
begin

  -- Merge checkbit and data buses
  comb: process(sdo,dqin)
    variable dq: std_logic_vector(2*dbits-1 downto 0);
    variable dqpad: std_logic_vector(2*(dbits+padbits)-1 downto 0);
    variable cb: std_logic_vector(dbits-1 downto 0);
    variable cbpad: std_logic_vector(2*chkbits downto 0);  -- Extra bit to handle chkbits=0
    variable dqcb: std_logic_vector(2*(dbits+padbits+chkbits)-1 downto 0);
    variable dm: std_logic_vector(dbits/4-1 downto 0);
    variable dmpad: std_logic_vector((dbits+padbits)/4-1 downto 0);
    variable cbdm: std_logic_vector(dbits/8-1 downto 0);
    variable cbdmpad: std_logic_vector(chkbits/4 downto 0);
    variable dqcbdm: std_logic_vector((dbits+padbits+chkbits)/4-1 downto 0);
    variable vcsn,vcke: std_logic_vector(ncs-1 downto 0);
    variable vsdck: std_logic_vector(nclk-1 downto 0);
  begin

    dq := sdo.data(2*dbits-1 downto 0);
    dqpad := ddr_widthconv(dq, dbits+padbits );
    if chkbits > 0 then
      cb    := sdo.cb(dbits-1 downto 0);
      cbpad := '0' & ddr_widthconv(cb, chkbits);
      dqcb  := ddrmerge(cbpad(2*chkbits-1 downto 0), dqpad);
    else
      dqcb  := dqpad;
    end if;
    dqout <= dqcb;

    dqcb := dqin;
    if chkbits > 0 then
      cbpad := '0' & dqin(2*(chkbits+dbits+padbits)-1 downto 2*(dbits+padbits)+chkbits) &
               dqin(chkbits+dbits+padbits-1 downto dbits+padbits);
      cb := ddr_widthconv(cbpad(2*chkbits-1 downto 0), dbits/2);
    else
      cb := (others => '0');
    end if;
    dq := dqcb(2*dbits+chkbits+padbits-1 downto dbits+chkbits+padbits) &
          dqcb(dbits-1 downto 0);    
    sdi.cb(dbits-1 downto 0) <= cb;
    sdi.data(2*dbits-1 downto 0) <= dq;
    if sdi.cb'length > dbits then
      sdi.cb(sdi.cb'length-1 downto dbits) <= (others => '0');
    end if;
    if sdi.data'length > 2*dbits then
      sdi.data(sdi.data'length-1 downto 2*dbits) <= (others => '0');
    end if;
    dm := sdo.dqm(dbits/4-1 downto 0);
    dmpad := ddr_widthconv(dm, (dbits+padbits)/8);
    if chkbits > 0 then
      cbdm := sdo.cbdqm(dbits/8-1 downto 0);
      cbdmpad := '0' & ddr_widthconv(cbdm(dbits/8-1 downto 0), chkbits/8);
      dqcbdm := ddrmerge(cbdmpad(chkbits/4-1 downto 0), dmpad);
    else
      dqcbdm := dmpad;
    end if;
    dqm <= dqcbdm;

    cal_en  <= sdr_widthconv(sdo.cbcal_en (dbits/16-1 downto 0) &
                             sdo.cal_en (dbits/8-1 downto 0), (dbits+padbits+chkbits)/8 );
    cal_inc <= sdr_widthconv(sdo.cbcal_inc(dbits/16-1 downto 0) &
                             sdo.cal_inc(dbits/8-1 downto 0), (dbits+padbits+chkbits)/8 );
    
    vcsn := (others => '1');
    for x in 0 to ncs-1 loop
      if x<2 then
        vcsn(x) := sdo.sdcsn(x);
      end if;
      vcke(x) := sdo.sdcke(x mod 2);
    end loop;
    for x in 0 to nclk-1 loop
      vsdck(x) := sdo.sdck(x mod 2);
    end loop;
    
    csn <= vcsn;
    cke <= vcke;
    sdck <= vsdck;
  end process;
  
  -- Phy instantiation
    ddr_phy0 : ddrphy 
     generic map (tech => tech, MHz => MHz, rstdelay => rstdelay
-- reduce 200 us start-up delay during simulation
-- pragma translate_off
	/ 200
-- pragma translate_on
	, dbits     => dbits+padbits+chkbits,clk_mul  => clk_mul,  clk_div  => clk_div, 
        rskew    => rskew, mobile => mobile,
        abits       => abits,       nclk    => nclk,      ncs      => ncs, scantest => scantest,
        phyiconf => phyiconf)
     port map (
	rst, clk, clkout, clkoutret, clkread, lock,
	ddr_clk, ddr_clkb, ddr_clk_fb_out, ddr_clk_fb,
	ddr_cke, ddr_csb, ddr_web, ddr_rasb, ddr_casb, 
	ddr_dm, ddr_dqs, ddr_ad, ddr_ba, ddr_dq, 
        
	sdo.address(abits-1 downto 0), sdo.ba(1 downto 0),
	dqin, dqout, 
	dqm, sdo.bdrive, sdo.bdrive, sdo.qdrive, 
	sdo.rasn, sdo.casn, sdo.sdwen, csn, cke, sdck, sdo.moben,sdi.datavalid,
        testen,testrst,scanen,testoen);

    sdi.regrdata <= (others => '0');
    sdi.writereq <= '0';
end;




library ieee;
use ieee.std_logic_1164.all;

library grlib;
use grlib.stdlib.all;
library techmap;
use techmap.gencomp.all;
library gaisler;
use gaisler.ddrpkg.all;

------------------------------------------------------------------
-- DDR1 PHY with checkbits merged on data bus, pads not in phy --
------------------------------------------------------------------

entity ddrphy_wrap_cbd_wo_pads is
  generic (tech     : integer := virtex2; MHz        : integer := 100; 
	rstdelay    : integer := 200;     dbits      : integer := 16;  padbits  : integer := 0;
	clk_mul     : integer := 2 ;      clk_div    : integer := 2;
        rskew       : integer := 0;       mobile     : integer := 0;
        abits       : integer := 14;      nclk     : integer := 3;     ncs      : integer := 2;
        chkbits  : integer := 0;
        scantest : integer := 0; phyiconf : integer := 0);
  port (
    rst            : in    std_ulogic;
    clk            : in    std_logic;   -- input clock
    clkout         : out   std_ulogic;  -- system clock
    clkoutret      : in    std_ulogic;  -- system clock return
    lock           : out   std_ulogic;  -- DCM locked

    ddr_clk        : out   std_logic_vector(nclk-1 downto 0);
    ddr_clkb       : out   std_logic_vector(nclk-1 downto 0);
    ddr_clk_fb_out : out   std_logic;
    ddr_clk_fb     : in    std_logic;
    ddr_cke        : out   std_logic_vector(ncs-1 downto 0);
    ddr_csb        : out   std_logic_vector(ncs-1 downto 0);
    ddr_web        : out   std_ulogic;                               -- ddr write enable
    ddr_rasb       : out   std_ulogic;                               -- ddr ras
    ddr_casb       : out   std_ulogic;                               -- ddr cas
    ddr_dm         : out   std_logic_vector ((dbits+padbits+chkbits)/8-1 downto 0);    -- ddr dm
    ddr_dqs_in     : in    std_logic_vector ((dbits+padbits+chkbits)/8-1 downto 0);    -- ddr dqs
    ddr_dqs_out    : out   std_logic_vector ((dbits+padbits+chkbits)/8-1 downto 0);    -- ddr dqs
    ddr_dqs_oen    : out   std_logic_vector ((dbits+padbits+chkbits)/8-1 downto 0);    -- ddr dqs
    ddr_ad         : out   std_logic_vector (abits-1 downto 0);           -- ddr address
    ddr_ba         : out   std_logic_vector (1 downto 0); -- ddr bank address
    ddr_dq_in      : in    std_logic_vector (dbits+padbits+chkbits-1 downto 0);      -- ddr data
    ddr_dq_out     : out   std_logic_vector (dbits+padbits+chkbits-1 downto 0);      -- ddr data
    ddr_dq_oen     : out   std_logic_vector (dbits+padbits+chkbits-1 downto 0);     
    sdi            : out   ddrctrl_in_type;
    sdo            : in    ddrctrl_out_type;

    testen      : in std_ulogic;
    testrst     : in std_ulogic;
    scanen      : in std_ulogic;
    testoen     : in std_ulogic);
end;

architecture rtl of ddrphy_wrap_cbd_wo_pads is

  function ddr_widthconv(x: std_logic_vector; ow: integer) return std_logic_vector is
    variable r: std_logic_vector(2*ow-1 downto 0);
    constant iw: integer := x'length/2;
  begin
    r := (others => '0');
    if iw <= ow then
      r(iw+ow-1 downto ow) := x(2*iw-1 downto iw);
      r(iw-1 downto 0) := x(iw-1 downto 0);
    else
      r := x(iw+ow-1 downto iw) & x(ow-1 downto 0);
    end if;
    return r;
  end;

  function sdr_widthconv(x: std_logic_vector; ow: integer) return std_logic_vector is
    variable r: std_logic_vector(ow-1 downto 0);
    constant iw: integer := x'length;
    variable xd : std_logic_vector(iw-1 downto 0);
  begin
    r := (others => '0'); xd := x;
    if iw >= ow then
      r := xd(ow-1 downto 0);
    else
      r(iw-1 downto 0) := xd;
    end if;
    return r;
  end;

  function ddrmerge(a,b: std_logic_vector) return std_logic_vector is
    constant aw: integer := a'length/2;
    constant bw: integer := b'length/2;
  begin
    return a(2*aw-1 downto aw) & b(2*bw-1 downto bw) & a(aw-1 downto 0) & b(bw-1 downto 0);
  end;
  
  signal dqin: std_logic_vector(2*(chkbits+dbits+padbits)-1 downto 0);
  signal dqout: std_logic_vector(2*(chkbits+dbits+padbits)-1 downto 0);
  signal dqm: std_logic_vector((chkbits+dbits+padbits)/4-1 downto 0);
  
  signal odt,csn,cke: std_logic_vector(ncs-1 downto 0);
  signal sdck: std_logic_vector(nclk-1 downto 0);

  signal gnd : std_logic_vector(chkbits*2-1 downto 0);
  
begin

  gnd <= (others => '0');
  
  -- Merge checkbit and data buses
  comb: process(sdo,dqin)
    variable dq: std_logic_vector(2*dbits-1 downto 0);
    variable dqpad: std_logic_vector(2*(dbits+padbits)-1 downto 0);
    variable cb: std_logic_vector(dbits-1 downto 0);
    variable cbpad: std_logic_vector(2*chkbits downto 0);  -- Extra bit to handle chkbits=0
    variable dqcb: std_logic_vector(2*(dbits+padbits+chkbits)-1 downto 0);
    variable dm: std_logic_vector(dbits/4-1 downto 0);
    variable dmpad: std_logic_vector((dbits+padbits)/4-1 downto 0);
    variable cbdm: std_logic_vector(dbits/8-1 downto 0);
    variable cbdmpad: std_logic_vector(chkbits/4 downto 0);
    variable dqcbdm: std_logic_vector((dbits+padbits+chkbits)/4-1 downto 0);
    variable vcsn,vodt,vcke: std_logic_vector(ncs-1 downto 0);
    variable vsdck: std_logic_vector(nclk-1 downto 0);    
  begin

    dq := sdo.data(2*dbits-1 downto 0);
    dqpad := ddr_widthconv(dq, dbits+padbits );
    if chkbits > 0 then
      cb    := sdo.cb(dbits-1 downto 0);
      cbpad := '0' & ddr_widthconv(cb, chkbits);
      dqcb  := ddrmerge(cbpad(2*chkbits-1 downto 0), dqpad);
    else
      dqcb  := dqpad;
    end if;
    dqout <= dqcb;

    dqcb := dqin;
    if chkbits > 0 then
      cbpad := '0' & dqin(2*(chkbits+dbits+padbits)-1 downto 2*(dbits+padbits)+chkbits) &
               dqin(chkbits+dbits+padbits-1 downto dbits+padbits);
      cb := ddr_widthconv(cbpad(2*chkbits-1 downto 0), dbits/2);
    else
      cb := (others => '0');
    end if;
    dq := dqcb(2*dbits+chkbits+padbits-1 downto dbits+chkbits+padbits) &
          dqcb(dbits-1 downto 0);    
    sdi.cb(dbits-1 downto 0) <= cb;
    sdi.data(2*dbits-1 downto 0) <= dq;
    if sdi.cb'length > dbits then
      sdi.cb(sdi.cb'length-1 downto dbits) <= (others => '0');
    end if;
    if sdi.data'length > 2*dbits then
      sdi.data(sdi.data'length-1 downto 2*dbits) <= (others => '0');
    end if;
    dm := sdo.dqm(dbits/4-1 downto 0);
    dmpad := ddr_widthconv(dm, (dbits+padbits)/8);
    if chkbits > 0 then
      cbdm := sdo.cbdqm(dbits/8-1 downto 0);
      cbdmpad := '0' & ddr_widthconv(cbdm(dbits/8-1 downto 0), chkbits/8);
      dqcbdm := ddrmerge(cbdmpad(chkbits/4-1 downto 0), dmpad);
    else
      dqcbdm := dmpad;
    end if;
    dqm <= dqcbdm;
            
    vcsn := (others => '1');
    for x in 0 to ncs-1 loop
      if x<2 then
        vcsn(x) := sdo.sdcsn(x);
      end if;
      vodt(x) := sdo.odt(x mod 2);
      vcke(x) := sdo.sdcke(x mod 2);
    end loop;
    for x in 0 to nclk-1 loop
      vsdck(x) := sdo.sdck(x mod 2);
    end loop;
    
    csn <= vcsn;
    cke <= vcke;
    sdck <= vsdck;
    
  end process;
  
  -- Phy instantiation
  ddr_phy0 : ddrphy_wo_pads
    generic map (
      tech => tech, MHz => MHz, rstdelay => rstdelay
-- reduce 200 us start-up delay during simulation
-- pragma translate_off
      / 200
-- pragma translate_on
      , dbits => dbits+padbits+chkbits, clk_mul => clk_mul, clk_div => clk_div, 
      rskew => rskew,
      abits => abits, nclk => nclk, ncs => ncs, mobile => mobile, scantest => scantest, phyiconf => phyiconf)
    port map (
      rst => rst, clk => clk, clkout => clkout, clkoutret => clkoutret,
      lock => lock,
        
      ddr_clk => ddr_clk, ddr_clkb => ddr_clkb, ddr_clk_fb_out => ddr_clk_fb_out, ddr_clk_fb => ddr_clk_fb,
      ddr_cke => ddr_cke, ddr_csb => ddr_csb, ddr_web => ddr_web, ddr_rasb => ddr_rasb, ddr_casb => ddr_casb, 
      ddr_dm => ddr_dm, ddr_dqs_in => ddr_dqs_in, ddr_dqs_out => ddr_dqs_out, ddr_dqs_oen => ddr_dqs_oen,
      ddr_ad => ddr_ad, ddr_ba => ddr_ba, ddr_dq_in => ddr_dq_in, ddr_dq_out => ddr_dq_out, ddr_dq_oen => ddr_dq_oen,
      
      addr => sdo.address(abits-1 downto 0), ba => sdo.ba(1 downto 0), dqin => dqin, dqout => dqout, dm => dqm,
      oen => sdo.bdrive,
      dqs => sdo.bdrive, dqsoen => sdo.qdrive, rasn => sdo.rasn, casn => sdo.casn, wen => sdo.sdwen, csn => csn,
      cke => cke, ck => sdck, moben => sdo.moben, dqvalid => sdi.datavalid,
      testen => testen, testrst => testrst, scanen => scanen, testoen => testoen
      );
  sdi.regrdata <= (others => '0');
  sdi.writereq <= '0';
end;




library ieee;
use ieee.std_logic_1164.all;

library grlib;
use grlib.stdlib.all;
library techmap;
use techmap.gencomp.all;
library gaisler;
use gaisler.ddrpkg.all;

------------------------------------------------------------------
-- DDR2 PHY wrapper -----------------------------------------------
------------------------------------------------------------------

-------------------------------------------------------------------------------
-- There are three variants of the PHY wrapper depending on pads/checkbits:
-- 1. ddr2phy_wrap:
--       This provides pads and outputs checkbits on separate vectors
-- 2. ddr2phy_wrap_cbd:
--       This provides pads and merges checkbits+data on same vector
-- 3. ddr2phy_wrap_cbd_wo_pads:
--       This does not provide pads and merges checkbits+data on same vectors
--
-- Variants (1),(3) can not be used when ddr2phy_builtin_pads(tech)=1
-------------------------------------------------------------------------------

entity ddr2phy_wrap is
  generic (tech     : integer := virtex2; MHz        : integer := 100; 
	rstdelay    : integer := 200;     dbits      : integer := 16;  padbits  : integer := 0;
	clk_mul     : integer := 2 ;      clk_div    : integer := 2;
	ddelayb0    : integer := 0;       ddelayb1   : integer := 0;   ddelayb2 : integer := 0;
	ddelayb3    : integer := 0;       ddelayb4   : integer := 0;   ddelayb5 : integer := 0;
	ddelayb6    : integer := 0;       ddelayb7   : integer := 0;
        cbdelayb0   : integer := 0;       cbdelayb1: integer := 0;     cbdelayb2: integer := 0;
        cbdelayb3   : integer := 0;
        numidelctrl : integer := 4;       norefclk   : integer := 0;   odten    : integer := 0;
        rskew       : integer := 0;       eightbanks : integer range 0 to 1 := 0;
        dqsse       : integer range 0 to 1 := 0;
        abits       : integer := 14;      nclk     : integer := 3;     ncs      : integer := 2;
        cben        : integer := 0;       chkbits  : integer := 8;     ctrl2en  : integer := 0;
        resync      : integer := 0;       custombits: integer := 8;
        scantest    : integer := 0);
  port (
    rst            : in    std_ulogic;
    clk            : in    std_logic;   -- input clock
    clkref200      : in    std_logic;   -- input 200MHz clock
    clkout         : out   std_ulogic;  -- system clock
    clkoutret      : in    std_ulogic;  -- system clock return
    clkresync      : in    std_ulogic;  -- resync clock (if resync/=0)
    lock           : out   std_ulogic;  -- DCM locked

    ddr_clk        : out   std_logic_vector(nclk-1 downto 0);
    ddr_clkb       : out   std_logic_vector(nclk-1 downto 0);
    ddr_clk_fb_out : out   std_logic;
    ddr_clk_fb     : in    std_logic;
    ddr_cke        : out   std_logic_vector(ncs-1 downto 0);
    ddr_csb        : out   std_logic_vector(ncs-1 downto 0);
    ddr_web        : out   std_ulogic;                               -- ddr write enable
    ddr_rasb       : out   std_ulogic;                               -- ddr ras
    ddr_casb       : out   std_ulogic;                               -- ddr cas
    ddr_dm         : out   std_logic_vector ((dbits+padbits)/8-1 downto 0);    -- ddr dm
    ddr_dqs        : inout std_logic_vector ((dbits+padbits)/8-1 downto 0);    -- ddr dqs
    ddr_dqsn       : inout std_logic_vector ((dbits+padbits)/8-1 downto 0);    -- ddr dqs
    ddr_ad         : out   std_logic_vector (abits-1 downto 0);           -- ddr address
    ddr_ba         : out   std_logic_vector (1+eightbanks downto 0); -- ddr bank address
    ddr_dq         : inout std_logic_vector ((dbits+padbits)-1 downto 0);      -- ddr data
    ddr_odt        : out   std_logic_vector(ncs-1 downto 0);
    ddr_cbdm       : out   std_logic_vector(chkbits/8-1 downto 0);
    ddr_cbdqs      : inout std_logic_vector(chkbits/8-1 downto 0);
    ddr_cbdqsn     : inout std_logic_vector(chkbits/8-1 downto 0);
    ddr_cbdq       : inout std_logic_vector(chkbits-1 downto 0);
    ddr_web2       : out   std_ulogic;                               -- ddr write enable
    ddr_rasb2      : out   std_ulogic;                               -- ddr ras
    ddr_casb2      : out   std_ulogic;                               -- ddr cas
    ddr_ad2        : out   std_logic_vector (abits-1 downto 0);      -- ddr address
    ddr_ba2        : out   std_logic_vector (1+eightbanks downto 0); -- ddr bank address
    
    sdi            : out   ddrctrl_in_type;
    sdo            : in    ddrctrl_out_type;

    customclk      : in    std_ulogic;
    customdin      : in    std_logic_vector(custombits-1 downto 0);
    customdout     : out   std_logic_vector(custombits-1 downto 0);

    testen         : in    std_ulogic;
    testrst        : in    std_ulogic;
    scanen         : in    std_ulogic;
    testoen        : in    std_ulogic
    );
end;

architecture rtl of ddr2phy_wrap is

  signal lddr_clk,lddr_clkb: std_logic_vector(nclk-1 downto 0);
  signal lddr_clk_fb_out,lddr_clk_fb: std_ulogic;
  signal lddr_cke,lddr_csb,lddr_odt: std_logic_vector(ncs-1 downto 0);
  signal lddr_web,lddr_rasb,lddr_casb: std_ulogic;
  signal lddr_dm,lddr_dqs_in,lddr_dqs_out,lddr_dqs_oen: std_logic_vector((dbits+padbits+chkbits)/8-1 downto 0);
  signal lddr_ad: std_logic_vector(abits-1 downto 0);
  signal lddr_ba: std_logic_vector(1+eightbanks downto 0);
  signal lddr_dq_in,lddr_dq_out,lddr_dq_oen: std_logic_vector(dbits+padbits+chkbits-1 downto 0);
  
  
begin

  -- Instantiate PHY without pads via other wrapper
  w0: ddr2phy_wrap_cbd_wo_pads
    generic map (tech,MHz,rstdelay,dbits,padbits,clk_mul,clk_div,
                 ddelayb0,ddelayb1,ddelayb2,ddelayb3,ddelayb4,ddelayb5,ddelayb6,ddelayb7,
                 cbdelayb0,cbdelayb1,cbdelayb2,cbdelayb3,
                 numidelctrl,norefclk,odten,rskew,
                 eightbanks,dqsse,abits,nclk,ncs,chkbits,resync,custombits,scantest)
    port map (
      rst,clk,clkref200,clkout,clkoutret,clkresync,lock,
      lddr_clk,lddr_clkb,lddr_clk_fb_out,lddr_clk_fb,
      lddr_cke,lddr_csb,lddr_web,lddr_rasb,lddr_casb,lddr_dm,
      lddr_dqs_in,lddr_dqs_out,lddr_dqs_oen,
      lddr_ad,lddr_ba,lddr_dq_in,lddr_dq_out,lddr_dq_oen,
      lddr_odt,
      sdi,sdo,customclk,customdin,customdout,testen,testrst,scanen,testoen);

  -- Instantiate pads for control signals and data bus
  p0: ddr2pads
    generic map (tech,dbits+padbits,eightbanks,dqsse,abits,nclk,ncs,ctrl2en)
    port map (
      ddr_clk,ddr_clkb,ddr_clk_fb_out,ddr_clk_fb,
      ddr_cke,ddr_csb,ddr_web,ddr_rasb,ddr_casb,
      ddr_dm,ddr_dqs,ddr_dqsn,ddr_ad,ddr_ba,ddr_dq,ddr_odt,
      ddr_web2,ddr_rasb2,ddr_casb2,ddr_ad2,ddr_ba2,

      lddr_clk,lddr_clkb,lddr_clk_fb_out,lddr_clk_fb,
      lddr_cke,lddr_csb,lddr_web,lddr_rasb,lddr_casb,
      lddr_dm(dbits/8+padbits/8-1 downto 0),
      lddr_dqs_in(dbits/8+padbits/8-1 downto 0),
      lddr_dqs_out(dbits/8+padbits/8-1 downto 0),
      lddr_dqs_oen(dbits/8+padbits/8-1 downto 0),
      lddr_ad,lddr_ba,
      lddr_dq_in(dbits+padbits-1 downto 0),
      lddr_dq_out(dbits+padbits-1 downto 0),
      lddr_dq_oen(dbits+padbits-1 downto 0),
      lddr_odt);
      
  -- Instantiate pads for checkbit bus
    cbdqpad: iopadvv
      generic map (tech => tech, slew => 1, level => sstl18_ii, width => chkbits)
      port map (pad => ddr_cbdq,
                i => lddr_dq_out(dbits+padbits+chkbits-1 downto dbits+padbits),
                en => lddr_dq_oen(dbits+padbits+chkbits-1 downto dbits+padbits),
                o => lddr_dq_in(dbits+padbits+chkbits-1 downto dbits+padbits));
    cbdqmpad: outpadv
      generic map (tech => tech, slew => 1, level => sstl18_i, width => chkbits/8)
      port map (pad => ddr_cbdm,
                i => lddr_dm(dbits/8+padbits/8+chkbits/8-1 downto dbits/8+padbits/8));
    cbdqspad: iopad_dsvv
      generic map (tech => tech, slew => 1, level => sstl18_ii, width => chkbits/8)
      port map (padp => ddr_cbdqs, padn => ddr_cbdqsn,
                i => lddr_dqs_out(dbits/8+padbits/8+chkbits/8-1 downto dbits/8+padbits/8),
                en => lddr_dqs_oen(dbits/8+padbits/8+chkbits/8-1 downto dbits/8+padbits/8),
                o => lddr_dqs_in(dbits/8+padbits/8+chkbits/8-1 downto dbits/8+padbits/8));

end;

library ieee;
use ieee.std_logic_1164.all;

library grlib;
use grlib.stdlib.all;
library techmap;
use techmap.gencomp.all;
library gaisler;
use gaisler.ddrpkg.all;

------------------------------------------------------------------
-- DDR2 PHY with checkbits merged on data bus --------------------
------------------------------------------------------------------

entity ddr2phy_wrap_cbd is
  generic (tech     : integer := virtex2; MHz        : integer := 100; 
	rstdelay    : integer := 200;     dbits      : integer := 16;  padbits  : integer := 0;
	clk_mul     : integer := 2 ;      clk_div    : integer := 2;
	ddelayb0    : integer := 0;       ddelayb1   : integer := 0;   ddelayb2 : integer := 0;
	ddelayb3    : integer := 0;       ddelayb4   : integer := 0;   ddelayb5 : integer := 0;
	ddelayb6    : integer := 0;       ddelayb7   : integer := 0;
        cbdelayb0   : integer := 0;       cbdelayb1: integer := 0;     cbdelayb2: integer := 0;
        cbdelayb3   : integer := 0;
        numidelctrl : integer := 4;       norefclk   : integer := 0;   odten    : integer := 0;
        rskew       : integer := 0;       eightbanks : integer range 0 to 1 := 0;
        dqsse       : integer range 0 to 1 := 0;
        abits       : integer := 14;      nclk     : integer := 3;     ncs      : integer := 2;
        chkbits  : integer := 0;          ctrl2en  : integer := 0;
        resync      : integer := 0;       custombits: integer := 8;    extraio  : integer := 0;
        scantest    : integer := 0);
  port (
    rst            : in    std_ulogic;
    clk            : in    std_logic;   -- input clock
    clkref200      : in    std_logic;   -- input 200MHz clock
    clkout         : out   std_ulogic;  -- system clock
    clkoutret      : in    std_ulogic;  -- system clock return
    clkresync      : in    std_ulogic;
    lock           : out   std_ulogic;  -- DCM locked

    ddr_clk        : out   std_logic_vector(nclk-1 downto 0);
    ddr_clkb       : out   std_logic_vector(nclk-1 downto 0);
    ddr_clk_fb_out : out   std_logic;
    ddr_clk_fb     : in    std_logic;
    ddr_cke        : out   std_logic_vector(ncs-1 downto 0);
    ddr_csb        : out   std_logic_vector(ncs-1 downto 0);
    ddr_web        : out   std_ulogic;                               -- ddr write enable
    ddr_rasb       : out   std_ulogic;                               -- ddr ras
    ddr_casb       : out   std_ulogic;                               -- ddr cas
    ddr_dm         : out   std_logic_vector ((dbits+padbits+chkbits)/8-1 downto 0);    -- ddr dm
    ddr_dqs        : inout std_logic_vector (extraio+(dbits+padbits+chkbits)/8-1 downto 0);    -- ddr dqs
    ddr_dqsn       : inout std_logic_vector ((dbits+padbits+chkbits)/8-1 downto 0);    -- ddr dqs
    ddr_ad         : out   std_logic_vector (abits-1 downto 0);           -- ddr address
    ddr_ba         : out   std_logic_vector (1+eightbanks downto 0); -- ddr bank address
    ddr_dq         : inout std_logic_vector (dbits+padbits+chkbits-1 downto 0);      -- ddr data
    ddr_odt        : out   std_logic_vector(ncs-1 downto 0);
    ddr_web2       : out   std_ulogic;                               -- ddr write enable
    ddr_rasb2      : out   std_ulogic;                               -- ddr ras
    ddr_casb2      : out   std_ulogic;                               -- ddr cas
    ddr_ad2        : out   std_logic_vector (abits-1 downto 0);      -- ddr address
    ddr_ba2        : out   std_logic_vector (1+eightbanks downto 0); -- ddr bank address
    
    sdi            : out   ddrctrl_in_type;
    sdo            : in    ddrctrl_out_type;

    customclk      : in    std_ulogic;
    customdin      : in    std_logic_vector(custombits-1 downto 0);
    customdout     : out   std_logic_vector(custombits-1 downto 0);

    testen      : in std_ulogic;
    testrst     : in std_ulogic;
    scanen      : in std_ulogic;
    testoen     : in std_ulogic;
    oct_rdn     : in  std_logic := '0';
    oct_rup     : in  std_logic := '0'
    );
end;

architecture rtl of ddr2phy_wrap_cbd is

  function ddr_widthconv(x: std_logic_vector; ow: integer) return std_logic_vector is
    variable r: std_logic_vector(2*ow-1 downto 0);
    constant iw: integer := x'length/2;
  begin
    r := (others => '0');
    if iw <= ow then
      r(iw+ow-1 downto ow) := x(2*iw-1 downto iw);
      r(iw-1 downto 0) := x(iw-1 downto 0);
    else
      r := x(iw+ow-1 downto iw) & x(ow-1 downto 0);
    end if;
    return r;
  end;

  function sdr_widthconv(x: std_logic_vector; ow: integer) return std_logic_vector is
    variable r: std_logic_vector(ow-1 downto 0);
    constant iw: integer := x'length;
    variable xd : std_logic_vector(iw-1 downto 0);
  begin
    r := (others => '0'); xd := x;
    if iw >= ow then
      r := xd(ow-1 downto 0);
    else
      r(iw-1 downto 0) := xd;
    end if;
    return r;
  end;

  function ddrmerge(a,b: std_logic_vector) return std_logic_vector is
    constant aw: integer := a'length/2;
    constant bw: integer := b'length/2;
  begin
    return a(2*aw-1 downto aw) & b(2*bw-1 downto bw) & a(aw-1 downto 0) & b(bw-1 downto 0);
  end;

  type int_array is array (natural range <>) of integer;
  constant delays: int_array(0 to 7) := (ddelayb0,ddelayb1,ddelayb2,ddelayb3,
                                         ddelayb4,ddelayb5,ddelayb6,ddelayb7);
  constant cbdelays: int_array(0 to 11) := (cbdelayb0,cbdelayb1,cbdelayb2,cbdelayb3,0,0,0,0,0,0,0,0);
  constant cbddelays: int_array(0 to 11) :=
    delays(0 to (dbits+padbits)/8-1) & cbdelays(0 to 11-(dbits+padbits)/8);
  
  signal dqin: std_logic_vector(2*(chkbits+dbits+padbits)-1 downto 0);
  signal dqout: std_logic_vector(2*(chkbits+dbits+padbits)-1 downto 0);
  signal dqm: std_logic_vector((chkbits+dbits+padbits)/4-1 downto 0);
  signal cal_en: std_logic_vector((chkbits+dbits+padbits)/8-1 downto 0);
  signal cal_inc: std_logic_vector((chkbits+dbits+padbits)/8-1 downto 0);

  signal odt,csn,cke: std_logic_vector(ncs-1 downto 0);
  
begin

  -- Merge checkbit and data buses
  comb: process(sdo,dqin)
    variable dq: std_logic_vector(2*dbits-1 downto 0);
    variable dqpad: std_logic_vector(2*(dbits+padbits)-1 downto 0);
    variable cb: std_logic_vector(dbits-1 downto 0);
    variable cbpad: std_logic_vector(2*chkbits downto 0);  -- Extra bit to handle chkbits=0
    variable dqcb: std_logic_vector(2*(dbits+padbits+chkbits)-1 downto 0);
    variable dm: std_logic_vector(dbits/4-1 downto 0);
    variable dmpad: std_logic_vector((dbits+padbits)/4-1 downto 0);
    variable cbdm: std_logic_vector(dbits/8-1 downto 0);
    variable cbdmpad: std_logic_vector(chkbits/4 downto 0);
    variable dqcbdm: std_logic_vector((dbits+padbits+chkbits)/4-1 downto 0);
    variable vcsn,vodt,vcke: std_logic_vector(ncs-1 downto 0);
  begin

    dq := sdo.data(2*dbits-1 downto 0);
    dqpad := ddr_widthconv(dq, dbits+padbits );
    if chkbits > 0 then
      cb    := sdo.cb(dbits-1 downto 0);
      cbpad := '0' & ddr_widthconv(cb, chkbits);
      dqcb  := ddrmerge(cbpad(2*chkbits-1 downto 0), dqpad);
    else
      dqcb  := dqpad;
    end if;
    dqout <= dqcb;

    dqcb := dqin;
    if chkbits > 0 then
      cbpad := '0' & dqin(2*(chkbits+dbits+padbits)-1 downto 2*(dbits+padbits)+chkbits) &
               dqin(chkbits+dbits+padbits-1 downto dbits+padbits);
      cb := ddr_widthconv(cbpad(2*chkbits-1 downto 0), dbits/2);
    else
      cb := (others => '0');
    end if;
    dq := dqcb(2*dbits+chkbits+padbits-1 downto dbits+chkbits+padbits) &
          dqcb(dbits-1 downto 0);    
    sdi.cb(dbits-1 downto 0) <= cb;
    sdi.data(2*dbits-1 downto 0) <= dq;
    if sdi.cb'length > dbits then
      sdi.cb(sdi.cb'length-1 downto dbits) <= (others => '0');
    end if;
    if sdi.data'length > 2*dbits then
      sdi.data(sdi.data'length-1 downto 2*dbits) <= (others => '0');
    end if;
    dm := sdo.dqm(dbits/4-1 downto 0);
    dmpad := ddr_widthconv(dm, (dbits+padbits)/8);
    if chkbits > 0 then
      cbdm := sdo.cbdqm(dbits/8-1 downto 0);
      cbdmpad := '0' & ddr_widthconv(cbdm(dbits/8-1 downto 0), chkbits/8);
      dqcbdm := ddrmerge(cbdmpad(chkbits/4-1 downto 0), dmpad);
    else
      dqcbdm := dmpad;
    end if;
    dqm <= dqcbdm;

    cal_en  <= sdr_widthconv(sdo.cbcal_en (dbits/16-1 downto 0) &
                             sdo.cal_en (dbits/8-1 downto 0), (dbits+padbits+chkbits)/8 );
    cal_inc <= sdr_widthconv(sdo.cbcal_inc(dbits/16-1 downto 0) &
                             sdo.cal_inc(dbits/8-1 downto 0), (dbits+padbits+chkbits)/8 );
        
    vcsn := (others => '1');
    for x in 0 to ncs-1 loop
      if x<2 then
        vcsn(x) := sdo.sdcsn(x);
      end if;
      vodt(x) := sdo.odt(x mod 2);
      vcke(x) := sdo.sdcke(x mod 2);
    end loop;
    csn <= vcsn;
    odt <= vodt;
    cke <= vcke;
    
  end process;
  
  -- Phy instantiation
    ddr_phy0 : ddr2phy 
     generic map (tech => tech, MHz => MHz, rstdelay => rstdelay
-- reduce 200 us start-up delay during simulation
-- pragma translate_off
	/ 200
-- pragma translate_on
	, dbits     => dbits+padbits+chkbits,clk_mul  => clk_mul,  clk_div  => clk_div, 
	ddelayb0    => cbddelays(0),    ddelayb1 => cbddelays(1), ddelayb2 => cbddelays(2),
	ddelayb3    => cbddelays(3),    ddelayb4 => cbddelays(4), ddelayb5 => cbddelays(5),
	ddelayb6    => cbddelays(6),    ddelayb7 => cbddelays(7), ddelayb8 => cbddelays(8),
        ddelayb9 => cbddelays(9), ddelayb10 => cbddelays(10), ddelayb11 => cbddelays(11),
        numidelctrl => numidelctrl, norefclk => norefclk, rskew    => rskew,
        eightbanks  => eightbanks,  dqsse => dqsse,
        abits       => abits,       nclk    => nclk,      ncs      => ncs,
        ctrl2en  => ctrl2en, resync => resync, custombits => custombits, extraio => extraio,
        scantest    => scantest)
     port map (
	rst, clk, clkref200, clkout, clkoutret, clkresync, lock,
	ddr_clk, ddr_clkb, ddr_clk_fb_out, ddr_clk_fb,
	ddr_cke, ddr_csb, ddr_web, ddr_rasb, ddr_casb, 
	ddr_dm, ddr_dqs, ddr_dqsn, ddr_ad, ddr_ba, ddr_dq, ddr_odt,
        
	sdo.address(abits-1 downto 0), sdo.ba,
	dqin, dqout, 
	dqm, sdo.bdrive, sdo.nbdrive, sdo.bdrive, sdo.qdrive, 
	sdo.rasn, sdo.casn, sdo.sdwen, csn, cke, 
	cal_en, cal_inc, 
        sdo.cal_pll, sdo.cal_rst, odt, sdo.oct, sdo.read_pend,
        sdo.regwdata, sdo.regwrite, sdi.regrdata, sdi.datavalid,
        customclk, customdin, customdout,
        
        ddr_web2, ddr_rasb2, ddr_casb2, ddr_ad2, ddr_ba2,

        testen, testrst, scanen, testoen,
        oct_rdn, oct_rup
        );
  sdi.writereq <= '0';
end;

library ieee;
use ieee.std_logic_1164.all;

library grlib;
use grlib.stdlib.all;
library techmap;
use techmap.gencomp.all;
library gaisler;
use gaisler.ddrpkg.all;

------------------------------------------------------------------
-- DDR2 PHY with checkbits merged on data bus, pads not in phy --
------------------------------------------------------------------

entity ddr2phy_wrap_cbd_wo_pads is
  generic (tech     : integer := virtex2; MHz        : integer := 100; 
	rstdelay    : integer := 200;     dbits      : integer := 16;  padbits  : integer := 0;
	clk_mul     : integer := 2 ;      clk_div    : integer := 2;
	ddelayb0    : integer := 0;       ddelayb1   : integer := 0;   ddelayb2 : integer := 0;
	ddelayb3    : integer := 0;       ddelayb4   : integer := 0;   ddelayb5 : integer := 0;
	ddelayb6    : integer := 0;       ddelayb7   : integer := 0;
        cbdelayb0   : integer := 0;       cbdelayb1: integer := 0;     cbdelayb2: integer := 0;
        cbdelayb3   : integer := 0;
        numidelctrl : integer := 4;       norefclk   : integer := 0;   odten    : integer := 0;
        rskew       : integer := 0;       eightbanks : integer range 0 to 1 := 0;
        dqsse       : integer range 0 to 1 := 0;
        abits       : integer := 14;      nclk     : integer := 3;     ncs      : integer := 2;
        chkbits  : integer := 0;          resync     : integer := 0;   custombits: integer := 8;
        scantest   : integer := 0);
  port (
    rst            : in    std_ulogic;
    clk            : in    std_logic;   -- input clock
    clkref200      : in    std_logic;   -- input 200MHz clock
    clkout         : out   std_ulogic;  -- system clock
    clkoutret      : in    std_ulogic;  -- system clock return
    clkresync      : in    std_ulogic;
    lock           : out   std_ulogic;  -- DCM locked

    ddr_clk        : out   std_logic_vector(nclk-1 downto 0);
    ddr_clkb       : out   std_logic_vector(nclk-1 downto 0);
    ddr_clk_fb_out : out   std_logic;
    ddr_clk_fb     : in    std_logic;
    ddr_cke        : out   std_logic_vector(ncs-1 downto 0);
    ddr_csb        : out   std_logic_vector(ncs-1 downto 0);
    ddr_web        : out   std_ulogic;                               -- ddr write enable
    ddr_rasb       : out   std_ulogic;                               -- ddr ras
    ddr_casb       : out   std_ulogic;                               -- ddr cas
    ddr_dm         : out   std_logic_vector ((dbits+padbits+chkbits)/8-1 downto 0);    -- ddr dm
    ddr_dqs_in     : in    std_logic_vector ((dbits+padbits+chkbits)/8-1 downto 0);    -- ddr dqs
    ddr_dqs_out    : out   std_logic_vector ((dbits+padbits+chkbits)/8-1 downto 0);    -- ddr dqs
    ddr_dqs_oen    : out   std_logic_vector ((dbits+padbits+chkbits)/8-1 downto 0);    -- ddr dqs
    ddr_ad         : out   std_logic_vector (abits-1 downto 0);           -- ddr address
    ddr_ba         : out   std_logic_vector (1+eightbanks downto 0); -- ddr bank address
    ddr_dq_in      : in    std_logic_vector (dbits+padbits+chkbits-1 downto 0);      -- ddr data
    ddr_dq_out     : out   std_logic_vector (dbits+padbits+chkbits-1 downto 0);      -- ddr data
    ddr_dq_oen     : out   std_logic_vector (dbits+padbits+chkbits-1 downto 0);      -- ddr data
    ddr_odt        : out   std_logic_vector(ncs-1 downto 0);
    
    sdi            : out   ddrctrl_in_type;
    sdo            : in    ddrctrl_out_type;

    customclk      : in    std_ulogic;
    customdin      : in    std_logic_vector(custombits-1 downto 0);
    customdout     : out   std_logic_vector(custombits-1 downto 0);

    testen      : in std_ulogic;
    testrst     : in std_ulogic;
    scanen      : in std_ulogic;
    testoen     : in std_ulogic);
end;

architecture rtl of ddr2phy_wrap_cbd_wo_pads is

  function ddr_widthconv(x: std_logic_vector; ow: integer) return std_logic_vector is
    variable r: std_logic_vector(2*ow-1 downto 0);
    constant iw: integer := x'length/2;
  begin
    r := (others => '0');
    if iw <= ow then
      r(iw+ow-1 downto ow) := x(2*iw-1 downto iw);
      r(iw-1 downto 0) := x(iw-1 downto 0);
    else
      r := x(iw+ow-1 downto iw) & x(ow-1 downto 0);
    end if;
    return r;
  end;

  function sdr_widthconv(x: std_logic_vector; ow: integer) return std_logic_vector is
    variable r: std_logic_vector(ow-1 downto 0);
    constant iw: integer := x'length;
    variable xd : std_logic_vector(iw-1 downto 0);
  begin
    r := (others => '0'); xd := x;
    if iw >= ow then
      r := xd(ow-1 downto 0);
    else
      r(iw-1 downto 0) := xd;
    end if;
    return r;
  end;

  function ddrmerge(a,b: std_logic_vector) return std_logic_vector is
    constant aw: integer := a'length/2;
    constant bw: integer := b'length/2;
  begin
    return a(2*aw-1 downto aw) & b(2*bw-1 downto bw) & a(aw-1 downto 0) & b(bw-1 downto 0);
  end;

  type int_array is array (natural range <>) of integer;
  constant delays: int_array(0 to 7) := (ddelayb0,ddelayb1,ddelayb2,ddelayb3,
                                         ddelayb4,ddelayb5,ddelayb6,ddelayb7);
  constant cbdelays: int_array(0 to 11) := (cbdelayb0,cbdelayb1,cbdelayb2,cbdelayb3,0,0,0,0,0,0,0,0);
  constant cbddelays: int_array(0 to 11) :=
    delays(0 to (dbits+padbits)/8-1) & cbdelays(0 to 11-(dbits+padbits)/8);
  
  signal dqin: std_logic_vector(2*(chkbits+dbits+padbits)-1 downto 0);
  signal dqout: std_logic_vector(2*(chkbits+dbits+padbits)-1 downto 0);
  signal dqm: std_logic_vector((chkbits+dbits+padbits)/4-1 downto 0);
  signal cal_en: std_logic_vector((chkbits+dbits+padbits)/8-1 downto 0);
  signal cal_inc: std_logic_vector((chkbits+dbits+padbits)/8-1 downto 0);
  
  signal odt,csn,cke: std_logic_vector(ncs-1 downto 0);

  signal gnd : std_logic_vector(chkbits*2-1 downto 0);
  
begin

  gnd <= (others => '0');
  
  -- Merge checkbit and data buses
  comb: process(sdo,dqin)
    variable dq: std_logic_vector(2*dbits-1 downto 0);
    variable dqpad: std_logic_vector(2*(dbits+padbits)-1 downto 0);
    variable cb: std_logic_vector(dbits-1 downto 0);
    variable cbpad: std_logic_vector(2*chkbits downto 0);  -- Extra bit to handle chkbits=0
    variable dqcb: std_logic_vector(2*(dbits+padbits+chkbits)-1 downto 0);
    variable dm: std_logic_vector(dbits/4-1 downto 0);
    variable dmpad: std_logic_vector((dbits+padbits)/4-1 downto 0);
    variable cbdm: std_logic_vector(dbits/8-1 downto 0);
    variable cbdmpad: std_logic_vector(chkbits/4 downto 0);
    variable dqcbdm: std_logic_vector((dbits+padbits+chkbits)/4-1 downto 0);
    variable vcsn,vodt,vcke: std_logic_vector(ncs-1 downto 0);
  begin

    dq := sdo.data(2*dbits-1 downto 0);
    dqpad := ddr_widthconv(dq, dbits+padbits );
    if chkbits > 0 then
      cb    := sdo.cb(dbits-1 downto 0);
      cbpad := '0' & ddr_widthconv(cb, chkbits);
      dqcb  := ddrmerge(cbpad(2*chkbits-1 downto 0), dqpad);
    else
      dqcb  := dqpad;
    end if;
    dqout <= dqcb;

    dqcb := dqin;
    if chkbits > 0 then
      cbpad := '0' & dqin(2*(chkbits+dbits+padbits)-1 downto 2*(dbits+padbits)+chkbits) &
               dqin(chkbits+dbits+padbits-1 downto dbits+padbits);
      cb := ddr_widthconv(cbpad(2*chkbits-1 downto 0), dbits/2);
    else
      cb := (others => '0');
    end if;
    dq := dqcb(2*dbits+chkbits+padbits-1 downto dbits+chkbits+padbits) &
          dqcb(dbits-1 downto 0);    
    sdi.cb(dbits-1 downto 0) <= cb;
    sdi.data(2*dbits-1 downto 0) <= dq;
    if sdi.cb'length > dbits then
      sdi.cb(sdi.cb'length-1 downto dbits) <= (others => '0');
    end if;
    if sdi.data'length > 2*dbits then
      sdi.data(sdi.data'length-1 downto 2*dbits) <= (others => '0');
    end if;
    dm := sdo.dqm(dbits/4-1 downto 0);
    dmpad := ddr_widthconv(dm, (dbits+padbits)/8);
    if chkbits > 0 then
      cbdm := sdo.cbdqm(dbits/8-1 downto 0);
      cbdmpad := '0' & ddr_widthconv(cbdm(dbits/8-1 downto 0), chkbits/8);
      dqcbdm := ddrmerge(cbdmpad(chkbits/4-1 downto 0), dmpad);
    else
      dqcbdm := dmpad;
    end if;
    dqm <= dqcbdm;

    cal_en  <= sdr_widthconv(sdo.cbcal_en (dbits/16-1 downto 0) &
                             sdo.cal_en (dbits/8-1 downto 0), (dbits+padbits+chkbits)/8 );
    cal_inc <= sdr_widthconv(sdo.cbcal_inc(dbits/16-1 downto 0) &
                             sdo.cal_inc(dbits/8-1 downto 0), (dbits+padbits+chkbits)/8 );
        
    vcsn := (others => '1');
    for x in 0 to ncs-1 loop
      if x<2 then
        vcsn(x) := sdo.sdcsn(x);
      end if;
      vodt(x) := sdo.odt(x mod 2);
      vcke(x) := sdo.sdcke(x mod 2);
    end loop;
    csn <= vcsn;
    odt <= vodt;
    cke <= vcke;
    
  end process;
  
  -- Phy instantiation
  ddr_phy0 : ddr2phy_wo_pads
    generic map (tech => tech, MHz => MHz, rstdelay => rstdelay
-- reduce 200 us start-up delay during simulation
-- pragma translate_off
       / 200
-- pragma translate_on
       , dbits     => dbits+padbits+chkbits,clk_mul  => clk_mul,  clk_div  => clk_div, 
	ddelayb0    => cbddelays(0),    ddelayb1 => cbddelays(1), ddelayb2 => cbddelays(2),
	ddelayb3    => cbddelays(3),    ddelayb4 => cbddelays(4), ddelayb5 => cbddelays(5),
	ddelayb6    => cbddelays(6),    ddelayb7 => cbddelays(7), ddelayb8 => cbddelays(8),
        ddelayb9 => cbddelays(9), ddelayb10 => cbddelays(10), ddelayb11 => cbddelays(11),
       numidelctrl => numidelctrl, norefclk => norefclk, rskew    => rskew,
       eightbanks  => eightbanks,  dqsse => dqsse,
       abits       => abits,       nclk    => nclk,      ncs      => ncs, resync => resync, custombits => custombits,
       scantest => scantest)
     port map (
	rst => rst, clk => clk, clkref => clkref200, clkout => clkout, clkoutret => clkoutret,
        clkresync => clkresync, lock => lock,
        
	ddr_clk => ddr_clk, ddr_clkb => ddr_clkb, ddr_clk_fb_out => ddr_clk_fb_out, ddr_clk_fb => ddr_clk_fb,
	ddr_cke => ddr_cke, ddr_csb => ddr_csb, ddr_web => ddr_web, ddr_rasb => ddr_rasb, ddr_casb => ddr_casb, 
	ddr_dm => ddr_dm, ddr_dqs_in => ddr_dqs_in, ddr_dqs_out => ddr_dqs_out, ddr_dqs_oen => ddr_dqs_oen,
        ddr_ad => ddr_ad, ddr_ba => ddr_ba, ddr_dq_in => ddr_dq_in, ddr_dq_out => ddr_dq_out, ddr_dq_oen => ddr_dq_oen,
        ddr_odt => ddr_odt,
        
	addr => sdo.address(abits-1 downto 0), ba => sdo.ba, dqin => dqin, dqout => dqout, dm => dqm,
        oen => sdo.bdrive, noen => sdo.nbdrive,
        dqs => sdo.bdrive, dqsoen => sdo.qdrive, rasn => sdo.rasn, casn => sdo.casn, wen => sdo.sdwen, csn => csn,
        cke => cke, cal_en => cal_en, cal_inc => cal_inc, cal_pll => sdo.cal_pll, cal_rst => sdo.cal_rst, odt => odt,
        oct => sdo.oct, read_pend => sdo.read_pend, regwdata => sdo.regwdata, regwrite => sdo.regwrite,
        regrdata => sdi.regrdata, dqin_valid => sdi.datavalid,
        customclk => customclk, customdin => customdin, customdout => customdout,
        testen => testen, testrst => testrst, scanen => scanen, testoen => testoen
        );
  sdi.writereq <= '0';
end;








------------------------------------------------------------------
-- LPDDR2/LPDDR3 PHY with checkbits merged on data bus, no pads --
------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;

library grlib;
use grlib.stdlib.all;
library techmap;
use techmap.gencomp.all;
library gaisler;
use gaisler.ddrpkg.all;

entity lpddr2phy_wrap_cbd_wo_pads is
  generic (tech     : integer := virtex2;
           dbits      : integer := 16;
           nclk     : integer := 3;
           ncs      : integer := 2;
           chkbits  : integer := 0;
           padbits  : integer := 0;
           scantest : integer := 0);
  port (
    rst            : in    std_ulogic;
    clkin          : in    std_ulogic;  -- input clock
    clkin2         : in    std_ulogic;  -- input clock
    clkout         : out   std_ulogic;  -- system clock
    clkoutret      : in    std_ulogic;  -- system clock return
    clkout2        : out   std_ulogic;  -- system clock
    lock           : out   std_ulogic;  -- DCM locked

    ddr_clk        : out   std_logic_vector(nclk-1 downto 0);
    ddr_clkb       : out   std_logic_vector(nclk-1 downto 0);
    ddr_cke        : out   std_logic_vector(ncs-1 downto 0);
    ddr_csb        : out   std_logic_vector(ncs-1 downto 0);
    ddr_ca         : out   std_logic_vector(9 downto 0);                             -- ddr cmd/addr
    ddr_dm         : out   std_logic_vector ((dbits+padbits+chkbits)/8-1 downto 0);  -- ddr dm
    ddr_dqs_in     : in    std_logic_vector ((dbits+padbits+chkbits)/8-1 downto 0);  -- ddr dqs
    ddr_dqs_out    : out   std_logic_vector ((dbits+padbits+chkbits)/8-1 downto 0);  -- ddr dqs
    ddr_dqs_oen    : out   std_logic_vector ((dbits+padbits+chkbits)/8-1 downto 0);  -- ddr dqs
    ddr_dq_in      : in    std_logic_vector (dbits+padbits+chkbits-1 downto 0);      -- ddr data
    ddr_dq_out     : out   std_logic_vector (dbits+padbits+chkbits-1 downto 0);      -- ddr data
    ddr_dq_oen     : out   std_logic_vector (dbits+padbits+chkbits-1 downto 0);
    sdi            : out   ddrctrl_in_type;
    sdo            : in    ddrctrl_out_type;

    testen      : in std_ulogic;
    testrst     : in std_ulogic;
    scanen      : in std_ulogic;
    testoen     : in std_ulogic);
end;

architecture rtl of lpddr2phy_wrap_cbd_wo_pads is

  function ddr_widthconv(x: std_logic_vector; ow: integer) return std_logic_vector is
    variable r: std_logic_vector(2*ow-1 downto 0);
    constant iw: integer := x'length/2;
  begin
    r := (others => '0');
    if iw <= ow then
      r(iw+ow-1 downto ow) := x(2*iw-1 downto iw);
      r(iw-1 downto 0) := x(iw-1 downto 0);
    else
      r := x(iw+ow-1 downto iw) & x(ow-1 downto 0);
    end if;
    return r;
  end;

  function sdr_widthconv(x: std_logic_vector; ow: integer) return std_logic_vector is
    variable r: std_logic_vector(ow-1 downto 0);
    constant iw: integer := x'length;
    variable xd : std_logic_vector(iw-1 downto 0);
  begin
    r := (others => '0'); xd := x;
    if iw >= ow then
      r := xd(ow-1 downto 0);
    else
      r(iw-1 downto 0) := xd;
    end if;
    return r;
  end;

  function ddrmerge(a,b: std_logic_vector) return std_logic_vector is
    constant aw: integer := a'length/2;
    constant bw: integer := b'length/2;
  begin
    return a(2*aw-1 downto aw) & b(2*bw-1 downto bw) & a(aw-1 downto 0) & b(bw-1 downto 0);
  end;

  signal dqin: std_logic_vector(2*(chkbits+dbits+padbits)-1 downto 0);
  signal dqout: std_logic_vector(2*(chkbits+dbits+padbits)-1 downto 0);
  signal dqm: std_logic_vector((chkbits+dbits+padbits)/4-1 downto 0);

  signal odt,csn,cke: std_logic_vector(ncs-1 downto 0);
  signal sdck: std_logic_vector(nclk-1 downto 0);

  signal gnd : std_logic_vector(chkbits*2-1 downto 0);

begin

  gnd <= (others => '0');

  -- Merge checkbit and data buses
  comb: process(sdo,dqin)
    variable dq: std_logic_vector(2*dbits-1 downto 0);
    variable dqpad: std_logic_vector(2*(dbits+padbits)-1 downto 0);
    variable cb: std_logic_vector(dbits-1 downto 0);
    variable cbpad: std_logic_vector(2*chkbits downto 0);  -- Extra bit to handle chkbits=0
    variable dqcb: std_logic_vector(2*(dbits+padbits+chkbits)-1 downto 0);
    variable dm: std_logic_vector(dbits/4-1 downto 0);
    variable dmpad: std_logic_vector((dbits+padbits)/4-1 downto 0);
    variable cbdm: std_logic_vector(dbits/8-1 downto 0);
    variable cbdmpad: std_logic_vector(chkbits/4 downto 0);
    variable dqcbdm: std_logic_vector((dbits+padbits+chkbits)/4-1 downto 0);
    variable vcsn,vcke: std_logic_vector(ncs-1 downto 0);
    variable vsdck: std_logic_vector(nclk-1 downto 0);
  begin

    dq := sdo.data(2*dbits-1 downto 0);
    dqpad := ddr_widthconv(dq, dbits+padbits );
    if chkbits > 0 then
      cb    := sdo.cb(dbits-1 downto 0);
      cbpad := '0' & ddr_widthconv(cb, chkbits);
      dqcb  := ddrmerge(cbpad(2*chkbits-1 downto 0), dqpad);
    else
      dqcb  := dqpad;
    end if;
    dqout <= dqcb;

    dqcb := dqin;
    if chkbits > 0 then
      cbpad := '0' & dqin(2*(chkbits+dbits+padbits)-1 downto 2*(dbits+padbits)+chkbits) &
               dqin(chkbits+dbits+padbits-1 downto dbits+padbits);
      cb := ddr_widthconv(cbpad(2*chkbits-1 downto 0), dbits/2);
    else
      cb := (others => '0');
    end if;
    dq := dqcb(2*dbits+chkbits+padbits-1 downto dbits+chkbits+padbits) &
          dqcb(dbits-1 downto 0);
    sdi.cb(dbits-1 downto 0) <= cb;
    sdi.data(2*dbits-1 downto 0) <= dq;
    if sdi.cb'length > dbits then
      sdi.cb(sdi.cb'length-1 downto dbits) <= (others => '0');
    end if;
    if sdi.data'length > 2*dbits then
      sdi.data(sdi.data'length-1 downto 2*dbits) <= (others => '0');
    end if;
    dm := sdo.dqm(dbits/4-1 downto 0);
    dmpad := ddr_widthconv(dm, (dbits+padbits)/8);
    if chkbits > 0 then
      cbdm := sdo.cbdqm(dbits/8-1 downto 0);
      cbdmpad := '0' & ddr_widthconv(cbdm(dbits/8-1 downto 0), chkbits/8);
      dqcbdm := ddrmerge(cbdmpad(chkbits/4-1 downto 0), dmpad);
    else
      dqcbdm := dmpad;
    end if;
    dqm <= dqcbdm;

    vcsn := (others => '1');
    for x in 0 to ncs-1 loop
      if x<2 then
        vcsn(x) := sdo.sdcsn(x);
      end if;
      vcke(x) := sdo.sdcke(x mod 2);
    end loop;
    for x in 0 to nclk-1 loop
      vsdck(x) := sdo.sdck(x mod 2);
    end loop;

    csn <= vcsn;
    cke <= vcke;
    sdck <= vsdck;

  end process;

  -- Phy instantiation
  ddr_phy0 : lpddr2phy_wo_pads
    generic map (
      tech => tech,
      dbits => dbits+padbits+chkbits,
      nclk => nclk,
      ncs => ncs,
      clkratio => 1,
      scantest => scantest)
    port map (
      rst => rst,
      clkin => clkin,
      clkin2 => clkin2,
      clkout => clkout,
      clkoutret => clkoutret,
      clkout2 => clkout2,
      lock => lock,

      ddr_clk => ddr_clk,
      ddr_clkb => ddr_clkb,
      ddr_cke => ddr_cke,
      ddr_csb => ddr_csb,
      ddr_ca => ddr_ca,
      ddr_dm => ddr_dm,
      ddr_dqs_in => ddr_dqs_in,
      ddr_dqs_out => ddr_dqs_out,
      ddr_dqs_oen => ddr_dqs_oen,
      ddr_dq_in => ddr_dq_in,
      ddr_dq_out => ddr_dq_out,
      ddr_dq_oen => ddr_dq_oen,

      ca => sdo.ca,
      cke => cke,
      csn => csn,
      dqin => dqin,
      dqout => dqout,
      dm => dqm,
      ckstop => sdo.sdck(0),
      boot => sdo.boot,
      wrpend => sdo.wrpend,
      rdpend => sdo.read_pend,
      wrreq(0) => sdi.writereq,
      rdvalid(0) => sdi.datavalid,

      refcal => '0',
      refcalwu => '0',
      refcaldone => open,

      phycmd => "00000000",
      phycmden => '0',
      phycmdin => x"00000000",
      phycmdout => open,

      testen => '0',
      testrst => '1',
      scanen => '0',
      testoen => '0'
      );
  sdi.regrdata <= (others => '0');

end;



