------------------------------------------------------------------------------- -- -- This VHDL design file is an open design; you can redistribute it and/or -- modify it and/or implement it under the terms of the Openip General Public -- License as it is going to be published by the OpenIP Organization and any -- coming versions of this license. -- You can check the draft license at -- http://www.opencores.org/OIPC/license.shtml -- ------------------------------------------------------------------------ ------------------------------------------------------------------------------- -- Title : Parameterisable DRAM model -- Project : Versatile Soft-Core Framework (VSCF) ------------------------------------------------------------------------------- -- File : d01bhv01.vhdl -- Author : Damon P Thompson-- Company : The University of Edinburgh -- Last update : 1999/08/23 -- Platform : GENERIC ------------------------------------------------------------------------------- -- Description : -- Parameterisable DRAM model, i.e. scalable data and address widths. -- Simulation assertions can be toggled on/off. -- Uses !RAS/!CAS control sequence for modelling DRAM activity. -- Refresh is monitored with data corrupted to "UU ... " -- ------------------------------------------------------------------------------- -- Modification history : -- Created about 2 years ago, and I can't really remember -- -------------------------------------+----------------------------------------- -- | LIBRARY IEEE, ARITH_LIB, VSCF; -- | USE IEEE.std_logic_1164.ALL; -- | -- | -------------------------------------+----------------------------------------- ENTITY dram_cfg IS generic ( assertions : boolean := true; -- Toggle assertions ON/OFF data_width : integer := 8; -- Data I/O bus width adrs_width : integer := 20 -- Address " " - must be EVEN ); port ( ras, cas, wrt : in std_logic; adrs_bus : in std_logic_vector((((adrs_width)/2)-1) downto 0); data_bus : inout std_logic_vector((data_width-1) downto 0) ); end dram_cfg; ARCHITECTURE simulate OF dram_cfg IS -- DRAM timing specification constant t_ref_max : time := 7.5 uS; -- max. refresh cycle time constant t_cac_max : time := 30 nS; -- max. access time after !CAS constant t_rac_max : time := 120 nS; -- max. access time after !RAS constant t_off_max : time := 30 nS; -- max. o/p diable after !CAS constant t_ras_min : time := 120 nS; -- min. !RAS low pulse width constant t_ras_max : time := 10 uS; -- max. !RAS low pulse width constant t_cas_min : time := 30 nS; -- min. !CAS low pulse width constant t_cas_max : time := 10 uS; -- max. !CAS low pulse width constant t_rps_min : time := 90 nS; -- min. !RAS high pulse width constant t_cps_min : time := 35 nS; -- min. !CAS high pulse width constant t_rcd_min : time := 25 nS; -- min. !RAS low to !CAS low constant t_rcd_max : time := 90 nS; -- max. !RAS low to !CAS low constant t_crp_min : time := 10 nS; -- min. !CAS high to !RAS low constant t_csr_min : time := 10 nS; -- min. !CAS low to !RAS low constant t_chr_min : time := 25 nS; -- min. !RAS low to !CAS high -- Define memory array according to the 'adrs_width' GENERIC parameter type memory is array (0 to ((2**adrs_width)-1)) of std_logic_vector((data_width-1) downto 0); -- Define states for !RAS/!CAS DRAM model type dram_states is ( idle_11, r_01, rc_00, rcc_01, c_10, cr_00, crc_01, crr_10 ); -- Some required type conversion procedures PROCEDURE int_to_vec( int_arg : IN INTEGER; vec_rslt : OUT STD_LOGIC_VECTOR) IS variable tmp_int : integer; variable tmp_vec : std_logic_vector(vec_rslt'range); begin tmp_int := int_arg; for i in 0 to (vec_rslt'LENGTH - 1) loop if(tmp_int mod 2 = 1) then tmp_vec(i) := '1'; else tmp_vec(i) := '0'; end if; tmp_int := tmp_int / 2; end loop; vec_rslt := tmp_vec; end int_to_vec; PROCEDURE vec_to_int( vec_arg : IN STD_LOGIC_VECTOR; int_rslt : OUT INTEGER) IS variable tmp_int : integer := 0; begin for i in vec_arg'range loop if(vec_arg(i) = '1') then tmp_int := tmp_int + 2**i; end if; end loop; int_rslt := tmp_int; end vec_to_int; begin ras_cas_control : process(ras, cas) variable dram_state : dram_states; variable dram : memory; variable refresh_adrs : integer range 0 to ((2**adrs_width)-1) := 0; variable dram_vec_adrs : std_logic_vector((adrs_width-1) downto 0); variable dram_int_adrs : integer range 0 to ((2**adrs_width)-1) := 0; variable last_refresh, t_rh, t_rl, t_ch, t_cl : time := 0 ns; begin case dram_state is when idle_11 => if(ras'EVENT and ras = '0' and cas = '1') then t_rl := NOW; -- following read|write operation expected -- read row address from address bus if assertions then assert(NOW - t_rh >= t_rps_min) report "[idle_11] !RAS low too soon after !RAS high" severity error; assert(NOW - t_ch >= t_crp_min) report "[idle_11] !RAS low too soon after !CAS high" severity warning; end if; -- assertions dram_vec_adrs((adrs_width-1) downto (adrs_width/2)) := adrs_bus; dram_state := r_01; elsif(cas'EVENT and ras = '1' and cas = '0') then t_cl := NOW; -- following !CAS before !RAS refresh expected if assertions then assert(NOW - t_ch >= t_cps_min) report "[idle_11] !CAS low too soon after !CAS high" severity warning; end if; -- assertions dram_state := c_10; end if; when r_01 => if(ras'EVENT and ras = '1' and cas = '1') then t_rh := NOW; -- possible !CAS DRAM multiplexing occurred if assertions then assert(NOW - t_rl >= t_ras_min) report "[r_01] !RAS high too soon after !RAS low" severity warning; assert(NOW - t_rl <= t_ras_max) report "[r_01] !RAS high too late after !RAS low" severity warning; end if; -- assertions dram_state := idle_11; elsif(cas'EVENT and ras = '0' and cas = '0') then t_cl := NOW; -- read clomn address from address bus -- perform read|write operation if assertions then assert(NOW - t_rl >= t_rcd_min) report "[r_01] !CAS low too soon after !RAS low" severity warning; assert(NOW - t_rl <= t_rcd_max) report "[r_01] !CAS low too late after !RAS low" severity warning; end if; -- assertions dram_vec_adrs(((adrs_width/2)-1) downto 0) := adrs_bus; vec_to_int(dram_vec_adrs, dram_int_adrs); case wrt is when '0' => -- perform write operation dram(dram_int_adrs) := data_bus; when '1' => -- perform read operation data_bus <= dram(dram_int_adrs) after t_cac_max; when others => -- !WRT input is undefined...! if assertions then assert false report "[r_01] !WRT is undefined...!" severity warning; end if; -- assertions end case; dram_state := rc_00; end if; when rc_00 => if(ras'EVENT and ras = '1' and cas = '0') then -- ERROR...! Illegal !RAS event assert false report "[rc_00] Illegal !RAS event...! STOP...!" severity error; elsif(cas'EVENT and ras = '0' and cas = '1') then t_ch := NOW; data_bus <= (others => 'Z') after t_off_max; if assertions then assert(NOW - t_cl >= t_cas_min) report "[rc_00] !CAS high too soon after !CAS low" severity warning; assert(NOW - t_cl <= t_cas_max) report "[rc_00] !CAS high too late after !CAS low" severity warning; end if; -- assertions dram_state := rcc_01; end if; when rcc_01 => if(ras'EVENT and ras = '1' and cas = '1') then t_rh := NOW; if assertions then assert(NOW - t_rl >= t_ras_min) report "[rcc_01] !RAS high too soon after !RAS low" severity warning; assert(NOW - t_rl <= t_ras_max) report "[rcc_01] !RAS high too late after !RAS low" severity warning; end if; -- assertions dram_state := idle_11; elsif(cas'EVENT and ras = '0' and cas = '0') then -- ERROR...! Illegal !CAS event assert false report "[rcc_01] Illegal !CAS event...! STOP...!" severity error; end if; when c_10 => if(ras'EVENT and ras = '0' and cas = '0') then t_rl := NOW; -- perform !CAS before !RAS refresh operation refresh_adrs := refresh_adrs + 1; if assertions then assert(NOW - t_cl >= t_csr_min) report "[c_10] !RAS low too soon after !CAS low" severity warning; assert(NOW - t_rh >= t_rps_min) report "[c_10] !RAS low too soon after !RAS high" severity warning; end if; -- assertions refresh_adrs := (refresh_adrs + 1) mod ((2**adrs_width)-1); dram_state := cr_00; elsif(cas'EVENT and ras = '1' and cas = '1') then -- possible !RAS DRAM multiplexing occurred if assertions then assert(NOW - t_cl >= t_cas_min) report "[c_10] !CAS high too soon after !CAS low" severity warning; assert(NOW - t_cl <= t_cas_max) report "[c_10]!CAS high too late after !CAS low" severity warning; end if; -- assertions dram_state := idle_11; end if; when cr_00 => if(ras'EVENT and ras = '1' and cas = '0') then t_rh := NOW; if assertions then assert(NOW - t_rl >= t_ras_min) report "[cr_00] !RAS high too soon after !RAS low" severity warning; assert(NOW - t_rl <= t_ras_max) report "[cr_00] !RAS high too late after !RAS low" severity warning; end if; -- assertions dram_state := crr_10; elsif(cas'EVENT and ras = '0' and cas = '1') then t_ch := NOW; if assertions then assert(NOW - t_cl >= t_cas_min) report "[cr_00] !CAS high too soon after !CAS low" severity warning; assert(NOW - t_cl <= t_cas_max) report "[cr_00] !CAS high too late after !CAS low" severity warning; assert(NOW - t_rl >= t_chr_min) report "[cr_00] !CAS high too soon after !RAS low" severity warning; end if; -- assertions dram_state := crc_01; end if; when crr_10 => if(ras'EVENT and ras = '0' and cas = '0') then -- ERROR...! Illegal !RAS event assert false report "[crr_01] Illegal !RAS event...! STOP...!" severity error; elsif(cas'EVENT and ras = '1' and cas = '1') then t_ch := NOW; if assertions then assert(NOW - t_cl >= t_cas_min) report "[crr_10] !CAS high too soon after !CAS low" severity warning; assert(NOW - t_cl <= t_cas_max) report "[crr_10] !CAS high too late after !CAS low" severity warning; end if; -- assertions dram_state := idle_11; end if; when crc_01 => if(ras'EVENT and ras = '1' and cas = '1') then t_rh := NOW; if assertions then assert(NOW - t_rl >= t_ras_min) report "[crc_01] !RAS high too soon after !RAS low" severity warning; assert(NOW - t_rl <= t_ras_max) report "[crc_01] !RAS high too late after !RAS low" severity warning; end if; -- assertions dram_state := idle_11; elsif(cas'EVENT and ras = '0' and cas = '0') then -- ERROR...! Illegal !CAS event assert false report "[crc_01] Illegal !CAS event...! STOP...!" severity warning; end if; when others => null; end case; -- dram_state -- refresh monitor if(NOW - last_refresh > t_ref_max) then dram(refresh_adrs) := (others => 'U'); refresh_adrs := refresh_adrs + 1; if assertions then assert false report "[ref_mon] Too long since last refresh...! Amnesia...!" severity warning; end if; -- assertions last_refresh := NOW; -- or at least it should have been end if; -- refresh monitor end process ras_cas_control; end simulate;