📄 hs.vhd
字号:
-------------------------------------------------------------------------------- This file is a part of the GRLIB VHDL IP LIBRARY-- Copyright (C) 2003, Gaisler Research---- This program is free software; you can redistribute it and/or modify-- it under the terms of the GNU General Public License as published by-- the Free Software Foundation; either version 2 of the License, or-- (at your option) any later version.---- This program is distributed in the hope that it will be useful,-- but WITHOUT ANY WARRANTY; without even the implied warranty of-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-- GNU General Public License for more details.---- You should have received a copy of the GNU General Public License-- along with this program; if not, write to the Free Software-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ------------------------------------------------------------------------------- Entity: hs-- File: hs.vhd-- Author: David Lindh - Gaisler Research-- Description: High speed DDR memory interface------------------------------------------------------------------------------library ieee;use ieee.std_logic_1164.all;library grlib;use grlib.stdlib.all;use grlib.amba.all;library gaisler;use gaisler.misc.all;library techmap;use techmap.gencomp.all;use techmap.allmem.all;library gaisler;use gaisler.ddrrec.all;entity hs is generic( tech : in integer; dqsize : in integer; dmsize : in integer; strobesize: in integer; clkperiod : in integer); port ( rst : in std_ulogic; clk0 : in std_ulogic; clk90 : in std_ulogic; clk180 : in std_ulogic; clk270 : in std_ulogic; hclk : in std_ulogic; hssi : in hs_in_type; hsso : out hs_out_type); end entity hs; architecture rtl of hs is type wait_times_row_type is array(7 downto 0) of integer range 0 to 31; type wait_times_matrix_type is array(7 downto 0) of wait_times_row_type; constant DELAY_15NS : integer := (((15*1000)-1) / (clkperiod*1000))+1; constant DELAY_20NS : integer := (((20*1000)-1) / (clkperiod*1000))+1; constant DELAY_50NS : integer := (((50*1000)-1) / (clkperiod*1000))+1; constant DELAY_75NS : integer := (((75*1000)-1) / (clkperiod*1000))+1; constant DELAY_80NS : integer := (((80*1000)-1) / (clkperiod*1000))+1; constant DELAY_120NS : integer := (((120*1000)-1) / (clkperiod*1000))+1; constant wait_times : wait_times_matrix_type := -- NOP,BST,READ,WRITE,ACT,PRE,RFSH,LMR ((0, 0, 0, 0, 0, 0, 0, 0), (0, 0, 0, 0, 0, 0, 0, 0), (0, 0, 0, 2, DELAY_20NS, 10, 10, 10), (0, 0, 3, 0, DELAY_20NS, 10, 10, 10), (0, 0, DELAY_20NS, 1+DELAY_15NS+DELAY_20NS, DELAY_15NS, DELAY_20NS, DELAY_120NS, 2), (0, 0, 0, 1+DELAY_15NS, DELAY_50NS, DELAY_20NS, DELAY_120NS, 2), (0, 0, DELAY_20NS, 1+DELAY_15NS+DELAY_20NS, 10, DELAY_20NS, DELAY_120NS, 2), (0, 0, DELAY_20NS, 1+DELAY_15NS+DELAY_20NS, 10, DELAY_20NS, DELAY_120NS, 2)); --signal cmdr : cmd_reg_type; signal cmdri: cmd_reg_type; signal rwr : rw_reg_type; signal rwri : rw_reg_type; signal data_out : std_logic_vector((dqsize-1) downto 0); signal data_in : std_logic_vector((dqsize-1) downto 0); signal strobe_out : std_logic_vector((strobesize-1) downto 0); signal mask_out : std_logic_vector((dmsize-1) downto 0); signal dq1_i : std_logic_vector((dqsize-1) downto 0); signal dq1del_i : std_logic_vector((dqsize-1) downto 0); signal dq2_i : std_logic_vector((dqsize-1) downto 0); signal dq1_o : std_logic_vector((dqsize-1) downto 0); signal dq2_o : std_logic_vector((dqsize-1) downto 0); signal dm1_o : std_logic_vector((dmsize-1) downto 0); signal dm2_o : std_logic_vector((dmsize-1) downto 0); signal dqs1_o, dqs2_o, w_ce, r_ce, vcc, gnd : std_ulogic; -- DQS delay control signal signal uddcntl : std_ulogic; signal lock : std_ulogic; signal dqsdel : std_ulogic; signal read : std_ulogic; signal dqso : std_logic_vector((strobesize-1) downto 0); signal ddrclkpol : std_logic_vector((strobesize-1) downto 0); signal invrst : std_logic; signal clk_90 :std_ulogic;begin ------------------------------------------------------------------------------- rwcomb : process(rst, hssi, rwr, dq1_i, dq1del_i, dq2_i) variable v : rw_reg_type;begin v:= rwr; v.set_cmd := CMD_NOP; v.set_adr := (others => '0'); v.set_cs := "11"; v.begin_read := '0'; v.begin_write := '0'; ------------------------------------------------------------------------------- -- Buffer for incoming command------------------------------------------------------------------------------- case v.cbufstate is when no_cmd => v.hs_busy := '0'; if hssi.cmd_valid = '1' then v.next_bl := hssi.bl; v.next_buf := hssi.buf; v.next_cas := hssi.cas; v.next_adr := hssi.adr; v.next_cs := hssi.cs; v.next_cmd := hssi.cmd; v.next_ml := hssi.ml; v.next_ahb := hssi.ahb; v.cbufstate := new_cmd; end if; when new_cmd => v.hs_busy := '1'; end case; ------------------------------------------------------------------------------- -- Send commands-------------------------------------------------------------------------------case v.cmdstate is when idle => v.holdcnt := 0; if rwr.cbufstate = new_cmd then v.rw_cmd := rwr.next_cmd; v.rw_bl := rwr.next_bl; v.rw_cas := 2 + conv_integer(rwr.next_cas(0))+ conv_integer(rwr.next_cas(1)); v.set_cmd := rwr.next_cmd; v.set_adr := rwr.next_adr; v.set_cs := rwr.next_cs; v.set_cke := '1'; v.cbufstate := no_cmd; v.cmdstate := hold; -- Read command, delay start of Read machine if rwr.next_cmd = CMD_READ then if rwr.next_cas = "00" then -- cas 2 v.readwait(5) := '1'; v.bufwait(5):= rwr.next_buf; v.ahbwait(5) := rwr.next_ahb; v.blwait(5) := rwr.next_bl; v.caswait(5) := rwr.next_cas(0); else -- cas 2.5 or 3 v.readwait(6) := '1'; v.bufwait(6):= rwr.next_buf; v.ahbwait(6) := rwr.next_ahb; v.blwait(6) := rwr.next_bl; v.caswait(6) := rwr.next_cas(0); end if; -- Calculate delay until write can begin v.r2wholdcnt := rwr.rw_cas + rwr.rw_bl/2 +2; -- Write command, immediately start Write machine elsif rwr.next_cmd = CMD_WRITE then v.writewait(1) := '1'; v.bufwait(1):= rwr.next_buf; v.ahbwait(1) := rwr.next_ahb; v.blwait(1) := rwr.next_bl; v.mlwait(1) := rwr.next_ml; -- Active command, begin count towards ealiest precharge elsif rwr.next_cmd = CMD_ACTIVE then v.act2precnt := DELAY_50NS-1; end if; end if; -- Wait until next cmd is valid to send when hold => v.set_cmd := CMD_NOP; v.set_adr := (others => '0'); v.set_cs := "11"; -- Some waittimes which isn't constant if v.rw_cmd = CMD_READ and rwr.next_cmd = CMD_WRITE then v.wait_time := v.rw_cas + v.rw_bl/2; elsif v.rw_cmd = CMD_READ or v.rw_cmd = CMD_WRITE then v.wait_time := v.rw_bl/2; else v.wait_time := 0; end if; -- Calculate total wait time if rwr.cbufstate = new_cmd then if ((v.holdcnt+2 >= wait_times(conv_integer(rwr.next_cmd))(conv_integer(v.rw_cmd))+ v.wait_time) and (v.r2wholdcnt = 0 or rwr.next_cmd /= CMD_WRITE) and (v.act2precnt = 0 or rwr.next_cmd /= CMD_PRE)) then v.cmdstate := idle; end if; elsif v.holdcnt >= 4+DELAY_120NS then v.cmdstate := idle; end if; v.holdcnt := v.holdcnt +1;end case;-- Separate count for time beteen a read and write and between active and prechargeif v.r2wholdcnt /= 0 then v.r2wholdcnt := v.r2wholdcnt -1; end if;if v.act2precnt /= 0 then v.act2precnt := v.act2precnt -1; end if;--------------------------------------------------------------------------------- Delay cmd data for Read machine during CAS period------------------------------------------------------------------------------- if v.readwait(0) = '1' or v.writewait(0) = '1' then v.begin_read := v.readwait(0); v.begin_write := v.writewait(0); v.use_ahb := v.ahbwait(0); v.use_buf := v.bufwait(0); v.use_bl := v.blwait(0); if v.writewait(0) = '1' then v.use_ml := v.mlwait(0); else v.use_cas := v.caswait(0); end if; end if; v.readwait := '0' & v.readwait(6 downto 1); v.writewait := '0' & v.writewait(1); v.bufwait(5 downto 0) := v.bufwait(6 downto 1); v.ahbwait := 0 & v.ahbwait(6 downto 1); v.blwait := 8 & v.blwait(6 downto 1); v.mlwait := 1 & v.mlwait(1); v.caswait := '0' & v.caswait(6 downto 1); ------------------------------------------------------------------------------- -- Send/recieve data------------------------------------------------------------------------------- -- Read and Write routinescase v.rwstate is when idle => v.sync_adr(0) := (v.cur_buf(0)+1) & "00"; v.sync_adr(1) := (v.cur_buf(1)+1) & "00"; v.cmdDone := v.cur_buf; v.sync_write:= "00"; v.dq_dqs_oe := '1'; v.dqs1_o := '0'; v.w_ce := '0'; v.r_ce := '1'; v.cnt := 0; if v.begin_write = '1' then v.cur_buf(v.use_ahb) := v.use_buf; v.cur_ahb := v.use_ahb; v.dq_dqs_oe := '0'; v.w_ce := '1'; v.cnt := v.cnt +2; if v.use_bl = 2 then v.sync_adr(v.use_ahb) := (v.use_buf +1) & "00"; else v.sync_adr(v.use_ahb) := v.use_buf & "01"; end if; v.rwstate := w; elsif v.begin_read = '1' then v.cur_buf(v.use_ahb) := v.use_buf; v.cur_ahb := v.use_ahb; v.sync_adr(v.use_ahb) := v.use_buf & "00"; v.sync_write(v.use_ahb) := '1'; v.cnt := v.cnt +2; v.cmdDone(v.use_ahb) := v.use_buf; if v.use_cas = '0' then -- Cas 2 or 3 v.sync_wdata((2*dqsize)-1 downto 0) := dq1_i & dq2_i; else -- Cas 2.5 v.sync_wdata((2*dqsize)-1 downto 0) := dq2_i & dq1del_i; end if; v.rwstate := r; end if; -- Write when w => v.dqs1_o := '1';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -