-- Copyright (C) 1988-2004 Altera Corporation -- Any megafunction design, and related netlist (encrypted or decrypted), -- support information, device programming or simulation file, and any other -- associated documentation or information provided by Altera or a partner -- under Altera's Megafunction Partnership Program may be used only -- to program PLD devices (but not masked PLD devices) from Altera. Any -- other use of such megafunction design, netlist, support information, -- device programming or simulation file, or any other related documentation -- or information is prohibited for any other purpose, including, but not -- limited to modification, reverse engineering, de-compiling, or use with -- any other silicon devices, unless such use is explicitly licensed under -- a separate agreement with Altera or a megafunction partner. Title to the -- intellectual property, including patents, copyrights, trademarks, trade -- secrets, or maskworks, embodied in any such megafunction design, netlist, -- support information, device programming or simulation file, or any other -- related documentation or information provided by Altera or a megafunction -- partner, remains with Altera, the megafunction partner, or their respective -- licensors. No other licenses, including any licenses needed under any third -- party's intellectual property, are provided herein. -- Quartus II 4.0 Build 214 1/28/2004 ---START_PACKAGE_HEADER----------------------------------------------------- -- -- Package Name : ALTERA_DEVICE_FAMILIES -- -- Description : Common Altera device families comparison -- ---END_PACKAGE_HEADER-------------------------------------------------------- -- BEGINING OF PRIMITIVES Library ieee; use ieee.std_logic_1164.all; entity LCELL is port( a_in : in std_logic; a_out : out std_logic); end LCELL; architecture BEHAVIOR of LCELL is begin a_out <= a_in; end BEHAVIOR; Library ieee; use ieee.std_logic_1164.all; entity GLOBAL is port( a_in : in std_logic; a_out : out std_logic); end GLOBAL; architecture BEHAVIOR of GLOBAL is begin a_out <= a_in; end BEHAVIOR; Library ieee; use ieee.std_logic_1164.all; entity CARRY is port( a_in : in std_logic; a_out : out std_logic); end CARRY; architecture BEHAVIOR of CARRY is begin a_out <= a_in; end BEHAVIOR; Library ieee; use ieee.std_logic_1164.all; entity CASCADE is port( a_in : in std_logic; a_out : out std_logic); end CASCADE; architecture BEHAVIOR of CASCADE is begin a_out <= a_in; end BEHAVIOR; Library ieee; use ieee.std_logic_1164.all; entity CARRY_SUM is port( sin : in std_logic; cin : in std_logic; sout : out std_logic; cout : out std_logic); end CARRY_SUM; architecture BEHAVIOR of CARRY_SUM is begin sout <= sin; cout <= cin; end BEHAVIOR; Library ieee; use ieee.std_logic_1164.all; entity EXP is port( a_in : in std_logic; a_out : out std_logic); end EXP; architecture BEHAVIOR of EXP is begin a_out <= not a_in; end BEHAVIOR; -- BEGINING OF PACKAGES Library ieee; use ieee.std_logic_1164.all; -- PACKAGE DECLARATION package ALTERA_DEVICE_FAMILIES is -- FUNCTION DECLARATION function IS_VALID_FAMILY (device: in string) return boolean; function IS_FAMILY_APEX20K (device : in string) return boolean; function IS_FAMILY_APEX20KE (device : in string) return boolean; function IS_FAMILY_APEXII (device : in string) return boolean; function IS_FAMILY_ACEX2K (device : in string) return boolean; function IS_FAMILY_STRATIXGX (device : in string) return boolean; function IS_FAMILY_STRATIX (device : in string) return boolean; function IS_FAMILY_STRATIXHC (device : in string) return boolean; function IS_FAMILY_MERCURY (device : in string) return boolean; function IS_FAMILY_FLEX10KE (device : in string) return boolean; function IS_FAMILY_FLEX10K (device : in string) return boolean; function IS_FAMILY_FLEX10KA (device : in string) return boolean; function IS_FAMILY_FLEX6000 (device : in string) return boolean; function IS_FAMILY_MAX7000B (device : in string) return boolean; function IS_FAMILY_MAX7000AE (device : in string) return boolean; function IS_FAMILY_MAX3000A (device : in string) return boolean; function IS_FAMILY_MAX7000S (device : in string) return boolean; function IS_FAMILY_MAX7000A (device : in string) return boolean; function IS_FAMILY_STRATIXII (device : in string) return boolean; function IS_FAMILY_MAXII (device : in string) return boolean; end ALTERA_DEVICE_FAMILIES; package body ALTERA_DEVICE_FAMILIES is function IS_VALID_FAMILY (device : in string) return boolean is variable is_valid : boolean := false; begin if (IS_FAMILY_APEX20K(device) or IS_FAMILY_APEX20KE(device) or IS_FAMILY_APEXII( device) or IS_FAMILY_ACEX2K(device) or IS_FAMILY_STRATIXGX(device) or IS_FAMILY_STRATIX(device) or IS_FAMILY_MERCURY(device) or IS_FAMILY_FLEX10KE(device) or IS_FAMILY_FLEX10K(device) or IS_FAMILY_FLEX10KA(device) or IS_FAMILY_FLEX6000(device) or IS_FAMILY_MAX7000B(device) or IS_FAMILY_MAX7000AE(device) or IS_FAMILY_MAX3000A(device) or IS_FAMILY_MAX7000S(device) or IS_FAMILY_MAX7000A(device) or IS_FAMILY_STRATIXII(device) or IS_FAMILY_STRATIXHC(device) or IS_FAMILY_MAXII(device)) then is_valid := true; end if; return is_valid; end IS_VALID_FAMILY; function IS_FAMILY_APEX20K (device : in string) return boolean is variable is_20k : boolean := false; begin if (device = "APEX20K") then is_20k := true; end if; return is_20k; end IS_FAMILY_APEX20K; function IS_FAMILY_APEX20KE (device : in string) return boolean is variable is_20ke : boolean := false; begin if ((device = "APEX20KE") or (device = "APEX20KC") or (device = "EXCALIBUR_ARM") or (device = "EXCALIBUR_MIPS")) then is_20ke := true; end if; return is_20ke; end IS_FAMILY_APEX20KE; function IS_FAMILY_APEXII (device : in string) return boolean is variable is_apexii : boolean := false; begin if ((device = "APEX II") or (device = "APEXII")) then is_apexii := true; end if; return is_apexii; end IS_FAMILY_APEXII; function IS_FAMILY_ACEX2K (device : in string) return boolean is variable is_acex2k : boolean := false; begin if ((device = "CYCLONE") or (device = "Cyclone")) then is_acex2k := true; end if; return is_acex2k; end IS_FAMILY_ACEX2K; function IS_FAMILY_STRATIXGX (device : in string) return boolean is variable is_stratixgx : boolean := false; begin if ((device = "STRATIX-GX") or (device = "STRATIX GX") or (device = "Stratix GX")) then is_stratixgx := true; end if; return is_stratixgx; end IS_FAMILY_STRATIXGX; function IS_FAMILY_STRATIX (device : in string) return boolean is variable is_stratix : boolean := false; begin if ((device = "STRATIX") or (device = "Stratix")) then is_stratix := true; end if; return is_stratix; end IS_FAMILY_STRATIX; function IS_FAMILY_STRATIXHC (device : in string) return boolean is variable is_stratixhc : boolean := false; begin if ((device = "STRATIXHC") or (device = "StratixHC") or (device = "STRATIX HC") or (device = "Stratix HC") or (device = "HardCopy Stratix") or (device = "HARDCOPY STRATIX")) then is_stratixhc := true; end if; return is_stratixhc; end IS_FAMILY_STRATIXHC; function IS_FAMILY_MERCURY (device : in string) return boolean is variable is_mercury : boolean := false; begin if ((device = "MERCURY") or (device = "Mercury")) then is_mercury := true; end if; return is_mercury; end IS_FAMILY_MERCURY; function IS_FAMILY_FLEX10KE (device : in string) return boolean is variable is_flex10ke : boolean := false; begin if ((device = "FLEX10KE") or (device = "FLEX 10KE") or (device = "ACEX1K") or (device = "ACEX 1K")) then is_flex10ke := true; end if; return is_flex10ke; end IS_FAMILY_FLEX10KE; function IS_FAMILY_FLEX10K (device : in string) return boolean is variable is_flex10k : boolean := false; begin if ((device = "FLEX10K") or (device = "flex10k") or (device = "FLEX 10K") or (device = "flex 10k")) then is_flex10k := true; end if; return is_flex10k; end IS_FAMILY_FLEX10K; function IS_FAMILY_FLEX10KA (device : in string) return boolean is variable is_flex10ka : boolean := false; begin if ((device = "FLEX10KA") or (device = "flex10ka") or (device = "FLEX 10KA") or (device = "flex 10ka")) then is_flex10ka := true; end if; return is_flex10ka; end IS_FAMILY_FLEX10KA; function IS_FAMILY_FLEX6000 (device : in string) return boolean is variable is_flex6000 : boolean := false; begin if ((device = "FLEX6000") or (device = "flex6000") or (device = "FLEX 6000") or (device = "flex 6000") or (device = "FLEX6K") or (device = "flex6k")) then is_flex6000 := true; end if; return is_flex6000; end IS_FAMILY_FLEX6000; function IS_FAMILY_MAX7000B (device : in string) return boolean is variable is_max7000b : boolean := false; begin if ((device = "MAX7000B") or (device = "max7000b") or (device = "MAX 7000B") or (device = "max 7000b")) then is_max7000b := true; end if; return is_max7000b; end IS_FAMILY_MAX7000B; function IS_FAMILY_MAX7000AE (device : in string) return boolean is variable is_max7000ae : boolean := false; begin if ((device = "MAX7000AE") or (device = "max7000ae") or (device = "MAX 7000AE") or (device = "max 7000ae")) then is_max7000ae := true; end if; return is_max7000ae; end IS_FAMILY_MAX7000AE; function IS_FAMILY_MAX3000A (device : in string) return boolean is variable is_max3000a : boolean := false; begin if ((device = "MAX3000A") or (device = "max3000a") or (device = "MAX 3000A") or (device = "max 3000a")) then is_max3000a := true; end if; return is_max3000a; end IS_FAMILY_MAX3000A; function IS_FAMILY_MAX7000S (device : in string) return boolean is variable is_max7000s : boolean := false; begin if ((device = "MAX7000S") or (device = "max7000s") or (device = "MAX 7000S") or (device = "max 7000s")) then is_max7000s := true; end if; return is_max7000s; end IS_FAMILY_MAX7000S; function IS_FAMILY_MAX7000A (device : in string) return boolean is variable is_max7000a : boolean := false; begin if ((device = "MAX7000A") or (device = "max7000a") or (device = "MAX 7000A") or (device = "max 7000a")) then is_max7000a := true; end if; return is_max7000a; end IS_FAMILY_MAX7000A; function IS_FAMILY_STRATIXII (device : in string) return boolean is variable is_stratixii : boolean := false; begin if ((device = "Stratix II") or (device = "StratixII")) then is_stratixii := true; end if; return is_stratixii; end IS_FAMILY_STRATIXII; function IS_FAMILY_MAXII (device : in string) return boolean is variable is_maxii : boolean := false; begin if ((device = "MAX II") or (device = "max ii") or (device = "MAXII") or (device = "maxii")) then is_maxii := true; end if; return is_maxii; end IS_FAMILY_MAXII; end ALTERA_DEVICE_FAMILIES; -- END OF PACKAGE ---START_PACKAGE_HEADER----------------------------------------------------- -- -- Package Name : ALTERA_COMMON_CONVERSION -- -- Description : Common conversion functions -- ---END_PACKAGE_HEADER-------------------------------------------------------- -- BEGINING OF PACKAGE Library ieee; use ieee.std_logic_1164.all; use std.textio.all; -- PACKAGE DECLARATION package ALTERA_COMMON_CONVERSION is -- FUNCTION DECLARATION function INT_TO_STR_RAM (value : in integer) return string; function INT_TO_STR_ARITH (value : in integer) return string; function HEX_STR_TO_INT (str : in string) return integer; procedure SHRINK_LINE (str_line : inout line; pos : in integer); end ALTERA_COMMON_CONVERSION; package body ALTERA_COMMON_CONVERSION is -- This function converts an integer to a string function INT_TO_STR_RAM (value : in integer) return string is variable ivalue : integer := 0; variable index : integer := 0; variable digit : integer := 0; variable line_no: string(8 downto 1) := " "; begin ivalue := value; index := 1; while (ivalue > 0) loop digit := ivalue MOD 10; ivalue := ivalue/10; case digit is when 0 => line_no(index) := '0'; when 1 => line_no(index) := '1'; when 2 => line_no(index) := '2'; when 3 => line_no(index) := '3'; when 4 => line_no(index) := '4'; when 5 => line_no(index) := '5'; when 6 => line_no(index) := '6'; when 7 => line_no(index) := '7'; when 8 => line_no(index) := '8'; when 9 => line_no(index) := '9'; when others => ASSERT FALSE REPORT "Illegal number!" SEVERITY ERROR; end case; index := index + 1; end loop; return line_no; end INT_TO_STR_RAM; function INT_TO_STR_ARITH (value : in integer) return string is variable ivalue : integer := 0; variable index : integer := 0; variable digit : integer := 0; variable temp: string(10 downto 1) := "0000000000"; begin ivalue := value; index := 1; while (ivalue > 0) loop digit := ivalue mod 10; ivalue := ivalue/10; case digit is when 0 => temp(index) := '0'; when 1 => temp(index) := '1'; when 2 => temp(index) := '2'; when 3 => temp(index) := '3'; when 4 => temp(index) := '4'; when 5 => temp(index) := '5'; when 6 => temp(index) := '6'; when 7 => temp(index) := '7'; when 8 => temp(index) := '8'; when 9 => temp(index) := '9'; when others => ASSERT FALSE REPORT "Illegal number!" SEVERITY ERROR; end case; index := index + 1; end loop; if value < 0 then return '-'& temp(index downto 1); else return temp(index downto 1); end if; end INT_TO_STR_ARITH; -- This function converts a hexadecimal number to an integer function HEX_STR_TO_INT (str : in string) return integer is variable len : integer := str'length; variable ivalue : integer := 0; variable digit : integer := 0; begin for i in len downto 1 loop case str(i) is when '0' => digit := 0; when '1' => digit := 1; when '2' => digit := 2; when '3' => digit := 3; when '4' => digit := 4; when '5' => digit := 5; when '6' => digit := 6; when '7' => digit := 7; when '8' => digit := 8; when '9' => digit := 9; when 'A' => digit := 10; when 'a' => digit := 10; when 'B' => digit := 11; when 'b' => digit := 11; when 'C' => digit := 12; when 'c' => digit := 12; when 'D' => digit := 13; when 'd' => digit := 13; when 'E' => digit := 14; when 'e' => digit := 14; when 'F' => digit := 15; when 'f' => digit := 15; when others => ASSERT FALSE REPORT "Illegal character "& str(i) & "in Intel Hex File! " SEVERITY ERROR; end case; ivalue := ivalue * 16 + digit; end loop; return ivalue; end HEX_STR_TO_INT; -- This procedure "cuts" the str_line into desired length procedure SHRINK_LINE (str_line : inout line; pos : in integer) is subtype nstring is string(1 to pos); variable str : nstring; begin if (pos >= 1) then read(str_line, str); end if; end; end ALTERA_COMMON_CONVERSION; -- END OF PACKAGE ---START_ENTITY_HEADER--------------------------------------------------------- -- -- Entity Name : altaccumulate -- -- Description : Parameterized accumulator megafunction. The accumulator -- performs an add function or a subtract function based on the add_sub -- parameter. The input data can be signed or unsigned. -- -- Limitation : n/a -- -- Results expected: result - The results of add or subtract operation. Output -- port [width_out-1 .. 0] wide. -- cout - The cout port has a physical interpretation as -- the carry-out (borrow-in) of the MSB. The cout -- port is most meaningful for detecting overflow -- in unsigned operations. The cout port operates -- in the same manner for signed and unsigned -- operations. -- overflow - Indicates the accumulator is overflow. -- ---END_ENTITY_HEADER----------------------------------------------------------- library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; -- BEGINNING OF ENTITY entity altaccumulate is -- GENERIC DECLARATION generic ( width_in : integer := 4; -- Required width_out : integer := 8; -- Required lpm_representation : string := "UNSIGNED"; extra_latency : integer := 0; use_wys : string := "ON"; lpm_hint : string := "UNUSED"; lpm_type : string := "altaccumulate" ); -- PORT DECLARATION port ( -- INPUT PORT DECLARATION cin : in std_logic := 'Z'; data : in std_logic_vector(width_in -1 downto 0); -- Required port add_sub : in std_logic := '1'; clock : in std_logic; -- Required port sload : in std_logic := '0'; clken : in std_logic := '1'; sign_data : in std_logic := '0'; aclr : in std_logic := '0'; -- OUTPUT PORT DECLARATION result : out std_logic_vector(width_out -1 downto 0) := (others => '0'); -- Required port cout : out std_logic := '0'; overflow : out std_logic := '0' ); end altaccumulate; -- END OF ENTITY -- BEGINNING OF ARCHITECTURE architecture behaviour of altaccumulate is -- TYPE DECLARATION type pipeline is array (extra_latency-1 downto 0) of std_logic_vector (width_out+1 downto 0); -- SIGNAL DECLARATION signal temp_sum : std_logic_vector (width_out downto 0) := (others => '0'); signal cout_int : std_logic := '0'; signal overflow_int : std_logic := '0'; signal result_int : std_logic_vector (width_out+1 downto 0) := (others => '0'); signal result_pipe : pipeline := (others => (others => '0')); signal head : integer := 0; begin MSG: process begin if( width_in <= 0 ) then ASSERT FALSE REPORT "Error! Value of width_in parameter must be greater than 0." SEVERITY ERROR; end if; if( width_out <= 0 ) then ASSERT FALSE REPORT "Error! Value of width_out parameter must be greater than 0." SEVERITY ERROR; end if; if( extra_latency > width_out ) then ASSERT FALSE REPORT "Info: Value of extra_latency parameter should be lower than width_out parameter for better performance/utilization." SEVERITY NOTE; end if; if( width_in > width_out ) then ASSERT FALSE REPORT "Error! Value of width_in parameter should be lower than or equal to width_out." SEVERITY ERROR; end if; wait; end process MSG; -- PROCESS DECLARATION ADDSUB : process (data, add_sub, sload, cin, sign_data, result_int (width_out-1 downto 0)) -- VARIABLE DECLARATIOM variable fb_int : std_logic_vector (width_out downto 0) := (others => '0'); variable data_int : std_logic_vector (width_out-1 downto 0) := (others => '0'); variable zeropad : std_logic_vector ((width_out - width_in)-1 downto 0) := (others => '0'); variable temp_sum_int : std_logic_vector (width_out downto 0) := (others => '0'); variable cout_temp, borrow : std_logic; variable result_full : std_logic_vector (width_out downto 0); variable temp_sum_zero : std_logic_vector (width_out downto 0) := (others => '0'); variable cin_int : std_logic; begin if ((LPM_REPRESENTATION = "SIGNED") or (sign_data = '1')) then zeropad := (others => data (width_in-1)); else zeropad := (others => '0'); end if; if (sload = '1') then fb_int := (others => '0'); else fb_int := ('0' & result_int (width_out-1 downto 0)); end if; if ((data (0) = '1') or (data (0) = '0')) then data_int := (zeropad & data); end if; -- If cin is omitted (i.e. cin = 'z'), cin default is 0 for add operation -- and 1 for subtract operation. if ((cin /= '0') and (cin /= '1')) then cin_int := not add_sub; else cin_int := cin; end if; if (sload = '1') then temp_sum_int := unsigned(temp_sum_zero) + unsigned(data_int); else if (add_sub = '1') then temp_sum_int := unsigned(temp_sum_zero) + unsigned(fb_int) + unsigned(data_int) + cin_int; cout_temp := temp_sum_int(width_out); else borrow := not cin_int; if ((borrow /= '1') and (borrow /= '0')) then borrow := '0'; end if; temp_sum_int := unsigned(temp_sum_zero) + unsigned (fb_int) - unsigned (data_int) - borrow; result_full := unsigned(temp_sum_zero) + unsigned(data_int) + borrow; if (fb_int >= result_full) then cout_temp :='1'; else cout_temp :='0'; end if; end if; end if; if (sload = '0') then if ((LPM_REPRESENTATION = "SIGNED") or (sign_data = '1')) then overflow_int <= ((not (data (width_in-1) xor result_int (width_out -1))) xor (not (add_sub))) and (result_int (width_out -1) xor temp_sum_int (width_out -1)); else overflow_int <= not (add_sub xor cout_temp); end if; else overflow_int <= '0'; cout_temp := not add_sub; end if; cout_int <= cout_temp; temp_sum <= temp_sum_int; end process ADDSUB; ACC: process (clock, aclr, cout_int) -- VARIABLE DECLARATIOM variable head_pipe : integer; variable full_res: std_logic_vector (width_out+1 downto 0); begin head_pipe := head; if (aclr = '1') then result <= (others => '0'); result_int <= (others => '0'); cout <= '0'; overflow <= '0'; result_pipe <= (others => (others => '0')); else if (extra_latency = 0) then cout <= cout_int; end if; if (clock'event and (clock = '1' and clken = '1')) then if (extra_latency > 0) then result_pipe (head_pipe) <= (result_int (width_out+1) & cout_int & result_int (width_out-1 downto 0)); head_pipe := (head_pipe + 1) mod (extra_latency); if (head_pipe = head) then full_res := (result_int (width_out+1) & cout_int & result_int (width_out-1 downto 0)); else full_res := result_pipe (head_pipe); end if; cout <= full_res (width_out); result <= full_res (width_out-1 downto 0); overflow <= full_res (width_out+1); else overflow <= overflow_int; result <= temp_sum (width_out-1 downto 0); end if; result_int <= (overflow_int & cout_int & temp_sum (width_out-1 downto 0)); end if; end if; head <= head_pipe; end process ACC; end behaviour; -- End behaviour of altaccumulate -- END OF ARCHITECTURE -- -------------------------------------------------------------------------- -- Module Name : altmult_accum -- -- Description : a*b + x (MAC) -- -- Limitation : Stratix DSP block -- -- Results expected : signed & unsigned, maximum of 3 pipelines(latency) each. -- -- -------------------------------------------------------------------------- library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; use work.ALTERA_DEVICE_FAMILIES.all; entity altmult_accum is generic ( -- --------------------- -- PARAMETER DECLARATION -- --------------------- width_a : integer := 1; width_b : integer := 1; width_result : integer := 2; width_upper_data : integer := 1; input_source_a : string := "DATAA"; input_source_b : string := "DATAB"; input_reg_a : string := "CLOCK0"; input_aclr_a : string := "ACLR3"; input_reg_b : string := "CLOCK0"; input_aclr_b : string := "ACLR3"; addnsub_reg : string := "CLOCK0"; addnsub_aclr : string := "ACLR3"; addnsub_pipeline_reg : string := "CLOCK0"; addnsub_pipeline_aclr : string := "ACLR3"; accum_direction : string := "ADD"; accum_sload_reg : string := "CLOCK0"; accum_sload_aclr : string := "ACLR3"; accum_sload_pipeline_reg : string := "CLOCK0"; accum_sload_pipeline_aclr : string := "ACLR3"; representation_a : string := "UNSIGNED"; sign_reg_a : string := "CLOCK0"; sign_aclr_a : string := "ACLR3"; sign_pipeline_reg_a : string := "CLOCK0"; sign_pipeline_aclr_a : string := "ACLR3"; representation_b : string := "UNSIGNED"; sign_reg_b : string := "CLOCK0"; sign_aclr_b : string := "ACLR3"; sign_pipeline_reg_b : string := "CLOCK0"; sign_pipeline_aclr_b : string := "ACLR3"; multiplier_reg : string := "CLOCK0"; multiplier_aclr : string := "ACLR3"; output_reg : string := "CLOCK0"; output_aclr : string := "ACLR3"; extra_multiplier_latency : integer := 0; extra_accumulator_latency : integer := 0; dedicated_multiplier_circuitry : string := "AUTO"; dsp_block_balancing : string := "AUTO"; lpm_hint : string := "UNUSED"; lpm_type : string := "altmult_accum"; intended_device_family : string := "Stratix"; multiplier_rounding : string := "NO"; mult_round_aclr : string := "ACLR3"; mult_round_reg : string := "CLOCK0"; multiplier_saturation : string := "NO"; mult_saturation_aclr : string := "ACLR3"; mult_saturation_reg : string := "CLOCK0"; accumulator_rounding : string := "NO"; accum_round_aclr : string := "ACLR3"; accum_round_reg : string := "CLOCK0"; accum_round_pipeline_aclr : string := "ACLR3"; accum_round_pipeline_reg : string := "CLOCK0"; accumulator_saturation : string := "NO"; accum_saturation_aclr : string := "ACLR3"; accum_saturation_reg : string := "CLOCK0"; accum_saturation_pipeline_aclr : string := "ACLR3"; accum_saturation_pipeline_reg : string := "CLOCK0"; accum_sload_upper_data_aclr : string := "ACLR3"; accum_sload_upper_data_pipeline_aclr : string := "ACLR3"; accum_sload_upper_data_pipeline_reg : string := "CLOCK0"; accum_sload_upper_data_reg : string := "CLOCK0"; port_mult_is_saturated : string := "UNUSED"; port_accum_is_saturated : string := "UNUSED" ); port ( -- ---------------- -- PORT DECLARATION -- ---------------- -- input data ports dataa : in std_logic_vector(width_a -1 downto 0); datab : in std_logic_vector(width_b -1 downto 0); scanina : in std_logic_vector(width_a -1 downto 0) := (others => 'Z'); scaninb : in std_logic_vector(width_b -1 downto 0) := (others => 'Z'); accum_sload_upper_data : in std_logic_vector(width_upper_data - 1 downto 0) := (others => '0'); sourcea : in std_logic := '1'; sourceb : in std_logic := '1'; -- control signals addnsub : in std_logic := 'Z'; accum_sload : in std_logic := '0'; signa : in std_logic := 'Z'; signb : in std_logic := 'Z'; -- clock ports clock0 : in std_logic := '1'; clock1 : in std_logic := '1'; clock2 : in std_logic := '1'; clock3 : in std_logic := '1'; -- clock enable ports ena0 : in std_logic := '1'; ena1 : in std_logic := '1'; ena2 : in std_logic := '1'; ena3 : in std_logic := '1'; -- clear ports aclr0 : in std_logic := '0'; aclr1 : in std_logic := '0'; aclr2 : in std_logic := '0'; aclr3 : in std_logic := '0'; -- round and saturation ports mult_round : in std_logic := '0'; mult_saturation : in std_logic := '0'; accum_round : in std_logic := '0'; accum_saturation : in std_logic := '0'; -- output ports result : out std_logic_vector(width_result -1 downto 0) := (others => '0'); overflow : out std_logic :='0'; scanouta : out std_logic_vector (width_a -1 downto 0) := (others => '0'); scanoutb : out std_logic_vector (width_b -1 downto 0) := (others => '0'); mult_is_saturated : out std_logic := '0'; accum_is_saturated : out std_logic := '0' ); end altmult_accum; architecture behaviour of altmult_accum is -- ------------------------------------- -- INTERNAL TEMPLATE DECLARATION -- ------------------------------------- type pipeline_accum is array (extra_accumulator_latency downto 0) of std_logic_vector (width_result downto 0); type pipeline_multi is array (extra_multiplier_latency downto 0) of std_logic_vector (width_a + width_b + 4 + 4 downto 0); type pipeline_sload is array (extra_multiplier_latency downto 0) of std_logic_vector (width_result -1 +4 downto 0); -- ------------------------------------- -- INTERNAL SIGNALS AND TYPE DECLARATION -- ------------------------------------- signal mult_a : std_logic_vector (width_a -1 downto 0):= (others => '0'); signal mult_b : std_logic_vector (width_b -1 downto 0):= (others => '0'); signal mult_res : std_logic_vector (width_a + width_b -1 + 4 downto 0):= (others => '0'); signal acc_sload_reg : std_logic := '0'; signal accum_sload_pipe : std_logic := '0'; signal sign_a_reg : std_logic := '0'; signal sign_a_pipe : std_logic := '0'; signal sign_a_latent : std_logic := '0'; signal sign_b_reg : std_logic := '0'; signal sign_b_pipe : std_logic := '0'; signal sign_b_latent : std_logic := '0'; signal addsub_reg : std_logic := '0'; signal addsub_pipe : std_logic := '0'; signal addsub_latent : std_logic := '0'; signal accum_sload_latent : std_logic := '0'; signal result_pipe : pipeline_accum := (others => (others => '0')); signal mult_pipe : pipeline_multi := (others => (others => '0')); signal sload_upper_data_pipe : pipeline_sload := (others => (others => '0')); signal mult_out_latent : std_logic_vector (width_a + width_b -1 + 4 downto 0):= (others => '0'); signal result_int : std_logic_vector (width_result -1 + 4 downto 0):= (others => '0'); signal temp_mult_zero : std_logic_vector (width_a + width_b downto 0):= (others => '0'); signal mult_full : std_logic_vector (width_a + width_b +4 + 4 downto 0):= (others => '0'); signal mult_signed : std_logic := '0'; signal do_add : std_logic := '0'; signal temp_mult_signed : std_logic := '0'; signal head_result : integer := 0; signal head_mult : integer := 0; signal lower_bits : std_logic_vector (width_result + width_upper_data -1 + 4 downto 0) := (others => '0'); signal sload_upper_data_reg : std_logic_vector (width_result -1 +4 downto 0) := (others => '0'); signal sload_upper_data_latent : std_logic_vector (width_result -1 +4 downto 0) := (others => '0'); signal sload_upper_data_wire : std_logic_vector (width_result -1 +4 downto 0) := (others => '0'); signal sload_upper_data_full : std_logic_vector (width_result -1 +4 downto 0) := (others => '0'); signal mult_is_saturated_wire : std_logic := '0'; signal mult_is_saturated_reg : std_logic := '0'; signal mult_is_saturated_out : std_logic := '0'; signal accum_is_saturated_out : std_logic := '0'; signal mult_round_wire : std_logic := '0'; signal mult_saturate_wire : std_logic := '0'; signal mult_final_out : std_logic_vector (width_a + width_b - 1 + 4 downto 0) := (others => '0'); signal accum_round_pipe_wire : std_logic := '0'; signal accum_round_wire : std_logic := '0'; signal accum_saturation_pipe_wire : std_logic := '0'; signal accum_saturate_wire : std_logic := '0'; begin scanouta <= mult_a; scanoutb <= mult_b; sign_a_latent <= mult_full (width_a + width_b + 4 + 4) when extra_multiplier_latency >0 else sign_a_reg; sign_b_latent <= mult_full (width_a + width_b + 3 + 4) when extra_multiplier_latency >0 else sign_b_reg; accum_sload_latent <= mult_full (width_a + width_b + 2 + 4) when extra_multiplier_latency >0 else acc_sload_reg; addsub_latent <= mult_full (width_a + width_b + 1 + 4) when extra_multiplier_latency >0 else addsub_reg; mult_signed <= mult_full (width_a + width_b + 4) when extra_multiplier_latency >0 else temp_mult_signed; mult_out_latent <= mult_full (width_a + width_b -1 + 4 downto 0) when extra_multiplier_latency >0 else mult_final_out; sload_upper_data_latent <= sload_upper_data_full when extra_multiplier_latency >0 else sload_upper_data_reg; mult_is_saturated <= mult_is_saturated_out when (port_mult_is_saturated = "USED") else '0'; accum_is_saturated <= accum_is_saturated_out when (port_accum_is_saturated = "USED") else '0'; -- Parameter Checking process begin if ((dedicated_multiplier_circuitry /= "AUTO") and (dedicated_multiplier_circuitry /= "YES") and (dedicated_multiplier_circuitry /= "NO")) then assert false report "Error: The DEDICATED_MULTIPLIER_CIRCUITRY parameter is set to an illegal value." severity error; end if; if (width_result < (width_a + width_b)) then assert false report "Error: width_result cannot be less than (width_a + width_b)" severity error; end if; if (width_a <= 0) then assert false report "Error: width_a must be greater than 0." severity error; end if; if (width_b <= 0) then assert false report "Error: width_b must be greater than 0." severity error; end if; if (width_result <= 0) then assert false report "Error: width_result must be greater than 0." severity error; end if; if ((not IS_FAMILY_STRATIXII(intended_device_family)) and (input_source_a /= "DATAA")) then assert false report "Error: The input source for port A are limited to input dataa." severity error; end if; if ((not IS_FAMILY_STRATIXII(intended_device_family)) and (input_source_b /= "DATAB")) then assert false report "Error: The input source for port B are limited to input datab." severity error; end if; if ((not IS_FAMILY_STRATIXII(intended_device_family)) and (multiplier_rounding /= "NO")) then assert false report "Error: There is no rounding feature for non-StratixII device." severity error; end if; if ((not IS_FAMILY_STRATIXII(intended_device_family)) and (accumulator_rounding /= "NO")) then assert false report "Error: There is no rounding feature for non-StratixII device." severity error; end if; if ((not IS_FAMILY_STRATIXII(intended_device_family)) and (multiplier_saturation /= "NO")) then assert false report "Error: There is no saturation feature for non-StratixII device." severity error; end if; if ((not IS_FAMILY_STRATIXII(intended_device_family)) and (accumulator_saturation /= "NO")) then assert false report "Error: There is no saturation feature for non-StratixII device." severity error; end if; wait; end process; -- ---------------------------------------------------------------------------- -- This process contains 1 register and a combinatorial block (to set mult_a) -- The signal registered is dataa -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if input_reg_a is unregistered and -- dataa changes value -- --------------------------------------------------------------------------- process (clock0, clock1, clock2, clock3, aclr0, aclr1, aclr2, aclr3, dataa) begin if (input_reg_a = "UNREGISTERED") then if (input_source_a = "DATAA") then mult_a <= dataa; elsif (input_source_a = "SCANA") then mult_a <= scanina; elsif (input_source_a = "VARIABLE") then if (sourcea = '1') then mult_a <= dataa; else mult_a <= scanina; end if; end if; else if (((input_aclr_a= "ACLR0") and (aclr0 = '1')) or ((input_aclr_a= "ACLR1") and (aclr1 = '1')) or ((input_aclr_a= "ACLR2") and (aclr2 = '1')) or ((input_aclr_a= "ACLR3") and (aclr3 = '1'))) then mult_a <= (others => '0'); elsif (((input_reg_a = "CLOCK0") and (clock0= '1') and clock0'event and (ena0 ='1')) or ((input_reg_a = "CLOCK1") and (clock1= '1') and clock1'event and (ena1 ='1')) or ((input_reg_a = "CLOCK2") and (clock2= '1') and clock2'event and (ena2 ='1')) or ((input_reg_a = "CLOCK3") and (clock3= '1') and clock3'event and (ena3 ='1'))) then if (input_source_a = "DATAA") then mult_a <= dataa; elsif (input_source_a = "SCANA") then mult_a <= scanina; elsif (input_source_a = "VARIABLE") then if (sourcea = '1') then mult_a <= dataa; else mult_a <= scanina; end if; end if; end if; end if; end process; -- ---------------------------------------------------------------------------- -- This process contains 1 register and a combinatorial block (to set mult_b) -- The signal registered is datab -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if input_reg_b is unregistered and -- datab changes value -- --------------------------------------------------------------------------- process (clock0, clock1, clock2, clock3, aclr0, aclr1, aclr2, aclr3, datab) begin if (input_reg_b = "UNREGISTERED") then if (input_source_b = "DATAB") then mult_b <= datab; elsif (input_source_b = "SCANB") then mult_b <= scaninb; elsif (input_source_b = "VARIABLE") then if (sourceb = '1') then mult_b <= datab; else mult_b <= scaninb; end if; end if; else if (((input_aclr_b= "ACLR0") and (aclr0 = '1')) or ((input_aclr_b= "ACLR1") and (aclr1 = '1')) or ((input_aclr_b= "ACLR2") and (aclr2 = '1')) or ((input_aclr_b= "ACLR3") and (aclr3 = '1'))) then mult_b <= (others => '0'); elsif (((input_reg_b = "CLOCK0") and (clock0= '1') and clock0'event and (ena0 ='1')) or ((input_reg_b = "CLOCK1") and (clock1= '1') and clock1'event and (ena1 ='1')) or ((input_reg_b = "CLOCK2") and (clock2= '1') and clock2'event and (ena2 ='1')) or ((input_reg_b = "CLOCK3") and (clock3= '1') and clock3'event and (ena3 ='1'))) then if (input_source_b = "DATAB") then mult_b <= datab; elsif (input_source_b = "SCANB") then mult_b <= scaninb; elsif (input_source_b = "VARIABLE") then if (sourceb = '1') then mult_b <= datab; else mult_b <= scaninb; end if; end if; end if; end if; end process; -- ------------------------------------------------------------------------------ -- This process contains 1 register and a combinatorial block (to set addsub_reg) -- The signal registered is addnsub -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if addnsub_reg is unregistered and -- addnsub changes value -- ------------------------------------------------------------------------------ process (clock0, clock1, clock2, clock3, aclr0, aclr1, aclr2, aclr3, addnsub) begin if (addnsub_reg = "UNREGISTERED") then addsub_reg <= addnsub; else if (((addnsub_aclr= "ACLR0") and (aclr0 = '1')) or ((addnsub_aclr= "ACLR1") and (aclr1 = '1')) or ((addnsub_aclr= "ACLR2") and (aclr2 = '1')) or ((addnsub_aclr= "ACLR3") and (aclr3 = '1'))) then addsub_reg <= '0'; elsif (((addnsub_reg = "CLOCK0") and (clock0= '1') and clock0'event and (ena0 ='1')) or ((addnsub_reg = "CLOCK1") and (clock1= '1') and clock1'event and (ena1 ='1')) or ((addnsub_reg = "CLOCK2") and (clock2= '1') and clock2'event and (ena2 ='1')) or ((addnsub_reg = "CLOCK3") and (clock3= '1') and clock3'event and (ena3 ='1'))) then addsub_reg <= addnsub; end if; end if; end process; -- ------------------------------------------------------------------------------------ -- This process contains 1 register and a combinatorial block (to set addsub_pipe) -- The signal registered is addnsub_latent -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if addnsub_pipeline_reg is unregistered and -- addsub_latent changes value -- ------------------------------------------------------------------------------------ process (clock0, clock1, clock2, clock3, aclr0, aclr1, aclr2, aclr3, addsub_latent) begin if (addnsub_pipeline_reg = "UNREGISTERED") then addsub_pipe <= addsub_latent; else if (((addnsub_pipeline_aclr= "ACLR0") and (aclr0 = '1')) or ((addnsub_pipeline_aclr= "ACLR1") and (aclr1 = '1')) or ((addnsub_pipeline_aclr= "ACLR2") and (aclr2 = '1')) or ((addnsub_pipeline_aclr= "ACLR3") and (aclr3 = '1'))) then addsub_pipe <= '0'; elsif (((addnsub_pipeline_reg = "CLOCK0") and (clock0= '1') and clock0'event and (ena0 ='1')) or ((addnsub_pipeline_reg = "CLOCK1") and (clock1= '1') and clock1'event and (ena1 ='1')) or ((addnsub_pipeline_reg = "CLOCK2") and (clock2= '1') and clock2'event and (ena2 ='1')) or ((addnsub_pipeline_reg = "CLOCK3") and (clock3= '1') and clock3'event and (ena3 ='1'))) then addsub_pipe <= addsub_latent; end if; end if; end process; -- --------------------------------------------------------------------------------- -- This process contains 1 register and a combinatorial block (to set acc_sload_reg) -- The signal registered is accum_sload -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if accum_sload_reg is unregistered and -- accum_sload changes value -- --------------------------------------------------------------------------------- process (clock0, clock1, clock2, clock3, aclr0, aclr1, aclr2, aclr3, accum_sload) begin if (accum_sload_reg = "UNREGISTERED") then acc_sload_reg <= accum_sload; else if (((accum_sload_aclr= "ACLR0") and (aclr0 = '1')) or ((accum_sload_aclr= "ACLR1") and (aclr1 = '1')) or ((accum_sload_aclr= "ACLR2") and (aclr2 = '1')) or ((accum_sload_aclr= "ACLR3") and (aclr3 = '1'))) then acc_sload_reg <= '0'; elsif (((accum_sload_reg = "CLOCK0") and (clock0= '1') and clock0'event and (ena0 ='1')) or ((accum_sload_reg = "CLOCK1") and (clock1= '1') and clock1'event and (ena1 ='1')) or ((accum_sload_reg = "CLOCK2") and (clock2= '1') and clock2'event and (ena2 ='1')) or ((accum_sload_reg = "CLOCK3") and (clock3= '1') and clock3'event and (ena3 ='1'))) then acc_sload_reg <= accum_sload; end if; end if; end process; -- ------------------------------------------------------------------------------------ -- This process contains 1 register and a combinatorial block (to set accum_sload_pipe) -- The signal registered is accum_sload_latent -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if accum_sload_pipeline_reg -- is unregistered and accum_sload_latent changes value -- ------------------------------------------------------------------------------------ process (clock0, clock1, clock2, clock3, aclr0, aclr1, aclr2, aclr3, accum_sload_latent) begin if (accum_sload_pipeline_reg = "UNREGISTERED") then accum_sload_pipe <= accum_sload_latent; else if (((accum_sload_pipeline_aclr = "ACLR0") and (aclr0 = '1')) or ((accum_sload_pipeline_aclr = "ACLR1") and (aclr1 = '1')) or ((accum_sload_pipeline_aclr = "ACLR2") and (aclr2 = '1')) or ((accum_sload_pipeline_aclr = "ACLR3") and (aclr3 = '1'))) then accum_sload_pipe <= '0'; elsif (((accum_sload_pipeline_reg = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((accum_sload_pipeline_reg = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((accum_sload_pipeline_reg = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((accum_sload_pipeline_reg = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1'))) then accum_sload_pipe <= accum_sload_latent; end if; end if; end process; -- ------------------------------------------------------------------------------ -- This process contains 1 register and a combinatorial block (to set sign_a_reg) -- The signal registered is signa -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if sign_reg_a is unregistered and -- signa changes value -- ------------------------------------------------------------------------------ process (clock0, clock1, clock2, clock3, aclr0, aclr1, aclr2, aclr3, signa) begin if (sign_reg_a = "UNREGISTERED") then sign_a_reg <= signa; else if (((sign_aclr_a= "ACLR0") and (aclr0 = '1')) or ((sign_aclr_a= "ACLR1") and (aclr1 = '1')) or ((sign_aclr_a= "ACLR2") and (aclr2 = '1')) or ((sign_aclr_a= "ACLR3") and (aclr3 = '1'))) then sign_a_reg <= '0'; elsif (((sign_reg_a = "CLOCK0") and (clock0= '1') and clock0'event and (ena0 ='1')) or ((sign_reg_a = "CLOCK1") and (clock1= '1') and clock1'event and (ena1 ='1')) or ((sign_reg_a = "CLOCK2") and (clock2= '1') and clock2'event and (ena2 ='1')) or ((sign_reg_a = "CLOCK3") and (clock3= '1') and clock3'event and (ena3 ='1'))) then sign_a_reg <= signa; end if; end if; end process; -- ------------------------------------------------------------------------------ -- This process contains 1 register and a combinatorial block (to set sign_b_reg) -- The signal registered is signb -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if sign_reg_b is unregistered and -- signb changes value -- ------------------------------------------------------------------------------ process (clock0, clock1, clock2, clock3, aclr0, aclr1, aclr2, aclr3, signb) begin if sign_reg_b= "UNREGISTERED" then sign_b_reg <= signb; else if (((sign_aclr_b= "ACLR0") and (aclr0 = '1')) or ((sign_aclr_b= "ACLR1") and (aclr1 = '1')) or ((sign_aclr_b= "ACLR2") and (aclr2 = '1')) or ((sign_aclr_b= "ACLR3") and (aclr3 = '1'))) then sign_b_reg <= '0'; elsif (((sign_reg_b = "CLOCK0") and (clock0= '1') and clock0'event and (ena0 ='1')) or ((sign_reg_b = "CLOCK1") and (clock1= '1') and clock1'event and (ena1 ='1')) or ((sign_reg_b = "CLOCK2") and (clock2= '1') and clock2'event and (ena2 ='1')) or ((sign_reg_b = "CLOCK3") and (clock3= '1') and clock3'event and (ena3 ='1'))) then sign_b_reg <= signb; end if; end if; end process; -- ------------------------------------------------------------------------------- -- This process contains 1 register and a combinatorial block (to set sign_a_pipe) -- The signal registered is sign_a_latent -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if sign_pipeline_reg_a -- is unregistered and sign_a_latent changes value -- ------------------------------------------------------------------------------- process (clock0, clock1, clock2, clock3, aclr0, aclr1, aclr2, aclr3, sign_a_latent) begin if (sign_pipeline_reg_a = "UNREGISTERED") then sign_a_pipe <= sign_a_latent; else if (((sign_pipeline_aclr_a= "ACLR0") and (aclr0 = '1')) or ((sign_pipeline_aclr_a= "ACLR1") and (aclr1 = '1')) or ((sign_pipeline_aclr_a= "ACLR2") and (aclr2 = '1')) or ((sign_pipeline_aclr_a= "ACLR3") and (aclr3 = '1'))) then sign_a_pipe <= '0'; elsif (((sign_pipeline_reg_a = "CLOCK0") and (clock0= '1') and clock0'event and (ena0 ='1')) or ((sign_pipeline_reg_a = "CLOCK1") and (clock1= '1') and clock1'event and (ena1 ='1')) or ((sign_pipeline_reg_a = "CLOCK2") and (clock2= '1') and clock2'event and (ena2 ='1')) or ((sign_pipeline_reg_a = "CLOCK3") and (clock3= '1') and clock3'event and (ena3 ='1'))) then sign_a_pipe <= sign_a_latent; end if; end if; end process; -- ------------------------------------------------------------------------------- -- This process contains 1 register and a combinatorial block (to set sign_b_pipe) -- The signal registered is sign_b_latent -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if sign_pipeline_reg_b -- is unregistered and sign_b_latent changes value -- ------------------------------------------------------------------------------- process (clock0, clock1, clock2, clock3, aclr0, aclr1, aclr2, aclr3, sign_b_latent) begin if (sign_pipeline_reg_b = "UNREGISTERED") then sign_b_pipe <= sign_b_latent; else if (((sign_pipeline_aclr_b= "ACLR0") and (aclr0 = '1')) or ((sign_pipeline_aclr_b= "ACLR1") and (aclr1 = '1')) or ((sign_pipeline_aclr_b= "ACLR2") and (aclr2 = '1')) or ((sign_pipeline_aclr_b= "ACLR3") and (aclr3 = '1'))) then sign_b_pipe <= '0'; elsif (((sign_pipeline_reg_b = "CLOCK0") and (clock0= '1') and clock0'event and (ena0 ='1')) or ((sign_pipeline_reg_b = "CLOCK1") and (clock1= '1') and clock1'event and (ena1 ='1')) or ((sign_pipeline_reg_b = "CLOCK2") and (clock2= '1') and clock2'event and (ena2 ='1')) or ((sign_pipeline_reg_b = "CLOCK3") and (clock3= '1') and clock3'event and (ena3 ='1'))) then sign_b_pipe <= sign_b_latent; end if; end if; end process; -- --------------------------------------------------------------------------------- -- This statement contains 1 register and a combinatorial block (to set accum_round_pipe_wire) -- The signal registered is accum_round -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if accum_round_reg -- is unregistered and accum_round changes value ------------------------------------------------------------------------------------- process (clock0, clock1, clock2, clock3, accum_round, aclr0, aclr1, aclr2, aclr3) begin if (accum_round_reg = "UNREGISTERED") then accum_round_pipe_wire <= accum_round; else if (((accum_round_aclr = "ACLR0") and (aclr0 = '1')) or ((accum_round_aclr = "ACLR1") and (aclr1 = '1')) or ((accum_round_aclr = "ACLR2") and (aclr2 = '1')) or ((accum_round_aclr = "ACLR3") and (aclr3 = '1'))) then accum_round_pipe_wire <= '0'; elsif (((accum_round_reg = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((accum_round_reg = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((accum_round_reg = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((accum_round_reg = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1'))) then accum_round_pipe_wire <= accum_round; end if; end if; end process; -- --------------------------------------------------------------------------------- -- This statement contains 1 register and a combinatorial block (to set accum_round_wire) -- The signal registered is accum_round_pipe_wire -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if accum_round_pipeline_reg -- is unregistered and accum_round_pipe_wire changes value ------------------------------------------------------------------------------------- process (clock0, clock1, clock2, clock3, accum_round_pipe_wire, aclr0, aclr1, aclr2, aclr3) begin if (accum_round_pipeline_reg = "UNREGISTERED") then accum_round_wire <= accum_round_pipe_wire; else if (((accum_round_pipeline_aclr = "ACLR0") and (aclr0 = '1')) or ((accum_round_pipeline_aclr = "ACLR1") and (aclr1 = '1')) or ((accum_round_pipeline_aclr = "ACLR2") and (aclr2 = '1')) or ((accum_round_pipeline_aclr = "ACLR3") and (aclr3 = '1'))) then accum_round_wire <= '0'; elsif (((accum_round_pipeline_reg = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((accum_round_pipeline_reg = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((accum_round_pipeline_reg = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((accum_round_pipeline_reg = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1'))) then accum_round_wire <= accum_round_pipe_wire; end if; end if; end process; -- --------------------------------------------------------------------------------- -- This statement contains 1 register and a combinatorial block (to set accum_saturation_pipe_wire) -- The signal registered is accum_saturation -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if accum_saturation_reg -- is unregistered and accum_saturation changes value -- --------------------------------------------------------------------------------- process (clock0, clock1, clock2, clock3, accum_saturation, aclr0, aclr1, aclr2, aclr3) begin if (accum_saturation_reg = "UNREGISTERED") then accum_saturation_pipe_wire <= accum_saturation; else if (((accum_saturation_aclr = "ACLR0") and (aclr0 = '1')) or ((accum_saturation_aclr = "ACLR1") and (aclr1 = '1')) or ((accum_saturation_aclr = "ACLR2") and (aclr2 = '1')) or ((accum_saturation_aclr = "ACLR3") and (aclr3 = '1'))) then accum_saturation_pipe_wire <= '0'; elsif (((accum_saturation_reg = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((accum_saturation_reg = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((accum_saturation_reg = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((accum_saturation_reg = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1'))) then accum_saturation_pipe_wire <= accum_saturation; end if; end if; end process; -- --------------------------------------------------------------------------------- -- This statement contains 1 register and a combinatorial block (to set accum_saturate_wire) -- The signal registered is accum_saturation_pipe_wire -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if accum_saturation_pipeline_reg -- is unregistered and accum_saturation_pipe_wire changes value -- --------------------------------------------------------------------------------- process (clock0, clock1, clock2, clock3, accum_saturation_pipe_wire, aclr0, aclr1, aclr2, aclr3) begin if (accum_saturation_pipeline_reg = "UNREGISTERED") then accum_saturate_wire <= accum_saturation_pipe_wire; else if (((accum_saturation_pipeline_aclr = "ACLR0") and (aclr0 = '1')) or ((accum_saturation_pipeline_aclr = "ACLR1") and (aclr1 = '1')) or ((accum_saturation_pipeline_aclr = "ACLR2") and (aclr2 = '1')) or ((accum_saturation_pipeline_aclr = "ACLR3") and (aclr3 = '1'))) then accum_saturate_wire <= '0'; elsif (((accum_saturation_pipeline_reg = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((accum_saturation_pipeline_reg = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((accum_saturation_pipeline_reg = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((accum_saturation_pipeline_reg = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1'))) then accum_saturate_wire <= accum_saturation_pipe_wire; end if; end if; end process; -- --------------------------------------------------------------------------------- -- This statement contains 1 register and a combinatorial block (to set mult_round_wire) -- The signal registered is mult_round -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if mult_round_reg -- is unregistered and mult_round changes value -- --------------------------------------------------------------------------------- process (clock0, clock1, clock2, clock3, mult_round, aclr0, aclr1, aclr2, aclr3) begin if (mult_round_reg = "UNREGISTERED") then mult_round_wire <= mult_round; else if (((mult_round_aclr = "ACLR0") and (aclr0 = '1')) or ((mult_round_aclr = "ACLR1") and (aclr1 = '1')) or ((mult_round_aclr = "ACLR2") and (aclr2 = '1')) or ((mult_round_aclr = "ACLR3") and (aclr3 = '1'))) then mult_round_wire <= '0'; elsif (((mult_round_reg = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((mult_round_reg = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((mult_round_reg = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((mult_round_reg = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1'))) then mult_round_wire <= mult_round; end if; end if; end process; -- --------------------------------------------------------------------------------- -- This statement contains 1 register and a combinatorial block (to set mult_saturation_wire) -- The signal registered is mult_saturation -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if mult_saturation_reg -- is unregistered and mult_saturation changes value -- --------------------------------------------------------------------------------- process (clock0, clock1, clock2, clock3, mult_saturation, aclr0, aclr1, aclr2, aclr3) begin if (mult_saturation_reg = "UNREGISTERED") then mult_saturate_wire <= mult_saturation; else if (((mult_saturation_aclr = "ACLR0") and (aclr0 = '1')) or ((mult_saturation_aclr = "ACLR1") and (aclr1 = '1')) or ((mult_saturation_aclr = "ACLR2") and (aclr2 = '1')) or ((mult_saturation_aclr = "ACLR3") and (aclr3 = '1'))) then mult_saturate_wire <= '0'; elsif (((mult_saturation_reg = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((mult_saturation_reg = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((mult_saturation_reg = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((mult_saturation_reg = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1'))) then mult_saturate_wire <= mult_saturation; end if; end if; end process; -- --------------------------------------------------------------------------------- -- This statement contains 1 register and a combinatorial block (to set sload_upper_data_reg) -- The signal registered is accum_sload_upper_data -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if accum_sload_upper_data_reg -- is unregistered and accum_sload_upper_data changes value -- --------------------------------------------------------------------------------- process (clock0, clock1, clock2, clock3, accum_sload_upper_data, aclr0, aclr1, aclr2, aclr3) begin if (accum_sload_upper_data_reg = "UNREGISTERED") then if( width_upper_data > width_result) then sload_upper_data_reg <= accum_sload_upper_data(width_result - 1 downto 0) & lower_bits(3 downto 0); else sload_upper_data_reg <= accum_sload_upper_data & lower_bits(width_result - width_upper_data - 1 + 4 downto 0); end if; else if (((accum_sload_upper_data_aclr = "ACLR0") and (aclr0 = '1')) or ((accum_sload_upper_data_aclr = "ACLR1") and (aclr1 = '1')) or ((accum_sload_upper_data_aclr = "ACLR2") and (aclr2 = '1')) or ((accum_sload_upper_data_aclr = "ACLR3") and (aclr3 = '1'))) then sload_upper_data_reg <= (others => '0'); elsif (((accum_sload_upper_data_reg = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((accum_sload_upper_data_reg = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((accum_sload_upper_data_reg = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((accum_sload_upper_data_reg = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1'))) then if( width_upper_data > width_result) then sload_upper_data_reg <= accum_sload_upper_data(width_result - 1 downto 0) & lower_bits(3 downto 0); else sload_upper_data_reg <= accum_sload_upper_data & lower_bits(width_result - width_upper_data - 1 + 4 downto 0); end if; end if; end if; end process; -- --------------------------------------------------------------------------------- -- This statement contains 1 register and a combinatorial block (to set sload_upper_data_wire) -- The signal registered is sload_upper_data_latent -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if accum_sload_upper_data_pipeline_reg -- is unregistered and sload_upper_data_latent changes value -- --------------------------------------------------------------------------------- process (clock0, clock1, clock2, clock3, sload_upper_data_latent, aclr0, aclr1, aclr2, aclr3) begin if (accum_sload_upper_data_pipeline_reg = "UNREGISTERED") then sload_upper_data_wire <= sload_upper_data_latent; else if (((accum_sload_upper_data_pipeline_aclr = "ACLR0") and (aclr0 = '1')) or ((accum_sload_upper_data_pipeline_aclr = "ACLR1") and (aclr1 = '1')) or ((accum_sload_upper_data_pipeline_aclr = "ACLR2") and (aclr2 = '1')) or ((accum_sload_upper_data_pipeline_aclr = "ACLR3") and (aclr3 = '1'))) then sload_upper_data_wire <= (others => '0'); elsif (((accum_sload_upper_data_pipeline_reg = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((accum_sload_upper_data_pipeline_reg = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((accum_sload_upper_data_pipeline_reg = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((accum_sload_upper_data_pipeline_reg = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1'))) then sload_upper_data_wire <= sload_upper_data_latent; end if; end if; end process; -- ---------------------------------------------------------------------------- -- This block multiplies the two input numbers and sets the result to mult_final_out -- ---------------------------------------------------------------------------- process (mult_a, mult_b, sign_a_reg, sign_b_reg, mult_round_wire, mult_saturate_wire) variable temp_mult_int : std_logic_vector (width_a + width_b downto 0); variable temp_mult : std_logic_vector (width_a + width_b -1 downto 0):= (others => '0'); variable neg_a, neg_b, is_signed : std_logic; variable mult_round_out : std_logic_vector (width_a + width_b - 1 downto 0) := (others => '0'); variable mult_saturate_overflow : std_logic := '0'; variable mult_saturate_out : std_logic_vector (width_a + width_b - 1 + 4 downto 0) := (others => '0'); variable mult_result : std_logic_vector (width_a + width_b - 1 + 4 downto 0) := (others => '0'); variable zero_bits : std_logic_vector (3 downto 0) := (others => '0'); begin is_signed := '0'; if (((representation_a = "SIGNED") and (signa = 'Z')) or (sign_a_reg = '1')) then neg_a := mult_a (width_a-1); is_signed :='1'; end if; if (((representation_b = "SIGNED") and (signb = 'Z')) or (sign_b_reg = '1')) then neg_b := mult_b (width_b-1); is_signed :='1'; end if; if (((representation_a = "SIGNED") and (signa = 'Z')) or (sign_a_reg = '1')) then if (((representation_b = "SIGNED") and( signb = 'Z')) or (sign_b_reg = '1')) then temp_mult_int := signed (temp_mult_zero) + (signed (mult_a) * signed (mult_b)); else temp_mult_int := signed (temp_mult_zero) + (signed (mult_a) * unsigned (mult_b)); end if; else if (((representation_b = "SIGNED") and (signb = 'Z')) or (sign_b_reg = '1')) then temp_mult_int := signed (temp_mult_zero) + (unsigned (mult_a) * signed (mult_b)); else temp_mult_int := signed (temp_mult_zero) + (unsigned (mult_a) * unsigned (mult_b)); end if; end if; temp_mult := temp_mult_int (width_a + width_b -1 downto 0); if (IS_FAMILY_STRATIXII(intended_device_family)) then -- StratixII rounding support -- This is based on both input is in Q1.15 format with assumption -- width_a = 16 and width_b = 16 if ((multiplier_rounding = "YES") or ((multiplier_rounding = "VARIABLE") and (mult_round_wire = '1'))) then mult_round_out := unsigned (temp_mult) + ( 2 ** (width_a + width_b - 18)); else mult_round_out := temp_mult; end if; -- StratixII saturation support if ((multiplier_saturation = "YES") or (( multiplier_saturation = "VARIABLE") and (mult_saturate_wire = '1'))) then if((mult_round_out(width_a + width_b - 1) = '0') and (mult_round_out(width_a + width_b - 2) = '1')) then mult_saturate_overflow := '1'; else mult_saturate_overflow := '0'; end if; if (mult_saturate_overflow = '0') then mult_saturate_out := mult_round_out & zero_bits; else for i in (width_a + width_b - 1 + 4) downto (width_a + width_b - 2 + 4) loop mult_saturate_out(i) := mult_round_out(width_a + width_b - 1); end loop; for i in (width_a + width_b - 3 + 4) downto 0 loop mult_saturate_out(i) := not mult_round_out(width_a + width_b - 1); end loop; for i in 2 downto 0 loop mult_saturate_out(i) := '0'; end loop; end if; else mult_saturate_out := mult_round_out & zero_bits; mult_saturate_overflow := '0'; end if; if ((multiplier_rounding = "YES") or ((multiplier_rounding = "VARIABLE") and (mult_round_wire = '1'))) then mult_result := mult_saturate_out; for i in (width_a + width_b - 18 + 4) downto 0 loop mult_result(i) := '0'; end loop; else mult_result := mult_saturate_out; end if; mult_is_saturated_wire <= mult_saturate_overflow; end if; if (not IS_FAMILY_STRATIXII(intended_device_family)) then mult_final_out <= temp_mult & zero_bits; else mult_final_out <= mult_result; end if; end process; -- ---------------------------------------------------------------------------- -- This process contains 1 register and a combinatorial block (to set mult_res) -- The signal registered is mult_out_latent -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if multiplier_reg -- is unregistered and mult_out_latent changes value -- ---------------------------------------------------------------------------- process (clock0, clock1, clock2, clock3, aclr0, aclr1, aclr2, aclr3, mult_out_latent) begin if (multiplier_reg = "UNREGISTERED") then mult_res <= mult_out_latent; else if (((multiplier_aclr= "ACLR0") and (aclr0 = '1')) or ((multiplier_aclr= "ACLR1") and (aclr1 = '1')) or ((multiplier_aclr= "ACLR2") and (aclr2 = '1')) or ((multiplier_aclr= "ACLR3") and (aclr3 = '1'))) then mult_res <= (others =>'0'); elsif (((multiplier_reg = "CLOCK0") and (clock0= '1') and clock0'event and (ena0 ='1')) or ((multiplier_reg = "CLOCK1") and (clock1= '1') and clock1'event and (ena1 ='1')) or ((multiplier_reg = "CLOCK2") and (clock2= '1') and clock2'event and (ena2 ='1')) or ((multiplier_reg = "CLOCK3") and (clock3= '1') and clock3'event and (ena3 ='1'))) then mult_res <= mult_out_latent; end if; end if; end process; -- ---------------------------------------------------------------------------- -- This process contains 1 register and a combinatorial block (to set mult_is_saturated_reg) -- The signal registered is mult_is_saturated_wire -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if multiplier_reg -- is unregistered and mult_is_saturated_wire changes value -- ---------------------------------------------------------------------------- process (clock0, clock1, clock2, clock3, aclr0, aclr1, aclr2, aclr3, mult_is_saturated_wire) begin if (multiplier_reg = "UNREGISTERED") then mult_is_saturated_reg <= mult_is_saturated_wire; else if (((multiplier_aclr= "ACLR0") and (aclr0 = '1')) or ((multiplier_aclr= "ACLR1") and (aclr1 = '1')) or ((multiplier_aclr= "ACLR2") and (aclr2 = '1')) or ((multiplier_aclr= "ACLR3") and (aclr3 = '1'))) then mult_is_saturated_reg <= '0'; elsif (((multiplier_reg = "CLOCK0") and (clock0= '1') and clock0'event and (ena0 ='1')) or ((multiplier_reg = "CLOCK1") and (clock1= '1') and clock1'event and (ena1 ='1')) or ((multiplier_reg = "CLOCK2") and (clock2= '1') and clock2'event and (ena2 ='1')) or ((multiplier_reg = "CLOCK3") and (clock3= '1') and clock3'event and (ena3 ='1'))) then mult_is_saturated_reg <= mult_is_saturated_wire; end if; end if; end process; process (clock0, clock1, clock2, clock3, aclr0, aclr1, aclr2, aclr3) -- ------------------------------------------------------------------------ -- This process is only valid if extra_multiplier_latency is greater then 0 -- ------------------------------------------------------------------------ variable head_mult_int: integer := 0; -- ------------------------------------------------------------- -- This is the main process block that performs the accumulation -- ------------------------------------------------------------- variable head_result_int : integer := 0; variable temp_sum : std_logic_vector (width_result + 4 downto 0) := (others => '0'); variable result_full : std_logic_vector (width_result downto 0) := (others => '0'); variable cout_int, overflow_int :std_logic; variable temp_sum_zero : std_logic_vector (width_result + 4 downto 0) := (others => '0'); variable accum_int, addsub_int, signed_int : std_logic; variable result_temp : std_logic_vector (width_result -1 + 4 downto 0); variable sign_extend : std_logic_vector (width_result - width_a - width_b -1 downto 0) := (others => '0'); variable mult_res_temp : std_logic_vector (width_result -1 + 4 downto 0) := (others => '0'); variable accum_final_out : std_logic_vector (width_result - 1 + 4 downto 0) := (others => '0'); variable accum_round_out : std_logic_vector (width_result - 1 + 4 downto 0) := (others => '0'); variable accum_saturate_overflow : std_logic := '0'; variable accum_saturate_out : std_logic_vector (width_result - 1 + 4 downto 0) := (others => '0'); variable accum_result_sign_bits : std_logic_vector (width_result - width_a - width_b + 2 - 1 downto 0) := (others => '0'); variable accum_result_sign_bits_ones : std_logic_vector (width_result - width_a - width_b + 2 - 1 downto 0) := (others => '1'); variable accum_result_sign_bits_zeros : std_logic_vector (width_result - width_a - width_b + 2 - 1 downto 0) := (others => '0'); variable accum_result : std_logic_vector (width_result - 1 + 4 downto 0) := (others => '0'); begin -- ------------------------------------------------------------------------ -- This process is only valid if extra_multiplier_latency is greater then 0 -- ------------------------------------------------------------------------ if ( (((multiplier_aclr= "ACLR0") or (multiplier_reg = "UNREGISTERED")) and (aclr0 = '1')) or ((multiplier_reg /= "UNREGISTERED") and ( ((multiplier_aclr= "ACLR1") and (aclr1 = '1')) or ((multiplier_aclr= "ACLR2") and (aclr2 = '1')) or ((multiplier_aclr= "ACLR3") and (aclr3 = '1')) )) ) then mult_pipe <= (others => (others => '0')); mult_full <= (others => '0'); sload_upper_data_full <= (others => '0'); sload_upper_data_pipe <= (others => (others => '0')); elsif ( (((multiplier_reg = "CLOCK0") or (multiplier_reg = "UNREGISTERED")) and (clock0= '1') and clock0'event and (ena0 ='1')) or ((multiplier_reg = "CLOCK1") and (clock1= '1') and clock1'event and (ena1 ='1')) or ((multiplier_reg = "CLOCK2") and (clock2= '1') and clock2'event and (ena2 ='1')) or ((multiplier_reg = "CLOCK3") and (clock3= '1') and clock3'event and (ena3 ='1')) ) then if (extra_multiplier_latency >0) then head_mult_int := head_mult; mult_pipe (head_mult_int) <= sign_a_reg & sign_b_reg & acc_sload_reg & addsub_reg & '0' & mult_final_out; sload_upper_data_pipe (head_mult_int) <= sload_upper_data_reg; head_mult_int := (head_mult_int +1) mod (extra_multiplier_latency); if (extra_multiplier_latency = 1) then mult_full <= sign_a_reg & sign_b_reg & acc_sload_reg & addsub_reg & '0' & mult_final_out; sload_upper_data_full <= sload_upper_data_reg; else mult_full <= (mult_pipe(head_mult_int)); sload_upper_data_full <= (sload_upper_data_pipe(head_mult_int)); end if; head_mult <= head_mult_int; end if; end if; -- ------------------------------------------------------------- -- This is the main process block that performs the accumulation -- ------------------------------------------------------------- if (((output_aclr= "ACLR0") and (aclr0 = '1')) or ((output_aclr= "ACLR1") and (aclr1 = '1')) or ((output_aclr= "ACLR2") and (aclr2 = '1')) or ((output_aclr= "ACLR3") and (aclr3 = '1'))) then temp_sum := (others => '0'); result_pipe <= (others => (others => '0')); result <= (others => '0'); result_int <= (others => '0'); overflow_int := '0'; overflow <= '0'; accum_is_saturated_out <= '0'; mult_is_saturated_out <= '0'; elsif (((output_reg = "CLOCK0") and (clock0= '1') and clock0'event and (ena0 ='1')) or ((output_reg = "CLOCK1") and (clock1= '1') and clock1'event and (ena1 ='1')) or ((output_reg = "CLOCK2") and (clock2= '1') and clock2'event and (ena2 ='1')) or ((output_reg = "CLOCK3") and (clock3= '1') and clock3'event and (ena3 ='1'))) then if (accum_sload = 'Z') then accum_int := '1'; else accum_int := accum_sload_pipe; end if; -- check if addition flag is to be set if (((addnsub = 'Z') and (accum_direction = "ADD")) or (addsub_pipe = '1')) then addsub_int := '1'; else addsub_int := '0'; end if; -- check if signed flag is to be set if ((((representation_b = "SIGNED") and (signb = 'Z')) or (sign_b_pipe = '1')) or (((representation_a = "SIGNED") and (signa = 'Z')) or (sign_a_pipe = '1'))) then signed_int := '1'; else signed_int := '0'; end if; sign_extend := (others => (signed_int and mult_res (width_a + width_b -1 + 4))); mult_res_temp := sign_extend & mult_res; if (accum_int ='1') then if (not IS_FAMILY_STRATIXII(intended_device_family)) then result_temp := (others => '0'); else result_temp := sload_upper_data_wire; end if; else result_temp := result_int; end if; if (addsub_int = '1') then -- add the numbers if the add flag is turned on temp_sum := unsigned(temp_sum_zero)+ unsigned (result_temp) + unsigned (mult_res_temp); cout_int := temp_sum (width_result + 4); else -- subtract the numbers if the add flag is turned off temp_sum := unsigned(temp_sum_zero)+ unsigned (result_temp) - unsigned (mult_res_temp); if (unsigned (result_temp) >= unsigned (mult_res_temp)) then cout_int := '1'; else cout_int := '0'; end if; end if; if (signed_int = '1' and (not (mult_res = temp_mult_zero))) then overflow_int := (((not (mult_res (width_a + width_b-1+4) xor result_temp (width_result -1+4))) xor (not (addsub_int))) and (result_temp (width_result -1+4) xor temp_sum (width_result -1+4))); else overflow_int := not (addsub_int xor cout_int); end if; if (IS_FAMILY_STRATIXII(intended_device_family)) then -- StratixII rounding support -- This is based on both input is in Q1.15 format with assumption -- width_a = 16 and width_b = 16 -- result_width = widht_a + width_b if ((accumulator_rounding = "YES") or ((accumulator_rounding = "VARIABLE") and (accum_round_wire = '1'))) then accum_round_out := temp_sum(width_result -1 + 4 downto 0); accum_round_out := signed (accum_round_out) + ( 2 ** (width_a + width_b - 2 - 15 - 1 + 4)); else accum_round_out := temp_sum(width_result -1 + 4 downto 0); end if; -- StratixII saturation support if ((accumulator_saturation = "YES") or ((accumulator_saturation = "VARIABLE") and (accum_saturate_wire = '1'))) then accum_result_sign_bits := accum_round_out(width_result - 1+4 downto width_a + width_b - 2 + 4); if ((accum_result_sign_bits = accum_result_sign_bits_ones) or (accum_result_sign_bits = accum_result_sign_bits_zeros)) then accum_saturate_overflow := '0'; else accum_saturate_overflow := '1'; end if; if (accum_saturate_overflow = '0') then accum_saturate_out := accum_round_out; else for i in (width_result - 1 + 4) downto (width_a + width_b - 2 + 4) loop accum_saturate_out(i) := accum_round_out(width_result - 1 + 4); end loop; for i in (width_a + width_b - 3 + 4) downto 3 loop accum_saturate_out(i) := not accum_round_out(width_result - 1 + 4); end loop; for i in 2 downto 0 loop accum_saturate_out(i) := '0'; end loop; end if; else accum_saturate_out := accum_round_out; accum_saturate_overflow := '0'; end if; if ((accumulator_rounding = "YES") or ((accumulator_rounding = "VARIABLE") and (accum_round_wire = '1'))) then accum_result := accum_saturate_out; for i in (width_a + width_b - 17 - 1 + 4) downto 0 loop accum_result(i) := '0'; end loop; else accum_result := accum_saturate_out; end if; accum_is_saturated_out <= accum_saturate_overflow; mult_is_saturated_out <= mult_is_saturated_reg; end if; if (not IS_FAMILY_STRATIXII(intended_device_family)) then accum_final_out := temp_sum(width_result -1 + 4 downto 0); else accum_final_out := accum_result; end if; if (extra_accumulator_latency = 0) then result <= accum_final_out(width_result - 1 + 4 downto 4); overflow <= overflow_int; else head_result_int := head_result; result_pipe (head_result_int) <= (overflow_int & accum_final_out(width_result - 1 + 4 downto 4)); head_result_int := (head_result_int +1) mod (extra_accumulator_latency); result_full := result_pipe(head_result_int); result <= result_full (width_result-1 downto 0); overflow <= result_full (width_result); end if; result_int <= accum_final_out; end if; end process; end behaviour; -- end of ALT_MULT_ACCUM ---------------------------------------------------------------------------- -- Module Name : altmult_add -- -- Description : a*b + c*d -- -- Limitation : Stratix DSP block -- -- Results expected : signed & unsigned, maximum of 3 pipelines(latency) each. -- possible of zero pipeline. -- ---------------------------------------------------------------------------- library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; use work.ALTERA_DEVICE_FAMILIES.all; entity altmult_add is generic ( -- --------------------- -- PARAMETER DECLARATION -- --------------------- width_a : integer := 1; width_b : integer := 1; width_result : integer := 1; number_of_multipliers : integer := 1; -- A inputs input_register_a0 : string := "CLOCK0"; input_aclr_a0 : string := "ACLR3"; input_source_a0 : string := "DATAA"; input_register_a1 : string := "CLOCK0"; input_aclr_a1 : string := "ACLR3"; input_source_a1 : string := "DATAA"; input_register_a2 : string := "CLOCK0"; input_aclr_a2 : string := "ACLR3"; input_source_a2 : string := "DATAA"; input_register_a3 : string := "CLOCK0"; input_aclr_a3 : string := "ACLR3"; input_source_a3 : string := "DATAA"; representation_a : string := "UNSIGNED"; signed_register_a : string := "CLOCK0"; signed_aclr_a : string := "ACLR3"; signed_pipeline_register_a : string := "CLOCK0"; signed_pipeline_aclr_a : string := "ACLR3"; -- B inputs input_register_b0 : string := "CLOCK0"; input_aclr_b0 : string := "ACLR3"; input_source_b0 : string := "DATAB"; input_register_b1 : string := "CLOCK0"; input_aclr_b1 : string := "ACLR3"; input_source_b1 : string := "DATAB"; input_register_b2 : string := "CLOCK0"; input_aclr_b2 : string := "ACLR3"; input_source_b2 : string := "DATAB"; input_register_b3 : string := "CLOCK0"; input_aclr_b3 : string := "ACLR3"; input_source_b3 : string := "DATAB"; representation_b : string := "UNSIGNED"; signed_register_b : string := "CLOCK0"; signed_aclr_b : string := "ACLR3"; signed_pipeline_register_b : string := "CLOCK0"; signed_pipeline_aclr_b : string := "ACLR3"; -- Multiplier parameter multiplier_register0 : string := "CLOCK0"; multiplier_aclr0 : string := "ACLR3"; multiplier_register1 : string := "CLOCK0"; multiplier_aclr1 : string := "ACLR3"; multiplier_register2 : string := "CLOCK0"; multiplier_aclr2 : string := "ACLR3"; multiplier_register3 : string := "CLOCK0"; multiplier_aclr3 : string := "ACLR3"; addnsub_multiplier_register1 : string := "CLOCK0"; addnsub_multiplier_aclr1 : string := "ACLR3"; addnsub_multiplier_pipeline_register1 : string := "CLOCK0"; addnsub_multiplier_pipeline_aclr1 : string := "ACLR3"; addnsub_multiplier_register3 : string := "CLOCK0"; addnsub_multiplier_aclr3 : string := "ACLR3"; addnsub_multiplier_pipeline_register3 : string := "CLOCK0"; addnsub_multiplier_pipeline_aclr3 : string := "ACLR3"; multiplier1_direction : string := "ADD"; multiplier3_direction : string := "ADD"; -- output parameters output_register : string := "CLOCK0"; output_aclr : string := "ACLR0"; -- StratixII parameters multiplier01_rounding : string := "NO"; multiplier01_saturation : string := "NO"; mult01_round_aclr : string := "ACLR3"; mult01_round_register : string := "CLOCK0"; mult01_saturation_register : string := "CLOCK0"; mult01_saturation_aclr : string := "ACLR3"; multiplier23_rounding : string := "NO"; multiplier23_saturation : string := "NO"; mult23_round_aclr : string := "ACLR3"; mult23_round_register : string := "CLOCK0"; mult23_saturation_register : string := "CLOCK0"; mult23_saturation_aclr : string := "ACLR3"; adder1_rounding : string := "NO"; adder3_rounding : string := "NO"; addnsub1_round_aclr : string := "ACLR3"; addnsub1_round_pipeline_aclr : string := "ACLR3"; addnsub1_round_register : string := "CLOCK0"; addnsub1_round_pipeline_register : string := "CLOCK0"; addnsub3_round_aclr : string := "ACLR3"; addnsub3_round_pipeline_aclr : string := "ACLR3"; addnsub3_round_register : string := "CLOCK0"; addnsub3_round_pipeline_register : string := "CLOCK0"; port_mult0_is_saturated : string := "UNUSED"; port_mult1_is_saturated : string := "UNUSED"; port_mult2_is_saturated : string := "UNUSED"; port_mult3_is_saturated : string := "UNUSED"; -- General setting parameters extra_latency : integer := 0; dedicated_multiplier_circuitry : string := "AUTO"; dsp_block_balancing : string := "AUTO"; lpm_hint : string := "UNUSED"; lpm_type : string := "altmult_add"; intended_device_family : string := "Stratix" ); port ( -- ---------------- -- PORT DECLARATION -- ---------------- -- data input ports dataa : in std_logic_vector(number_of_multipliers * width_a -1 downto 0); datab : in std_logic_vector(number_of_multipliers * width_b -1 downto 0); scanina : in std_logic_vector(width_a -1 downto 0) := (others => '0'); scaninb : in std_logic_vector(width_b -1 downto 0) := (others => '0'); sourcea : in std_logic_vector((number_of_multipliers -1) downto 0) := (others => '0'); sourceb : in std_logic_vector((number_of_multipliers -1) downto 0) := (others => '0'); -- clock ports clock3 : in std_logic := '1'; clock2 : in std_logic := '1'; clock1 : in std_logic := '1'; clock0 : in std_logic := '1'; -- clear ports aclr3 : in std_logic := '0'; aclr2 : in std_logic := '0'; aclr1 : in std_logic := '0'; aclr0 : in std_logic := '0'; -- clock enable signals ena3 : in std_logic := '1'; ena2 : in std_logic := '1'; ena1 : in std_logic := '1'; ena0 : in std_logic := '1'; -- control signals signa : in std_logic := 'Z'; signb : in std_logic := 'Z'; addnsub1 : in std_logic := 'Z'; addnsub3 : in std_logic := 'Z'; -- StratixII only input ports mult01_round : in std_logic := '0'; mult23_round : in std_logic := '0'; mult01_saturation : in std_logic := '0'; mult23_saturation : in std_logic := '0'; addnsub1_round : in std_logic := '0'; addnsub3_round : in std_logic := '0'; -- output ports result : out std_logic_vector(width_result -1 downto 0) := (others => '0'); scanouta : out std_logic_vector (width_a -1 downto 0) := (others => '0'); scanoutb : out std_logic_vector (width_b -1 downto 0) := (others => '0'); -- StratixII only output ports mult0_is_saturated : out std_logic := '0'; mult1_is_saturated : out std_logic := '0'; mult2_is_saturated : out std_logic := '0'; mult3_is_saturated : out std_logic := '0' ); end altmult_add; architecture behaviour of altmult_add is -- --------------------------- -- SIGNAL AND TYPE DECLARATION -- --------------------------- type pipeline_accum is array (extra_latency downto 0) of std_logic_vector (width_result-1 downto 0); signal zeropad : std_logic_vector ((width_result - width_a - width_b)/2 -1 downto 0) := (others => '0'); signal answer : std_logic_vector (width_result + 1 downto 0) := (others => '0'); signal mult_a : std_logic_vector ((4 * width_a) -1 downto 0) := (others => '0'); signal mult_b : std_logic_vector ((4 * width_b) -1 downto 0) := (others => '0'); signal mult_res : std_logic_vector ((number_of_multipliers * (width_a + width_b)) + number_of_multipliers downto 0) := (others => '0'); signal zero_acc_reg : std_logic := '0'; signal zero_acc_pipe : std_logic := '0'; signal sign_a_reg : std_logic := '0'; signal sign_a_pipe : std_logic := '0'; signal sign_b_reg : std_logic := '0'; signal sign_b_pipe : std_logic := '0'; signal addsub_reg1 : std_logic := '0'; signal addsub_pipe1 : std_logic := '0'; signal addsub_reg3 : std_logic := '0'; signal addsub_pipe3 : std_logic := '0'; signal out_sum : std_logic_vector (width_result + 1 downto 0); signal result_pipe : pipeline_accum := (others => (others => '0')); signal mult_clock : std_logic_vector (3 downto 0) := (others => '0'); signal mult_ena : std_logic_vector (3 downto 0) := (others => '0'); signal mult_aclr : std_logic_vector (3 downto 0) := (others => '0'); signal clock_vector : std_logic_vector (3 downto 0) := (others => '0'); signal ena_vector : std_logic_vector (3 downto 0) := (others => '0'); signal aclr_vector : std_logic_vector (3 downto 0) := (others => '0'); signal dataa_int : std_logic_vector (4 * width_a -1 downto 0) := (others => '0'); signal datab_int : std_logic_vector (4 * width_b -1 downto 0) := (others => '0'); signal is_reg : std_logic_vector (3 downto 0) := (others => '0'); signal temp_mult_zero : std_logic_vector ((width_a + width_b) -1 downto 0) := (others => '0'); signal head_result : integer := 0; signal signed_mult : std_logic := '1'; signal mult01_round_wire : std_logic := '0'; signal mult01_saturate_wire : std_logic := '0'; signal mult23_round_wire : std_logic := '0'; signal mult23_saturate_wire : std_logic := '0'; signal mult_is_saturated : std_logic_vector ((number_of_multipliers - 1) downto 0) := (others => '0'); signal mult_is_saturated_pipe : std_logic_vector ((number_of_multipliers - 1) downto 0) := (others => '0'); signal sourcea_wire : std_logic_vector (3 downto 0) := (others => '0'); signal sourceb_wire : std_logic_vector (3 downto 0) := (others => '0'); signal addnsub1_round_wire : std_logic := '0'; signal addnsub1_round_pipe_wire : std_logic := '0'; signal addnsub3_round_wire : std_logic := '0'; signal addnsub3_round_pipe_wire : std_logic := '0'; -- ------------------------------------------------------------------- -- This function takes in a string that describes the clock name -- and returns the correct number that corresponds to that particular -- clock signal -- ------------------------------------------------------------------- function resolve_clock (ARG : string) return integer is variable clock_num:integer := 0; begin if (ARG = "CLOCK0") then clock_num := 0; elsif ARG = "CLOCK1" then clock_num := 1; elsif ARG = "CLOCK2" then clock_num := 2; elsif ARG = "CLOCK3" then clock_num := 3; end if; return clock_num; end resolve_clock; -- ------------------------------------------------------------------- -- This function takes in a string that describes the clear name -- and returns the correct number that corresponds to that particular -- clear signal -- ------------------------------------------------------------------- function resolve_aclr (ARG : string) return integer is variable aclr_num:integer := 0; begin if (ARG = "ACLR0") then aclr_num := 0; elsif ARG = "ACLR1" then aclr_num := 1; elsif ARG = "ACLR2" then aclr_num := 2; elsif ARG = "ACLR3" then aclr_num := 3; end if; return aclr_num; end resolve_aclr; -- ------------------------------------------------------------------- -- This function takes in a integer that describes the particular -- clock signal returns the correct string -- ------------------------------------------------------------------- function check_clock (arg: integer) return string is variable ret_val:string (1 to 6); begin if (arg = 0) then ret_val := multiplier_register0 (1 to 6); elsif arg =1 then ret_val := multiplier_register1 (1 to 6); elsif arg=2 then ret_val := multiplier_register2 (1 to 6); elsif arg=3 then ret_val := multiplier_register3 (1 to 6); else ret_val := "CLOCK0"; end if; return ret_val; end check_clock; begin scanouta <= mult_a ((number_of_multipliers * width_a) -1 downto (number_of_multipliers -1 ) * width_a) ; scanoutb <= mult_b ((number_of_multipliers * width_b) -1 downto (number_of_multipliers -1 ) * width_b) ; clock_vector (0) <= clock0; clock_vector (1) <= clock1; clock_vector (2) <= clock2; clock_vector (3) <= clock3; ena_vector (0) <= ena0; ena_vector (1) <= ena1; ena_vector (2) <= ena2; ena_vector (3) <= ena3; aclr_vector (0) <= aclr0; aclr_vector (1) <= aclr1; aclr_vector (2) <= aclr2; aclr_vector (3) <= aclr3; sourcea_wire ( number_of_multipliers - 1 downto 0) <= sourcea (number_of_multipliers -1 downto 0); sourceb_wire ( number_of_multipliers - 1 downto 0) <= sourceb (number_of_multipliers - 1 downto 0); -- Parameter Checking process begin -- Checking for invalid parameters, in case Wizard is bypassed (hand-modified). if (number_of_multipliers > 4) then assert false report "Altmult_add does not currently support NUMBER_OF_MULTIPLIERS > 4" severity error; end if; if (number_of_multipliers <= 0) then assert false report "NUMBER_OF_MULTIPLIERS must be greater than 0." severity error; end if; if ((width_a > 36) and (number_of_multipliers = 1)) then assert false report "Altmult_add does not support WIDTH_A greater than 36 if NUMBER_OF_MULTIPLIERS is equal to one." severity error; end if; if ((width_b > 36) and (number_of_multipliers = 1)) then assert false report "Altmult_add does not support WIDTH_B greater than 36 if NUMBER_OF_MULTIPLIERS is equal to one." severity error; end if; if (width_a <= 0) then assert false report "Error: width_a must be greater than 0." severity error; end if; if (width_b <= 0) then assert false report "Error: width_b must be greater than 0." severity error; end if; if (width_result <= 0) then assert false report "Error: width_result must be greater than 0." severity error; end if; if ((dedicated_multiplier_circuitry /= "AUTO") and (dedicated_multiplier_circuitry /= "YES") and (dedicated_multiplier_circuitry /= "NO")) then assert false report "Error: The DEDICATED_MULTIPLIER_CIRCUITRY parameter is set to an illegal value." severity error; end if; if ((input_source_a0 /= "DATAA") and (input_source_a0 /= "SCANA") and (input_source_a0 /= "VARIABLE")) then assert false report "Error: The INPUT_SOURCE_A0 parameter is set to an illegal value." severity error; end if; if ((input_source_a1 /= "DATAA") and (input_source_a1 /= "SCANA") and (input_source_a1 /= "VARIABLE")) then assert false report "Error: The INPUT_SOURCE_A1 parameter is set to an illegal value." severity error; end if; if ((input_source_a2 /= "DATAA") and (input_source_a2 /= "SCANA") and (input_source_a2 /= "VARIABLE")) then assert false report "Error: The INPUT_SOURCE_A2 parameter is set to an illegal value." severity error; end if; if ((input_source_a3 /= "DATAA") and (input_source_a3 /= "SCANA") and (input_source_a3 /= "VARIABLE")) then assert false report "Error: The INPUT_SOURCE_A3 parameter is set to an illegal value." severity error; end if; if ((input_source_b0 /= "DATAB") and (input_source_b0 /= "SCANB") and (input_source_b0 /= "VARIABLE")) then assert false report "Error: The INPUT_SOURCE_B0 parameter is set to an illegal value." severity error; end if; if ((input_source_b1 /= "DATAB") and (input_source_b1 /= "SCANB") and (input_source_b1 /= "VARIABLE")) then assert false report "Error: The INPUT_SOURCE_B1 parameter is set to an illegal value." severity error; end if; if ((input_source_b2 /= "DATAB") and (input_source_b2 /= "SCANB") and (input_source_b2 /= "VARIABLE")) then assert false report "Error: The INPUT_SOURCE_B2 parameter is set to an illegal value." severity error; end if; if ((input_source_b3 /= "DATAB") and (input_source_b3 /= "SCANB") and (input_source_b3 /= "VARIABLE")) then assert false report "Error: The INPUT_SOURCE_B3 parameter is set to an illegal value." severity error; end if; if ((not IS_FAMILY_STRATIXII(intended_device_family)) and (input_source_a0 = "VARIABLE")) then assert false report "Error: Non-StratixII family does not support input source as VARIABLE" severity error; end if; if ((not IS_FAMILY_STRATIXII(intended_device_family)) and (input_source_a1 = "VARIABLE")) then assert false report "Error: Non-StratixII family does not support input source as VARIABLE" severity error; end if; if ((not IS_FAMILY_STRATIXII(intended_device_family)) and (input_source_a2 = "VARIABLE")) then assert false report "Error: Non-StratixII family does not support input source as VARIABLE" severity error; end if; if ((not IS_FAMILY_STRATIXII(intended_device_family)) and (input_source_a3 = "VARIABLE")) then assert false report "Error: Non-StratixII family does not support input source as VARIABLE" severity error; end if; if ((not IS_FAMILY_STRATIXII(intended_device_family)) and (input_source_b0 = "VARIABLE")) then assert false report "Error: Non-StratixII family does not support input source as VARIABLE" severity error; end if; if ((not IS_FAMILY_STRATIXII(intended_device_family)) and (input_source_b1 = "VARIABLE")) then assert false report "Error: Non-StratixII family does not support input source as VARIABLE" severity error; end if; if ((not IS_FAMILY_STRATIXII(intended_device_family)) and (input_source_b2 = "VARIABLE")) then assert false report "Error: Non-StratixII family does not support input source as VARIABLE" severity error; end if; if ((not IS_FAMILY_STRATIXII(intended_device_family)) and (input_source_b3 = "VARIABLE")) then assert false report "Error: Non-StratixII family does not support input source as VARIABLE" severity error; end if; if ((not IS_FAMILY_STRATIXII(intended_device_family)) and ((multiplier01_rounding = "YES") or (multiplier01_rounding = "VARIABLE") or (multiplier23_rounding = "YES") or (multiplier23_rounding = "VARIABLE"))) then assert false report "Error: Non-StratixII family does not support rounding for multiplier" severity error; end if; if ((not IS_FAMILY_STRATIXII(intended_device_family)) and ((multiplier01_saturation = "YES") or (multiplier01_saturation = "VARIABLE") or (multiplier23_saturation = "YES") or (multiplier23_saturation = "VARIABLE"))) then assert false report "Error: Non-StratixII family does not support saturation for multiplier" severity error; end if; if ((not IS_FAMILY_STRATIXII(intended_device_family)) and ((adder1_rounding = "YES") or (adder1_rounding = "VARIABLE") or (adder3_rounding = "YES") or (adder3_rounding = "VARIABLE"))) then assert false report "Error: Non-StratixII family does not support rounding for adder" severity error; end if; wait; end process; -- ---------------------------------------------------------------- -- This process updates the dataa_int everytime dataa changes value -- ---------------------------------------------------------------- process (dataa) variable i :integer; begin for i in 0 to ((number_of_multipliers * width_a) -1) loop dataa_int (i) <= dataa (i); end loop; end process; -- ---------------------------------------------------------------- -- This process updates the datab_int everytime datab changes value -- ---------------------------------------------------------------- process (datab) variable i :integer; begin for i in 0 to ((number_of_multipliers * width_b) -1) loop datab_int (i) <= datab (i); end loop; end process; -- ------------------------------------------------------------------------------------ -- This process sets up all the clock, clock enable and clear signals for all registers -- ------------------------------------------------------------------------------------ process (clock0, clock1, clock2, clock3, aclr_vector, dataa_int, datab_int, signa, signb, addnsub1, addnsub3) variable temp_clock : integer := 0; variable temp_aclr : integer := 0; variable x : integer := 0; variable mult_a_pre0 : std_logic_vector (4 * width_a -1 downto 0):= (others => '0'); variable mult_a_pre1 : std_logic_vector (4 * width_a -1 downto 0):= (others => '0'); variable mult_a_pre2 : std_logic_vector (4 * width_a -1 downto 0):= (others => '0'); variable mult_a_pre3 : std_logic_vector (4 * width_a -1 downto 0):= (others => '0'); variable mult_b_pre0 : std_logic_vector (4 * width_b -1 downto 0):= (others => '0'); variable mult_b_pre1 : std_logic_vector (4 * width_b -1 downto 0):= (others => '0'); variable mult_b_pre2 : std_logic_vector (4 * width_b -1 downto 0):= (others => '0'); variable mult_b_pre3 : std_logic_vector (4 * width_b -1 downto 0):= (others => '0'); begin --sets up all the clock, clock enable and clear signals for multiplier0 if not (multiplier_register0 = "UNREGISTERED") then temp_clock := resolve_clock (multiplier_register0); mult_clock(0) <= clock_vector (temp_clock); mult_ena(0) <= ena_vector (temp_clock); temp_aclr := resolve_aclr (multiplier_aclr0); mult_aclr(0) <= aclr_vector (temp_aclr); is_reg(0) <= '1'; end if; --sets up all the clock, clock enable and clear signals for multiplier1 if not (multiplier_register1 = "UNREGISTERED") then temp_clock := resolve_clock (multiplier_register1); mult_clock(1) <= clock_vector (temp_clock); mult_ena(1) <= ena_vector (temp_clock); temp_aclr := resolve_aclr (multiplier_aclr1); mult_aclr(1) <= aclr_vector (temp_aclr); is_reg(1) <= '1'; end if; --sets up all the clock, clock enable and clear signals for multiplier2 if not (multiplier_register2 = "UNREGISTERED") then temp_clock := resolve_clock (multiplier_register2); mult_clock(2) <= clock_vector (temp_clock); mult_ena(2) <= ena_vector (temp_clock); temp_aclr := resolve_aclr (multiplier_aclr2); mult_aclr(2) <= aclr_vector (temp_aclr); is_reg(2) <= '1'; end if; --sets up all the clock, clock enable and clear signals for multiplier3 if not (multiplier_register3 = "UNREGISTERED") then temp_clock := resolve_clock (multiplier_register3); mult_clock(3) <= clock_vector (temp_clock); mult_ena(3) <= ena_vector (temp_clock); temp_aclr := resolve_aclr (multiplier_aclr3); mult_aclr(3) <= aclr_vector (temp_aclr); is_reg(3) <= '1'; end if; -- --------------------------------------------- -- SETTING UP THE DATA INPUT REGISTERS OF PORT A -- --------------------------------------------- -- ----------------- -- INPUT_REGISTER_A0 -- ----------------- -- set the initial value for mult_a_pre0 from dataa_int if (input_source_a0 = "DATAA") then mult_a_pre0 (width_a-1 downto 0) := dataa_int (width_a-1 downto 0); elsif (input_source_a0 = "SCANA") then if (IS_FAMILY_STRATIXII(intended_device_family)) then mult_a_pre0 (width_a-1 downto 0) := scanina; else mult_a_pre0 (width_a-1 downto 0) := dataa_int (width_a-1 downto 0); end if; else if (sourcea_wire(0) = '1') then mult_a_pre0 (width_a-1 downto 0) := scanina; else mult_a_pre0 (width_a-1 downto 0) := dataa_int (width_a-1 downto 0); end if; end if; -- ----------------------------------------------------------------------------------- -- Clears mult_a and mult_a_pre1 (this is the next variable to be used by register_a1) -- whenever clear signal is triggered -- -- If clock is triggered or register is not used, assign mult_a to mult_a_pre0 -- -- Check make sure that register_a1 doesnt use the same clock as register_a0, -- or if register_a0 is unregistered -- If so, then update mult_a_pre1 with mult_a_pre0 to be used for register_a1 -- -- if nothing happens (ie. clock/clear is not triggered), -- then update mult_a_pre1 with the current value of mult_a -- ----------------------------------------------------------------------------------- if ((((input_aclr_a0 = "ACLR0") and (aclr0 = '1')) or ((input_aclr_a0 = "ACLR1") and (aclr1 = '1')) or ((input_aclr_a0 = "ACLR2") and (aclr2 = '1')) or ((input_aclr_a0 = "ACLR3") and (aclr3 = '1'))) and (not (input_register_a0 = "UNREGISTERED"))) then mult_a(width_a-1 downto 0) <= (others => '0'); mult_a_pre1(width_a-1 downto 0) := (others => '0'); elsif (((input_register_a0 = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((input_register_a0 = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((input_register_a0 = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((input_register_a0 = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1')) or (input_register_a0 = "UNREGISTERED")) then mult_a (width_a-1 downto 0) <= mult_a_pre0 (width_a-1 downto 0); if ((not(input_register_a0 = input_register_a1)) or (input_register_a0 = "UNREGISTERED")) then mult_a_pre1 (width_a-1 downto 0) := mult_a_pre0 (width_a-1 downto 0); end if; else mult_a_pre1 (width_a-1 downto 0) := mult_a (width_a-1 downto 0); end if; -- ----------------- -- INPUT_REGISTER_A1 -- ----------------- -- set the initial value for mult_a_pre1 from dataa_int if input source is from dataa -- otherwise, load it from the mult_a_pre1 that stored the previous value from register_a0 if (input_source_a1 = "DATAA") then mult_a_pre1 ((2)*width_a-1 downto (width_a)) := dataa_int ((2)*width_a-1 downto (width_a)); elsif (input_source_a1 = "SCANA") then mult_a_pre1 ((2)*width_a-1 downto (width_a)) := mult_a_pre1(width_a-1 downto 0); else if (sourcea_wire(1) = '1') then mult_a_pre1 ((2)*width_a-1 downto (width_a)) := mult_a_pre1(width_a-1 downto 0); else mult_a_pre1 ((2)*width_a-1 downto (width_a)) := dataa_int ((2)*width_a-1 downto (width_a)); end if; end if; -- ----------------------------------------------------------------------------------- -- Clears mult_a and mult_a_pre2 (this is the next variable to be used by register_a2) -- whenever clear signal is triggered -- -- If clock is triggered or register is not used, assign mult_a to mult_a_pre1 -- -- Check make sure that register_a1 doesnt use the same clock as register_a2, -- or if register_a1 is unregistered -- If so, then update mult_a_pre2 with mult_a_pre1 to be used for register_a2 -- -- if nothing happens (ie. clock/clear is not triggered), -- then update mult_a_pre2 with the current value of mult_a -- ----------------------------------------------------------------------------------- if ((((input_aclr_a1 = "ACLR0") and (aclr0 = '1')) or ((input_aclr_a1 = "ACLR1") and (aclr1 = '1')) or ((input_aclr_a1 = "ACLR2") and (aclr2 = '1')) or ((input_aclr_a1 = "ACLR3") and (aclr3 = '1'))) and (not (input_register_a1 = "UNREGISTERED"))) then mult_a ((2)*width_a-1 downto (width_a)) <= (others => '0'); mult_a_pre2 ((2)*width_a-1 downto (width_a)) := (others => '0'); elsif (((input_register_a1 = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((input_register_a1 = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((input_register_a1 = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((input_register_a1 = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1')) or (input_register_a1 = "UNREGISTERED")) then mult_a ((2)*width_a-1 downto (width_a)) <= mult_a_pre1 ((2)*width_a-1 downto width_a); if ((not(input_register_a1 = input_register_a2)) or (input_register_a1 = "UNREGISTERED")) then mult_a_pre2 ((2)*width_a-1 downto (width_a)) := mult_a_pre1 ((2)*width_a-1 downto width_a); end if; else mult_a_pre2 ((2)*width_a-1 downto (width_a)) := mult_a ((2)*width_a-1 downto (width_a)); end if; -- ----------------- -- INPUT_REGISTER_A2 -- ----------------- -- set the initial value for mult_a_pre2 from dataa_int if input source is from dataa -- otherwise, load it from the mult_a_pre2 that stored the previous value from register_a1 if (input_source_a2 = "DATAA") then mult_a_pre2 ((3)*width_a-1 downto (2*width_a)) := dataa_int ((3)*width_a-1 downto (2*width_a)); elsif (input_source_a2 = "SCANA") then mult_a_pre2 ((3)*width_a-1 downto (2*width_a)) := mult_a_pre2((2)*width_a-1 downto (width_a)); else if (sourcea_wire(2) = '1') then mult_a_pre2 ((3)*width_a-1 downto (2*width_a)) := mult_a_pre2((2)*width_a-1 downto (width_a)); else mult_a_pre2 ((3)*width_a-1 downto (2*width_a)) := dataa_int ((3)*width_a-1 downto (2*width_a)); end if; end if; -- ----------------------------------------------------------------------------------- -- Clears mult_a and mult_a_pre3 (this is the next variable to be used by register_a3) -- whenever clear signal is triggered -- -- If clock is triggered or register is not used, assign mult_a to mult_a_pre2 -- -- Check make sure that register_a2 doesnt use the same clock as register_a3, -- or if register_a2 is unregistered -- If so, then update mult_a_pre3 with mult_a_pre2 to be used for register_a3 -- -- if nothing happens (ie. clock/clear is not triggered), -- then update mult_a_pre3 with the current value of mult_a -- ----------------------------------------------------------------------------------- if ((((input_aclr_a2 = "ACLR0") and (aclr0 = '1')) or ((input_aclr_a2 = "ACLR1") and (aclr1 = '1')) or ((input_aclr_a2 = "ACLR2") and (aclr2 = '1')) or ((input_aclr_a2 = "ACLR3") and (aclr3 = '1'))) and (not (input_register_a2 = "UNREGISTERED"))) then mult_a ((3)*width_a-1 downto (2*width_a)) <= (others => '0'); mult_a_pre3 ((3)*width_a-1 downto (2*width_a)) := (others => '0'); elsif (((input_register_a2 = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((input_register_a2 = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((input_register_a2 = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((input_register_a2 = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1')) or (input_register_a2 = "UNREGISTERED")) then mult_a ((3)*width_a-1 downto (2*width_a)) <= mult_a_pre2 ((3)*width_a-1 downto (2*width_a)); if ((not(input_register_a2 = input_register_a3)) or (input_register_a2 = "UNREGISTERED")) then mult_a_pre3 ((3)*width_a-1 downto (2*width_a)) := mult_a_pre2 ((3)*width_a-1 downto (2*width_a)); end if; else mult_a_pre3 ((3)*width_a-1 downto (2*width_a)) := mult_a ((3)*width_a-1 downto (2*width_a)); end if; -- ----------------- -- INPUT_REGISTER_A3 -- ----------------- -- set the initial value for mult_a_pre3 from dataa_int if input source is from dataa -- otherwise, load it from the mult_a_pre3 that stored the previous value from register_a2 if (input_source_a3 = "DATAA") then mult_a_pre3 ((4)*width_a-1 downto (3*width_a)) := dataa_int ((4)*width_a-1 downto (3*width_a)); elsif (input_source_a3 = "SCANA") then mult_a_pre3 ((4)*width_a-1 downto (3*width_a)) := mult_a_pre3 ((3)*width_a-1 downto (2*width_a)); else if (sourcea_wire(3) = '1') then mult_a_pre3 ((4)*width_a-1 downto (3*width_a)) := mult_a_pre3 ((3)*width_a-1 downto (2*width_a)); else mult_a_pre3 ((4)*width_a-1 downto (3*width_a)) := dataa_int ((4)*width_a-1 downto (3*width_a)); end if; end if; -- ----------------------------------------------------------------------------------- -- Clears mult_a whenever clear signal is triggered -- If clock is triggered or register is not used, assign mult_a to mult_a_pre3 -- ----------------------------------------------------------------------------------- if ((((input_aclr_a3 = "ACLR0") and (aclr0 = '1')) or ((input_aclr_a3 = "ACLR1") and (aclr1 = '1')) or ((input_aclr_a3 = "ACLR2") and (aclr2 = '1')) or ((input_aclr_a3 = "ACLR3") and (aclr3 = '1'))) and (not (input_register_a3 = "UNREGISTERED"))) then mult_a ((4)*width_a-1 downto (3*width_a)) <= (others => '0'); elsif (((input_register_a3 = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((input_register_a3 = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((input_register_a3 = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((input_register_a3 = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1')) or (input_register_a3 = "UNREGISTERED")) then mult_a ((4)*width_a-1 downto (3*width_a)) <= mult_a_pre3 ((4)*width_a-1 downto (3*width_a)); end if; -- --------------------------------------------- -- SETTING UP THE DATA INPUT REGISTERS OF PORT B -- --------------------------------------------- -- ----------------- -- INPUT_REGISTER_B0 -- ----------------- -- set the initial value for mult_b_pre0 from datab_int if (input_source_b0 = "DATAB") then mult_b_pre0 (width_b-1 downto 0) := datab_int (width_b-1 downto 0); elsif (input_source_b0 = "SCANB") then if (IS_FAMILY_STRATIXII(intended_device_family)) then mult_b_pre0 (width_b-1 downto 0) := scaninb; else mult_b_pre0 (width_b-1 downto 0) := datab_int (width_b-1 downto 0); end if; else if (sourceb_wire(0) = '1') then mult_b_pre0 (width_b-1 downto 0) := scaninb; else mult_b_pre0 (width_b-1 downto 0) := datab_int (width_b-1 downto 0); end if; end if; -- ----------------------------------------------------------------------------------- -- Clears mult_b and mult_b_pre1 (this is the next variable to be used by register_b1) -- whenever clear signal is triggered -- -- If clock is triggered or register is not used, assign mult_b to mult_b_pre0 -- -- Check make sure that register_b1 doesnt use the same clock as register_b0, -- or if register_b0 is unregistered -- If so, then update mult_b_pre1 with mult_b_pre0 to be used for register_b1 -- -- if nothing happens (ie. clock/clear is not triggered), -- then update mult_b_pre1 with the current value of mult_b -- ----------------------------------------------------------------------------------- if ((((input_aclr_b0 = "ACLR0") and (aclr0 = '1')) or ((input_aclr_b0 = "ACLR1") and (aclr1 = '1')) or ((input_aclr_b0 = "ACLR2") and (aclr2 = '1')) or ((input_aclr_b0 = "ACLR3") and (aclr3 = '1'))) and (not (input_register_b0 = "UNREGISTERED"))) then mult_b (width_b-1 downto 0) <= (others => '0'); mult_b_pre1 (width_b-1 downto 0) := (others => '0'); elsif (((input_register_b0 = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((input_register_b0 = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((input_register_b0 = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((input_register_b0 = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1')) or (input_register_b0 = "UNREGISTERED")) then mult_b (width_b-1 downto 0) <= mult_b_pre0 (width_b-1 downto 0); if ((not(input_register_b0 = input_register_b1)) or (input_register_b0 = "UNREGISTERED")) then mult_b_pre1 (width_b-1 downto 0) := mult_b_pre0 (width_b-1 downto 0); end if; else mult_b_pre1 (width_b-1 downto 0) := mult_b (width_b-1 downto 0); end if; -- ----------------- -- INPUT_REGISTER_B1 -- ----------------- -- set the initial value for mult_b_pre1 from datab_int if input source is from datab -- otherwise, load it from the mult_b_pre1 that stored the previous value from register_b0 if (input_source_b1 = "DATAB") then mult_b_pre1 ((2)*width_b-1 downto (width_b)) := datab_int ((2)*width_b-1 downto (width_b)); elsif (input_source_b1 = "SCANB") then mult_b_pre1 ((2)*width_b-1 downto (width_b)) := mult_b_pre1 (width_b-1 downto 0); else if (sourceb_wire(1) = '1') then mult_b_pre1 ((2)*width_b-1 downto (width_b)) := mult_b_pre1 (width_b-1 downto 0); else mult_b_pre1 ((2)*width_b-1 downto (width_b)) := datab_int ((2)*width_b-1 downto (width_b)); end if; end if; -- ----------------------------------------------------------------------------------- -- Clears mult_b and mult_b_pre2 (this is the next variable to be used by register_b2) -- whenever clear signal is triggered -- -- If clock is triggered or register is not used, assign mult_b to mult_b_pre1 -- -- Check make sure that register_a1 doesnt use the same clock as register_b2, -- or if register_b1 is unregistered -- If so, then update mult_b_pre2 with mult_b_pre1 to be used for register_b2 -- -- if nothing happens (ie. clock/clear is not triggered), -- then update mult_b_pre2 with the current value of mult_b -- ----------------------------------------------------------------------------------- if ((((input_aclr_b1 = "ACLR0") and (aclr0 = '1')) or ((input_aclr_b1 = "ACLR1") and (aclr1 = '1')) or ((input_aclr_b1 = "ACLR2") and (aclr2 = '1')) or ((input_aclr_b1 = "ACLR3") and (aclr3 = '1'))) and (not (input_register_b1 = "UNREGISTERED"))) then mult_b ((2)*width_b-1 downto (width_b)) <= (others => '0'); mult_b_pre2 ((2)*width_b-1 downto (width_b)) := (others => '0'); elsif (((input_register_b1 = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((input_register_b1 = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((input_register_b1 = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((input_register_b1 = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1')) or (input_register_b1 = "UNREGISTERED")) then mult_b ((2)*width_b-1 downto (width_b)) <= mult_b_pre1 ((2)*width_b-1 downto width_b); if ((not(input_register_b1 = input_register_b2)) or (input_register_b1 = "UNREGISTERED")) then mult_b_pre2 ((2)*width_b-1 downto (width_b)) := mult_b_pre1 ((2)*width_b-1 downto width_b); end if; else mult_b_pre2 ((2)*width_b-1 downto (width_b)) := mult_b ((2)*width_b-1 downto (width_b)); end if; -- ----------------- -- INPUT_REGISTER_B2 -- ----------------- -- set the initial value for mult_b_pre2 from datab_int if input source is from datab -- otherwise, load it from the mult_b_pre2 that stored the previous value from register_b1 if (input_source_b2 = "DATAB") then mult_b_pre2 ((3)*width_b-1 downto (2*width_b)) := datab_int ((3)*width_b-1 downto (2*width_b)); elsif (input_source_b2 = "SCANB") then mult_b_pre2 ((3)*width_b-1 downto (2*width_b)) := mult_b_pre2 ((2)*width_b-1 downto (width_b)); else if (sourceb_wire(2) = '1') then mult_b_pre2 ((3)*width_b-1 downto (2*width_b)) := mult_b_pre2 ((2)*width_b-1 downto (width_b)); else mult_b_pre2 ((3)*width_b-1 downto (2*width_b)) := datab_int ((3)*width_b-1 downto (2*width_b)); end if; end if; -- ----------------------------------------------------------------------------------- -- Clears mult_b and mult_b_pre3 (this is the next variable to be used by register_b3) -- whenever clear signal is triggered -- -- If clock is triggered or register is not used, assign mult_b to mult_b_pre2 -- -- Check make sure that register_b2 doesnt use the same clock as register_b3, -- or if register_b2 is unregistered -- If so, then update mult_b_pre3 with mult_b_pre2 to be used for register_b3 -- -- if nothing happens (ie. clock/clear is not triggered), -- then update mult_b_pre3 with the current value of mult_b -- ----------------------------------------------------------------------------------- if ((((input_aclr_b2 = "ACLR0") and (aclr0 = '1')) or ((input_aclr_b2 = "ACLR1") and (aclr1 = '1')) or ((input_aclr_b2 = "ACLR2") and (aclr2 = '1')) or ((input_aclr_b2 = "ACLR3") and (aclr3 = '1'))) and (not (input_register_b2 = "UNREGISTERED"))) then mult_b ((3)*width_b-1 downto (2*width_b)) <= (others => '0'); mult_b_pre3 ((3)*width_b-1 downto (2*width_b)) := (others => '0'); elsif (((input_register_b2 = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((input_register_b2 = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((input_register_b2 = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((input_register_b2 = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1')) or (input_register_b2 = "UNREGISTERED")) then mult_b ((3)*width_b-1 downto (2*width_b)) <= mult_b_pre2 ((3)*width_b-1 downto (2*width_b)); if ((not(input_register_b2 = input_register_b3)) or (input_register_b2 = "UNREGISTERED")) then mult_b_pre3 ((3)*width_b-1 downto (2*width_b)) := mult_b_pre2 ((3)*width_b-1 downto (2*width_b)); end if; else mult_b_pre3 ((3)*width_b-1 downto (2*width_b)) := mult_b ((3)*width_b-1 downto (2*width_b)); end if; -- ----------------- -- INPUT_REGISTER_B3 -- ----------------- -- set the initial value for mult_b_pre3 from datab_int if input source is from datab -- otherwise, load it from the mult_b_pre3 that stored the previous value from register_b2 if (input_source_b3 = "DATAB") then mult_b_pre3 ((4)*width_b-1 downto (3*width_b)) := datab_int ((4)*width_b-1 downto (3*width_b)); elsif (input_source_b3 = "SCANB") then mult_b_pre3 ((4)*width_b-1 downto (3*width_b)) := mult_b_pre3 ((3)*width_b-1 downto (2*width_b)); else if (sourceb_wire(3) = '1') then mult_b_pre3 ((4)*width_b-1 downto (3*width_b)) := mult_b_pre3 ((3)*width_b-1 downto (2*width_b)); else mult_b_pre3 ((4)*width_b-1 downto (3*width_b)) := datab_int ((4)*width_b-1 downto (3*width_b)); end if; end if; -- ----------------------------------------------------------------------------------- -- Clears mult_b whenever clear signal is triggered -- If clock is triggered or register is not used, assign mult_b to mult_b_pre3 -- ----------------------------------------------------------------------------------- if ((((input_aclr_b3 = "ACLR0") and (aclr0 = '1')) or ((input_aclr_b3 = "ACLR1") and (aclr1 = '1')) or ((input_aclr_b3 = "ACLR2") and (aclr2 = '1')) or ((input_aclr_b3 = "ACLR3") and (aclr3 = '1'))) and (not (input_register_b3 = "UNREGISTERED"))) then mult_b ((4)*width_b-1 downto (3*width_b)) <= (others => '0'); elsif (((input_register_b3 = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((input_register_b3 = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((input_register_b3 = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((input_register_b3 = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1')) or (input_register_b3 = "UNREGISTERED")) then mult_b ((4)*width_b-1 downto (3*width_b)) <= mult_b_pre3 ((4)*width_b-1 downto (3*width_b)); end if; -- --------------------------------------- -- SETTING UP THE CONTROL SIGNAL REGISTERS -- --------------------------------------- -- --------------------------------------------------------------------------------- -- This statement contains 1 register and a combinatorial block (to set addsub_reg1) -- The signal registered is addnsub1 -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if addnsub_multiplier_register1 -- is unregistered and addnsub1 changes value -- --------------------------------------------------------------------------------- if (addnsub_multiplier_register1 = "UNREGISTERED") then addsub_reg1 <= addnsub1; else if (((addnsub_multiplier_aclr1 = "ACLR0") and (aclr0 = '1')) or ((addnsub_multiplier_aclr1 = "ACLR1") and (aclr1 = '1')) or ((addnsub_multiplier_aclr1 = "ACLR2") and (aclr2 = '1')) or ((addnsub_multiplier_aclr1 = "ACLR3") and (aclr3 = '1'))) then addsub_reg1 <= '0'; elsif (((addnsub_multiplier_register1 = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((addnsub_multiplier_register1 = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((addnsub_multiplier_register1 = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((addnsub_multiplier_register1 = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1'))) then addsub_reg1 <= addnsub1; end if; end if; -- ---------------------------------------------------------------------------------- -- This statement contains 1 register and a combinatorial block (to set addsub_pipe1) -- The signal registered is addsub_reg1 -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if addnsub_multiplier_pipeline_register1 -- is unregistered and addsub_reg1 changes value -- ---------------------------------------------------------------------------------- if (addnsub_multiplier_pipeline_register1 = "UNREGISTERED") then addsub_pipe1 <= addsub_reg1; else if (((addnsub_multiplier_pipeline_aclr1 = "ACLR0") and (aclr0 = '1')) or ((addnsub_multiplier_pipeline_aclr1 = "ACLR1") and (aclr1 = '1')) or ((addnsub_multiplier_pipeline_aclr1 = "ACLR2") and (aclr2 = '1')) or ((addnsub_multiplier_pipeline_aclr1 = "ACLR3") and (aclr3 = '1'))) then addsub_pipe1<= '0'; elsif (((addnsub_multiplier_pipeline_register1 = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((addnsub_multiplier_pipeline_register1 = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((addnsub_multiplier_pipeline_register1 = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((addnsub_multiplier_pipeline_register1 = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1'))) then addsub_pipe1 <= addsub_reg1; end if; end if; -- --------------------------------------------------------------------------------- -- This statement contains 1 register and a combinatorial block (to set addsub_reg3) -- The signal registered is addsub3 -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if addnsub_multiplier_register3 -- is unregistered and addnsub3 changes value -- --------------------------------------------------------------------------------- if (addnsub_multiplier_register3 = "UNREGISTERED") then addsub_reg3 <= addnsub3; else if (((addnsub_multiplier_aclr3 = "ACLR0") and (aclr0 = '1')) or ((addnsub_multiplier_aclr3 = "ACLR1") and (aclr1 = '1')) or ((addnsub_multiplier_aclr3 = "ACLR2") and (aclr2 = '1')) or ((addnsub_multiplier_aclr3 = "ACLR3") and (aclr3 = '1'))) then addsub_reg3 <= '0'; elsif (((addnsub_multiplier_register3 = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((addnsub_multiplier_register3 = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((addnsub_multiplier_register3 = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((addnsub_multiplier_register3 = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1'))) then addsub_reg3 <= addnsub3; end if; end if; -- ---------------------------------------------------------------------------------- -- This statement contains 1 register and a combinatorial block (to set addsub_pipe3) -- The signal registered is addsub_reg3 -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if addnsub_multiplier_pipeline_register3 -- is unregistered and addsub_reg3 changes value -- ---------------------------------------------------------------------------------- if (addnsub_multiplier_pipeline_register3 = "UNREGISTERED") then addsub_pipe3 <= addsub_reg3; else if (((addnsub_multiplier_pipeline_aclr3 = "ACLR0") and (aclr0 = '1')) or ((addnsub_multiplier_pipeline_aclr3 = "ACLR1") and (aclr1 = '1')) or ((addnsub_multiplier_pipeline_aclr3 = "ACLR2") and (aclr2 = '1')) or ((addnsub_multiplier_pipeline_aclr3 = "ACLR3") and (aclr3 = '1'))) then addsub_pipe3<= '0'; elsif (((addnsub_multiplier_pipeline_register3 = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((addnsub_multiplier_pipeline_register3 = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((addnsub_multiplier_pipeline_register3 = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((addnsub_multiplier_pipeline_register3 = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1'))) then addsub_pipe3 <= addsub_reg3; end if; end if; -- -------------------------------------------------------------------------------- -- This statement contains 1 register and a combinatorial block (to set sign_a_reg) -- The signal registered is signa -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if signed_register_a -- is unregistered and signa changes value -- -------------------------------------------------------------------------------- if (signed_register_a= "UNREGISTERED") then sign_a_reg <= signa; else if (((signed_aclr_a = "ACLR0") and (aclr0 = '1')) or ((signed_aclr_a = "ACLR1") and (aclr1 = '1')) or ((signed_aclr_a = "ACLR2") and (aclr2 = '1')) or ((signed_aclr_a = "ACLR3") and (aclr3 = '1'))) then sign_a_reg <= '0'; elsif (((signed_register_a = "CLOCK0") and (clock0= '1') and clock0'event and (ena0 = '1')) or ((signed_register_a = "CLOCK1") and (clock1= '1') and clock1'event and (ena1 = '1')) or ((signed_register_a = "CLOCK2") and (clock2= '1') and clock2'event and (ena2 = '1')) or ((signed_register_a = "CLOCK3") and (clock3= '1') and clock3'event and (ena3 = '1'))) then sign_a_reg <= signa; end if; end if; -- -------------------------------------------------------------------------------- -- This statement contains 1 register and a combinatorial block (to set sign_b_reg) -- The signal registered is signb -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if signed_register_b -- is unregistered and signb changes value -- -------------------------------------------------------------------------------- if (signed_register_b= "UNREGISTERED") then sign_b_reg <= signb; else if (((signed_aclr_b = "ACLR0") and (aclr0 = '1')) or ((signed_aclr_b = "ACLR1") and (aclr1 = '1')) or ((signed_aclr_b = "ACLR2") and (aclr2 = '1')) or ((signed_aclr_b = "ACLR3") and (aclr3 = '1'))) then sign_b_reg <= '0'; elsif (((signed_register_b = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((signed_register_b = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((signed_register_b = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((signed_register_b = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1'))) then sign_b_reg <= signb; end if; end if; -- --------------------------------------------------------------------------------- -- This statement contains 1 register and a combinatorial block (to set sign_a_pipe) -- The signal registered is sign_a_reg -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if signed_pipeline_register_a -- is unregistered and sign_a_reg changes value -- --------------------------------------------------------------------------------- if (signed_pipeline_register_a = "UNREGISTERED") then sign_a_pipe <= sign_a_reg; else if (((signed_pipeline_aclr_a = "ACLR0") and (aclr0 = '1')) or ((signed_pipeline_aclr_a = "ACLR1") and (aclr1 = '1')) or ((signed_pipeline_aclr_a = "ACLR2") and (aclr2 = '1')) or ((signed_pipeline_aclr_a = "ACLR3") and (aclr3 = '1'))) then sign_a_pipe <= '0'; elsif (((signed_pipeline_register_a = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((signed_pipeline_register_a = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((signed_pipeline_register_a = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((signed_pipeline_register_a = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1'))) then sign_a_pipe <= sign_a_reg; end if; end if; -- --------------------------------------------------------------------------------- -- This statement contains 1 register and a combinatorial block (to set sign_b_pipe) -- The signal registered is sign_b_reg -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if signed_pipeline_register_b -- is unregistered and sign_b_reg changes value -- --------------------------------------------------------------------------------- if (signed_pipeline_register_b = "UNREGISTERED") then sign_b_pipe <= sign_b_reg; else if (((signed_pipeline_aclr_b = "ACLR0") and (aclr0 = '1')) or ((signed_pipeline_aclr_b = "ACLR1") and (aclr1 = '1')) or ((signed_pipeline_aclr_b = "ACLR2") and (aclr2 = '1')) or ((signed_pipeline_aclr_b = "ACLR3") and (aclr3 = '1'))) then sign_b_pipe <= '0'; elsif (((signed_pipeline_register_b = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((signed_pipeline_register_b = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((signed_pipeline_register_b = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((signed_pipeline_register_b = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1'))) then sign_b_pipe <= sign_b_reg; end if; end if; end process; -- ----------------------------------------------------------------------- -- This process block performs the rounding and saturation control signal -- setting -- ----------------------------------------------------------------------- process (clock0, clock1, clock2, clock3, aclr_vector, mult01_round, mult01_saturation, mult23_round, mult23_saturation, addnsub1_round, addnsub3_round, addnsub1_round_wire, addnsub3_round_wire) begin -- --------------------------------------------------------------------------------- -- This statement contains 1 register and a combinatorial block (to set mult01_round_wire) -- The signal registered is mult01_round -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if mult01_round_register -- is unregistered and mult01_round changes value -- --------------------------------------------------------------------------------- if (mult01_round_register = "UNREGISTERED") then mult01_round_wire <= mult01_round; else if (((mult01_round_aclr = "ACLR0") and (aclr0 = '1')) or ((mult01_round_aclr = "ACLR1") and (aclr1 = '1')) or ((mult01_round_aclr = "ACLR2") and (aclr2 = '1')) or ((mult01_round_aclr = "ACLR3") and (aclr3 = '1'))) then mult01_round_wire <= '0'; elsif (((mult01_round_register = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((mult01_round_register = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((mult01_round_register = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((mult01_round_register = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1'))) then mult01_round_wire <= mult01_round; end if; end if; -- --------------------------------------------------------------------------------- -- This statement contains 1 register and a combinatorial block (to set mult01_saturate_wire) -- The signal registered is mult01_saturation -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if mult01_saturate_register -- is unregistered and mult01_saturation changes value -- --------------------------------------------------------------------------------- if (mult01_saturation_register = "UNREGISTERED") then mult01_saturate_wire <= mult01_saturation; else if (((mult01_saturation_aclr = "ACLR0") and (aclr0 = '1')) or ((mult01_saturation_aclr = "ACLR1") and (aclr1 = '1')) or ((mult01_saturation_aclr = "ACLR2") and (aclr2 = '1')) or ((mult01_saturation_aclr = "ACLR3") and (aclr3 = '1'))) then mult01_saturate_wire <= '0'; elsif (((mult01_saturation_register = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((mult01_saturation_register = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((mult01_saturation_register = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((mult01_saturation_register = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1'))) then mult01_saturate_wire <= mult01_saturation; end if; end if; -- --------------------------------------------------------------------------------- -- This statement contains 1 register and a combinatorial block (to set mult23_round_wire) -- The signal registered is mult23_round -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if mult23_round_register -- is unregistered and mult23_round changes value -- --------------------------------------------------------------------------------- if (mult23_round_register = "UNREGISTERED") then mult23_round_wire <= mult23_round; else if (((mult23_round_aclr = "ACLR0") and (aclr0 = '1')) or ((mult23_round_aclr = "ACLR1") and (aclr1 = '1')) or ((mult23_round_aclr = "ACLR2") and (aclr2 = '1')) or ((mult23_round_aclr = "ACLR3") and (aclr3 = '1'))) then mult23_round_wire <= '0'; elsif (((mult23_round_register = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((mult23_round_register = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((mult23_round_register = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((mult23_round_register = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1'))) then mult23_round_wire <= mult23_round; end if; end if; -- --------------------------------------------------------------------------------- -- This statement contains 1 register and a combinatorial block (to set mult23_saturate_wire) -- The signal registered is mult23_saturation -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if mult23_saturate_register -- is unregistered and mult23_saturation changes value -- --------------------------------------------------------------------------------- if (mult23_saturation_register = "UNREGISTERED") then mult23_saturate_wire <= mult23_saturation; else if (((mult23_saturation_aclr = "ACLR0") and (aclr0 = '1')) or ((mult23_saturation_aclr = "ACLR1") and (aclr1 = '1')) or ((mult23_saturation_aclr = "ACLR2") and (aclr2 = '1')) or ((mult23_saturation_aclr = "ACLR3") and (aclr3 = '1'))) then mult23_saturate_wire <= '0'; elsif (((mult23_saturation_register = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((mult23_saturation_register = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((mult23_saturation_register = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((mult23_saturation_register = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1'))) then mult23_saturate_wire <= mult23_saturation; end if; end if; -- --------------------------------------------------------------------------------- -- This statement contains 1 register and a combinatorial block (to set addnsub1_round_wire) -- The signal registered is addnsub1_round -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if addnsub1_round_register -- is unregistered and addnsub1_round changes value -- --------------------------------------------------------------------------------- if (addnsub1_round_register = "UNREGISTERED") then addnsub1_round_wire <= addnsub1_round; else if (((addnsub1_round_aclr = "ACLR0") and (aclr0 = '1')) or ((addnsub1_round_aclr = "ACLR1") and (aclr1 = '1')) or ((addnsub1_round_aclr = "ACLR2") and (aclr2 = '1')) or ((addnsub1_round_aclr = "ACLR3") and (aclr3 = '1'))) then addnsub1_round_wire <= '0'; elsif (((addnsub1_round_register = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((addnsub1_round_register = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((addnsub1_round_register = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((addnsub1_round_register = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1'))) then addnsub1_round_wire <= addnsub1_round; end if; end if; -- --------------------------------------------------------------------------------- -- This statement contains 1 register and a combinatorial block (to set addnsub1_round_pipe_wire) -- The signal registered is addnsub1_round_wire -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if addnsub1_round_pipe_register -- is unregistered and addnsub1_round_wire changes value -- --------------------------------------------------------------------------------- if (addnsub1_round_pipeline_register = "UNREGISTERED") then addnsub1_round_pipe_wire <= addnsub1_round_wire; else if (((addnsub1_round_pipeline_aclr = "ACLR0") and (aclr0 = '1')) or ((addnsub1_round_pipeline_aclr = "ACLR1") and (aclr1 = '1')) or ((addnsub1_round_pipeline_aclr = "ACLR2") and (aclr2 = '1')) or ((addnsub1_round_pipeline_aclr = "ACLR3") and (aclr3 = '1'))) then addnsub1_round_pipe_wire <= '0'; elsif (((addnsub1_round_pipeline_register = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((addnsub1_round_pipeline_register = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((addnsub1_round_pipeline_register = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((addnsub1_round_pipeline_register = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1'))) then addnsub1_round_pipe_wire <= addnsub1_round_wire; end if; end if; -- --------------------------------------------------------------------------------- -- This statement contains 1 register and a combinatorial block (to set addnsub3_round_wire) -- The signal registered is addnsub3_round -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if addnsub3_round_register -- is unregistered and addnsub3_round changes value -- --------------------------------------------------------------------------------- if (addnsub3_round_register = "UNREGISTERED") then addnsub3_round_wire <= addnsub3_round; else if (((addnsub3_round_aclr = "ACLR0") and (aclr0 = '1')) or ((addnsub3_round_aclr = "ACLR1") and (aclr1 = '1')) or ((addnsub3_round_aclr = "ACLR2") and (aclr2 = '1')) or ((addnsub3_round_aclr = "ACLR3") and (aclr3 = '1'))) then addnsub3_round_wire <= '0'; elsif (((addnsub3_round_register = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((addnsub3_round_register = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((addnsub3_round_register = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((addnsub3_round_register = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1'))) then addnsub3_round_wire <= addnsub3_round; end if; end if; -- --------------------------------------------------------------------------------- -- This statement contains 1 register and a combinatorial block (to set addnsub3_round_pipe_wire) -- The signal registered is addnsub3_round_wire -- -- The register has an asynchronous clear and a clock enable signal -- NOTE: the combinatorial block is trigged if addnsub3_round_pipeline_register -- is unregistered and addnsub3_round_wire changes value -- --------------------------------------------------------------------------------- if (addnsub3_round_pipeline_register = "UNREGISTERED") then addnsub3_round_pipe_wire <= addnsub3_round_wire; else if (((addnsub3_round_pipeline_aclr = "ACLR0") and (aclr0 = '1')) or ((addnsub3_round_pipeline_aclr = "ACLR1") and (aclr1 = '1')) or ((addnsub3_round_pipeline_aclr = "ACLR2") and (aclr2 = '1')) or ((addnsub3_round_pipeline_aclr = "ACLR3") and (aclr3 = '1'))) then addnsub3_round_pipe_wire <= '0'; elsif (((addnsub3_round_pipeline_register = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((addnsub3_round_pipeline_register = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((addnsub3_round_pipeline_register = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((addnsub3_round_pipeline_register = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1'))) then addnsub3_round_pipe_wire <= addnsub3_round_wire; end if; end if; end process; -- ----------------------------------------------------------------------- -- This process block performs the multiplication of the two input numbers -- ----------------------------------------------------------------------- process (clock0, clock1, clock2, clock3, mult_aclr, mult_a, mult_b, sign_a_reg, sign_b_reg, mult01_round_wire, mult01_saturate_wire, mult23_round_wire, mult23_saturate_wire) variable mult_a_int : std_logic_vector (width_a -1 downto 0); variable mult_b_int : std_logic_vector (width_b -1 downto 0); variable mult_round_out : std_logic_vector (width_a + width_b - 1 downto 0) := (others => '0'); variable mult_result : std_logic_vector (width_a + width_b downto 0) := (others => '0'); variable mult_saturate_overflow : std_logic := '0'; variable mult_saturate_out : std_logic_vector (width_a + width_b downto 0) := (others => '0'); variable neg_a : std_logic := '0'; variable neg_b : std_logic := '0'; variable temp_mult_int : std_logic_vector ((width_a + width_b)-1 downto 0); variable mux_clock : std_logic; variable check_clock_out : string (1 to 6); variable x : integer; variable mult_round_bits : integer; variable zero_pad : std_logic := '0'; begin for i in 0 to (number_of_multipliers -1) loop x := i; if (i > 3) then x := 3; end if; mux_clock := mult_clock (x); check_clock_out := check_clock (x); if ((is_reg (x) = '1') and (mult_aclr (x) = '1')) then mult_res ( ((i+1)*(width_a + width_b))+i downto ((i*(width_a + width_b)) + i)) <= (others => '0'); mult_is_saturated(x) <= '0'; elsif (((check_clock_out = "CLOCK0") and clock0'event and (clock0='1') and (ena0 = '1')) or ((check_clock_out = "CLOCK1") and clock1'event and (clock1='1') and (ena1 = '1')) or ((check_clock_out = "CLOCK2") and clock2'event and (clock2='1') and (ena2 = '1')) or ((check_clock_out = "CLOCK3") and clock3'event and (clock3='1') and (ena3 = '1'))) or is_reg (x) = '0' then neg_a := '0'; neg_b := '0'; -- check if mult_a is to be interpreted a negative if (((representation_a = "SIGNED") and (signa = 'Z')) or (sign_a_reg = '1')) then neg_a := mult_a ( (i+1)*width_a-1); end if; -- check if mult_b is to be interpreted a negative if (((representation_b = "SIGNED") and (signb = 'Z')) or (sign_b_reg = '1')) then neg_b := mult_b ( (i+1)*width_b-1); end if; -- perfrom 2's complement mult_a is negative if (neg_a ='1') then mult_a_int := unsigned (not mult_a ( (i+1)*width_a-1 downto (i*width_a))) + 1; else mult_a_int := mult_a ( (i+1)*width_a-1 downto (i*width_a)); end if; -- perfrom 2's complement mult_b is negative if (neg_b ='1') then mult_b_int := unsigned (not mult_b ( (i+1)*width_b-1 downto (i*width_b))) + 1; else mult_b_int := mult_b ( (i+1)*width_b-1 downto (i*width_b)); end if; -- perfrom multiplication temp_mult_int := unsigned (temp_mult_zero) + unsigned(mult_a_int) * unsigned(mult_b_int); -- determining if the result should be a negative number -- based on the 2 input numbers if ((neg_a xor neg_b) = '1') then temp_mult_int := unsigned(temp_mult_zero) - unsigned(temp_mult_int); end if; if (IS_FAMILY_STRATIXII(intended_device_family)) then -- ------------------------------------------------------- -- Stratix II Rounding support -- This block basically carries out the rounding for the -- temp_mult_int. The equation to get the mult_round_out is -- obtained from the Stratix II Mac FFD which is below: -- round_adder_constant = (1 << (wfraction - wfraction_round - 1)) -- roundout[] = datain[] + round_adder_constant -- For Stratix II rounding, we round up the bits to 15 bits -- or in another word wfraction_round = 15. The sign bits would be 2 bits -- -------------------------------------------------------- if ((((x = 0) or (x = 1)) and ((multiplier01_rounding = "YES") or ((multiplier01_rounding = "VARIABLE") and (mult01_round_wire = '1')))) or (((x = 2) or (x = 3)) and ((multiplier23_rounding = "YES") or ((multiplier23_rounding = "VARIABLE") and (mult23_round_wire = '1'))))) then -- Here the value 17 is from the 2 bits of sign and the rounding for 15 bits mult_round_bits := (width_a + width_b) - 17; mult_round_out := unsigned (temp_mult_int) + ( 2 ** (mult_round_bits - 1)); else mult_round_out := temp_mult_int; end if; -- ------------------------------------------------------- -- Stratix II Saturation support -- This carries out the saturation for mult_round_out. -- The equation to get the saturated result is obtained -- from Stratix II MAC FFD which is below: -- satoverflow = 1 if sign bit is different -- satvalue[wtotal-1 : wfraction] = roundout[wtotal-1] -- satvalue[wfraction-1 : 0] = !roundout[wtotal-1] -- ------------------------------------------------------- if ((((x = 0) or (x = 1)) and ((multiplier01_saturation = "YES") or (( multiplier01_saturation = "VARIABLE") and (mult01_saturate_wire = '1')))) or (((x = 2) or (x = 3)) and ((multiplier23_saturation = "YES") or (( multiplier23_saturation = "VARIABLE") and (mult23_saturate_wire = '1'))))) then mult_saturate_overflow := (not mult_round_out(width_a + width_b - 1)) and (mult_round_out(width_a + width_b - 2)); mult_is_saturated(x) <= mult_saturate_overflow; if (mult_saturate_overflow = '0') then mult_saturate_out := mult_round_out & zero_pad; else -- We are doing the Q2.31 saturation, thus there is a bit -- insertion over here for i in (width_a + width_b) downto (width_a + width_b - 1) loop mult_saturate_out(i) := mult_round_out(width_a + width_b - 1); end loop; for i in (width_a + width_b - 2) downto 0 loop mult_saturate_out(i) := not mult_round_out(width_a + width_b - 1); end loop; end if; else mult_is_saturated(x) <= mult_saturate_overflow; mult_saturate_out := mult_round_out & zero_pad; end if; if ((((x = 0) or (x = 1)) and ((multiplier01_rounding = "YES") or (( multiplier01_rounding = "VARIABLE") and (mult01_round_wire = '1')))) or (((x = 2) or (x = 3)) and ((multiplier23_rounding = "YES") or (( multiplier23_rounding = "VARIABLE") and (mult23_round_wire = '1'))))) then mult_result := mult_saturate_out; for i in (mult_round_bits) downto 0 loop mult_result(i) := '0'; end loop; else mult_result := mult_saturate_out; end if; else mult_result := temp_mult_int & zero_pad; end if; mult_res ( ((i+1)*(width_a + width_b)) + i downto (i*(width_a + width_b) + i)) <= mult_result; end if; end loop; end process; -- ----------------------------------------------------------------- -- This is the main block that performs the addition and subtraction -- ----------------------------------------------------------------- process (clock0, clock1, clock2, clock3, aclr0, aclr1, aclr2, aclr3, mult_res, sign_a_reg, sign_b_reg, sign_a_pipe, sign_b_pipe, addsub_pipe1, addsub_pipe3, addsub_reg1, addsub_reg3, addnsub1_round_pipe_wire, addnsub3_round_pipe_wire, mult_is_saturated) variable head_result_int : integer := 0; variable do_add : boolean; variable asign : boolean; variable bsign : boolean; variable temp_sum : std_logic_vector (width_a + width_b + width_result downto 0) := (others => '0'); variable mult_res_temp : std_logic_vector ((width_a + width_b) downto 0); variable mult_res_ext : std_logic_vector (width_result-1 downto 0); variable adder_round_bits: integer; variable adder_result : std_logic_vector (width_result downto 0) := (others => '0'); variable adder_final_out : std_logic_vector (width_result - 1 downto 0) := (others => '0'); variable adder_round_out : std_logic_vector (width_result downto 0) := (others => '0'); begin if ((((output_aclr = "ACLR0") and (aclr0 = '1')) or ((output_aclr = "ACLR1") and (aclr1 = '1')) or ((output_aclr = "ACLR2") and (aclr2 = '1')) or ((output_aclr = "ACLR3") and (aclr3 = '1'))) and (not (output_register = "UNREGISTERED"))) then temp_sum := (others => '0'); result_pipe <= (others => (others => '0')); result <= (others => '0'); mult_is_saturated_pipe <= (others => '0'); elsif (((output_register = "CLOCK0") and (clock0 = '1') and clock0'event and (ena0 = '1')) or ((output_register = "CLOCK1") and (clock1 = '1') and clock1'event and (ena1 = '1')) or ((output_register = "CLOCK2") and (clock2 = '1') and clock2'event and (ena2 = '1')) or ((output_register = "CLOCK3") and (clock3 = '1') and clock3'event and (ena3 = '1')) or (output_register = "UNREGISTERED")) then temp_sum := (others => '0'); for i in 0 to (number_of_multipliers -1) loop -- use addsub_reg instead of addsub_pipe if -- addnsub_multiplier_pipeline_register is unregistered -- to determine the do_add flag if ((addnsub_multiplier_pipeline_register1 = "UNREGISTERED") and (addnsub_multiplier_pipeline_register3 = "UNREGISTERED"))then if (((i = 1) and (addsub_reg1 = '1')) or ((i = 3) and (addsub_reg3 = '1')) or ((i = 1) and (addnsub1 = 'Z') and (multiplier1_direction = "ADD")) or ((i = 3) and (addnsub3 = 'Z') and (multiplier3_direction = "ADD")) or (i = 0) or (i = 2) or (i > 3)) then do_add := true; else do_add := false; end if; elsif ((addnsub_multiplier_pipeline_register1 = "UNREGISTERED") and (not (addnsub_multiplier_pipeline_register3 = "UNREGISTERED")))then if (((i = 1) and (addsub_reg1 = '1')) or ((i = 3) and (addsub_pipe3 = '1')) or ((i = 1) and (addnsub1 = 'Z') and (multiplier1_direction = "ADD")) or ((i = 3) and (addnsub3 = 'Z') and (multiplier3_direction = "ADD")) or (i = 0) or (i = 2) or (i > 3)) then do_add := true; else do_add := false; end if; elsif ((not (addnsub_multiplier_pipeline_register1 = "UNREGISTERED")) and (addnsub_multiplier_pipeline_register3 = "UNREGISTERED")) then if (((i = 1) and (addsub_pipe1 = '1')) or ((i = 3) and (addsub_reg3 = '1')) or ((i = 1) and (addnsub1 = 'Z') and (multiplier1_direction = "ADD")) or ((i = 3) and (addnsub3 = 'Z') and (multiplier3_direction = "ADD")) or (i = 0) or (i = 2) or (i > 3)) then do_add := true; else do_add := false; end if; else if (((i = 1) and (addsub_pipe1 = '1')) or ((i = 3) and (addsub_pipe3 = '1')) or ((i = 1) and (addnsub1 = 'Z') and (multiplier1_direction = "ADD")) or ((i = 3) and (addnsub3 = 'Z') and (multiplier3_direction = "ADD")) or (i = 0) or (i = 2) or (i > 3)) then do_add := true; else do_add := false; end if; end if; mult_res_temp := mult_res( ((i+1)*(width_a + width_b) + i) downto ((i*(width_a + width_b)) + i)); -- Use sign_a_reg instead of sign_a_pipe when -- signed_pipeline_register_a is unregistered -- to set the asign flag if (signed_pipeline_register_a = "UNREGISTERED") then if ((sign_a_reg = '1') or ((signa = 'Z') and (representation_a = "SIGNED"))) then asign := true; else asign := false; end if; else if ((sign_a_pipe ='1') or ((signa = 'Z') and (representation_a = "SIGNED"))) then asign := true; else asign := false; end if; end if; -- Use sign_b_reg instead of sign_b_pipe when -- signed_pipeline_register_b is unregistered -- to set the bsign flag if (signed_pipeline_register_b = "UNREGISTERED") then if ((sign_b_reg ='1') or ((signb = 'Z') and (representation_b = "SIGNED"))) then bsign := true; else bsign := false; end if; else if ((sign_b_pipe ='1') or ((signb = 'Z') and (representation_b = "SIGNED"))) then bsign := true; else bsign := false; end if; end if; -- perform addition/subrtaction based ont he do_add flag if (do_add = true) then if ((asign = true) or (bsign = true)) then temp_sum := signed (temp_sum) + signed(mult_res_temp); else temp_sum := unsigned (temp_sum) + unsigned(mult_res_temp); end if; else if ((asign = true) or (bsign = true)) then temp_sum := signed (temp_sum) - signed(mult_res_temp); else temp_sum := unsigned (temp_sum) - unsigned(mult_res_temp); end if; end if; if (IS_FAMILY_STRATIXII(intended_device_family)) then -- ------------------------------------------------------- -- Stratix II Rounding support -- This block basically carries out the rounding for the -- temp_sum. The equation to get the adder_round_out is -- obtained from the Stratix II Mac FFD which is below: -- round_adder_constant = (1 << (wfraction - wfraction_round - 1)) -- roundout[] = datain[] + round_adder_constant -- For Stratix II rounding, we round up the bits to 15 bits -- or in another word wfraction_round = 15. -- -------------------------------------------------------- if (((i = 1) and ((adder1_rounding = "YES") or ((adder1_rounding = "VARIABLE") and (addnsub1_round_pipe_wire = '1')))) or ((i = 3) and ((adder3_rounding = "YES") or ((adder3_rounding = "VARIABLE") and (addnsub3_round_pipe_wire = '1'))))) then -- Here the value 17 is from the 2 bits of sign and the rounding for 15 bits -- Since adder always have an addition bits, thus the addition 1 bit adder_round_bits := (width_a + width_b) - 17 + 1; adder_round_out := signed (temp_sum(width_result downto 0)) + ( 2 ** (adder_round_bits - 1)); for j in (adder_round_bits - 1) downto 0 loop adder_round_out(j) := '0'; end loop; adder_result := adder_round_out; else adder_result := temp_sum(width_result downto 0); end if; end if; -- We shift one LSB bit out because we carry out width_a+width_b -- data input if (not IS_FAMILY_STRATIXII(intended_device_family)) then adder_final_out := temp_sum(width_result downto 1); else adder_final_out := adder_result(width_result downto 1); end if; end loop; -- for i in 0 to (number_of_multipliers -1) loop mult_is_saturated_pipe <= mult_is_saturated; if (extra_latency = 0) then result <= adder_final_out; else head_result_int := head_result; result_pipe (head_result_int) <= adder_final_out; head_result_int := (head_result_int +1) mod (extra_latency); result <= result_pipe(head_result_int); head_result <= head_result_int; end if; end if; end process; process (mult_is_saturated_pipe) begin -- We also need to update the multpilier saturated port. The reason we update it here -- is that the signal whether the multiplier is saturated or not can appear the same -- time as the adder result for num_mult in 0 to (number_of_multipliers -1) loop case num_mult is when 0 => if (port_mult0_is_saturated = "USED") then mult0_is_saturated <= mult_is_saturated_pipe(num_mult); end if; when 1 => if (port_mult1_is_saturated = "USED") then mult1_is_saturated <= mult_is_saturated_pipe(num_mult); end if; when 2 => if (port_mult2_is_saturated = "USED") then mult2_is_saturated <= mult_is_saturated_pipe(num_mult); end if; when 3 => if (port_mult3_is_saturated = "USED") then mult3_is_saturated <= mult_is_saturated_pipe(num_mult); end if; when others => assert false report "Error: Not supported number of multipliers in saturation"; end case; end loop; -- for i in 0 to (number_of_multipliers -1) loop end process; end behaviour; -- end of ALTMULT_ADD -- START ENTITY HEADER --------------------------------------------------------- -- -- Entity Name : altfp_mult -- -- Description : Parameterized floating point multiplier megafunction. -- This module implements IEEE-754 Compliant Floating Poing -- Multiplier. The module supports Single Precision, Single -- Extended Precision, and Double Precision floating point -- multiplication. -- -- Limitations : Fixed clock latency with 4 clock cycle delay. -- --Results expected : result of multiplication and the result's status bits -- END ENTITY HEADER ----------------------------------------------------------- -- LIBRARY USED----------------------------------------------------------------- library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; use work.ALTERA_COMMON_CONVERSION.all; -- ENTITY DECLARATION entity altfp_mult is -- GENERIC DECLARATION generic ( -- exponent width, Minimum = 8, Maximum = 31 width_exp : natural := 8; -- mantissa width, Minimum = 23, Maximum = 52 width_man : natural := 23; -- Specifies whether to use dedicated multiplier circuitry. dedicated_multiplier_circuitry : string := "AUTO"; reduced_functionality : string := "NO"; pipeline : natural := 5; lpm_hint : string := "UNUSED"; lpm_type : string := "altfp_mult" ); -- PORT DECLARATION port ( -- INPUT PORT DECLARATION -- Clock input to the multiplier.(Required) clock : in std_logic; -- Clock enable for the multiplier. clk_en : in std_logic := '1'; -- Asynchronous clear for the multiplier. aclr : in std_logic := '0'; -- Data input to the multiplier.(Required) dataa : in std_logic_vector(width_exp + width_man downto 0); datab : in std_logic_vector(width_exp + width_man downto 0); -- OUTPUT PORT DECLARATION -- Multiplier output port.(Required) result : out std_logic_vector(width_exp + width_man downto 0); overflow : out std_logic ; underflow : out std_logic ; zero : out std_logic; denormal : out std_logic ; indefinite : out std_logic; NaN : out std_logic ); end altfp_mult; -- END OF ENTITY -- BEGINNING OF ACHITECTURE -- ARCHITECTURE DECLARATION architecture behavior of altfp_mult is -- CONSTANT DECLARATION constant LATENCY : integer := pipeline -1; constant WIDTH_MAN_EXP : integer := width_exp + width_man; -- TYPE DECLARATION type PIPELINE_MULT is array (LATENCY downto 0) of std_logic_vector(WIDTH_MAN_EXP + 6 downto 0); -- FUNCTION DECLARATION -- Bitwise left shift procedure shift_left ( val : inout std_logic_vector) is variable temp : std_logic_vector((val'length - 1) downto 0); begin temp := val; if (val'length > 1) then for i in temp'high downto 1 loop temp(i) := temp(i-1); end loop; end if; temp(0) :='0'; val := temp; end shift_left; -- Bitwise right shift procedure shift_right ( cout: in std_logic; val : inout std_logic_vector ) is variable temp : std_logic_vector(val'length-1 downto 0); begin temp := val; if (val'length > 1) then for i in 0 to temp'high - 1 loop temp(i) := temp(i+1); end loop; end if; temp(temp'high) := cout; val := temp; end shift_right; -- Check whether all the bits is '0' or not function bit_all_0 ( val : std_logic_vector ) return boolean is variable all_0 : boolean := true; begin for i in val'range loop if (val(i) = '1') then all_0 := false; exit; end if; end loop; return all_0; end bit_all_0; -- Check whether all the bits is '0' or not (with specific range) function bit_all_0 ( val : std_logic_vector; index1 : integer; index2 : integer ) return boolean is variable all_0 : boolean := true; begin for i in index1 to index2 loop if (val(i) = '1') then all_0 := false; exit; end if; end loop; return all_0; end bit_all_0; -- add val1 to temporary result procedure add_bits( val1 : in std_logic_vector; result : inout std_logic_vector; cout : out std_logic) is variable co : std_logic; variable i : integer := 0; begin co := '0'; for i in 0 to val1'high loop if (co = '0') then if (val1(i) /= result(i + width_man + 1)) then result(i + width_man + 1) := '1'; else co := val1(i) and result(i + width_man + 1); result(i + width_man + 1) := '0'; end if; else co := val1(i) or result(i + width_man + 1); if (val1(i) /= result(i + width_man + 1)) then result(i + width_man + 1) := '0'; else result(i + width_man + 1) := '1'; end if; end if; end loop; cout := co; end add_bits; begin -- basic error checking for invalid deserialization factors MSG: process begin -- Check for illegal mode setting if ((width_exp + width_man) >= 64) then ASSERT FALSE REPORT "The sum of width_exp (" & INT_TO_STR_ARITH(width_exp) & ") and width_man (" & INT_TO_STR_ARITH(width_man) & ") must be less than 64" SEVERITY ERROR; end if; if (width_exp < 8) then ASSERT FALSE REPORT "width_exp (" & INT_TO_STR_ARITH(width_exp) & ") must be at least 8" SEVERITY ERROR; end if; if (width_man < 23) then ASSERT FALSE REPORT "width_man (" & INT_TO_STR_ARITH(width_man) & ") must be at least 23" SEVERITY ERROR; end if; if not ((width_exp >= 11) or ((width_exp = 8) and (width_man = 23))) then ASSERT FALSE REPORT "Found width_exp (" & INT_TO_STR_ARITH(width_exp) & ") inside the range of Single Precision. width_exp must be 8" & " and width_man must be 23 for Single Precision" SEVERITY ERROR; end if; if not ((width_man >= 31) or ((width_exp = 8) and (width_man = 23))) then ASSERT FALSE REPORT "Found width_man (" & INT_TO_STR_ARITH(width_man) & ") inside the range of Single Precision. width_exp must be 8" & " and width_man must be 23 for Single Precision" SEVERITY ERROR; end if; if (width_exp >= width_man) then ASSERT FALSE REPORT "width_exp (" & INT_TO_STR_ARITH(width_exp) & ") must be less than width_man (" & INT_TO_STR_ARITH(width_man) & ")" SEVERITY ERROR; end if; if ((pipeline /= 5) and (pipeline /= 6)) then ASSERT FALSE REPORT "The legal value for pipeline is 5 or 6." SEVERITY ERROR; end if; if ((reduced_functionality /= "NO") and (reduced_functionality /= "YES")) then ASSERT FALSE REPORT "reduced_functionality value must be ""YES"" or ""NO""." SEVERITY ERROR; end if; if (reduced_functionality /= "NO") then ASSERT FALSE REPORT "The Clearbox support is available for reduced functionality Floating Point Multiplier." SEVERITY WARNING; end if; wait; end process; -- MSG process MULTIPLY_FP: process(clock, clk_en, aclr) variable exp_dataa : integer := 0; variable exp_datab : integer := 0; variable exp_result : integer := 0; variable mant_dataa : std_logic_vector (width_man downto 0) := (others => '0'); variable mant_datab : std_logic_vector (width_man downto 0) := (others => '0'); variable mant_result : std_logic_vector ((2 * (width_man + 1)) - 1 downto 0) := (others => '0'); variable cout : std_logic := '0'; variable zero_mant_dataa : boolean := false; variable zero_mant_datab : boolean := false; variable zero_dataa : boolean := false; variable zero_datab : boolean := false; variable inf_dataa : boolean := false; variable inf_datab : boolean := false; variable NaN_dataa : boolean := false; variable NaN_datab : boolean := false; variable den_dataa : boolean := false; variable den_datab : boolean := false; variable no_multiply : boolean := false; variable no_rounding : boolean := false; variable mant_result_msb : std_logic := '0'; variable sticky_bit : std_logic := '0'; variable round_bit : std_logic := '0'; variable guard_bit : std_logic := '0'; variable carry : boolean := false; variable temp_result : PIPELINE_MULT := (others => (others => '0')); begin if (aclr = '1') then --clear the output ports temp_result := (others => (others => '0')); for i in LATENCY downto 0 loop temp_result(i)(WIDTH_MAN_EXP + 3) := '1'; -- set zero status end loop; result <= (others => '0'); overflow <= '0'; underflow <= '0'; zero <= '1'; denormal <= '0'; indefinite <= '0'; NaN <= '0'; elsif (clock = '1') and (clock'last_value = '0') and clock'event and (clk_en = '1') then -- Create latency for the output result for i in LATENCY downto 1 loop temp_result(i) := temp_result(i - 1); end loop; temp_result(0) := (others => '0'); mant_result := (others => '0'); --convert exponent of dataa[] to integer exp_dataa := 0; for i in 0 to width_exp -1 loop if (dataa(width_man + i) = '1') then exp_dataa := (2**i) + exp_dataa; end if; end loop; --convert exponent of datab[] to integer exp_datab := 0; for i in 0 to width_exp -1 loop if (datab(width_man + i) = '1') then exp_datab := (2**i) + exp_datab; end if; end loop; --check whether all the bits in mantissa of dataa[] is '0' zero_mant_dataa := true; for i in 0 to width_man -1 loop if (dataa(i) = '1') then zero_mant_dataa := false; exit; end if; end loop; --check whether all the bits in mantissa of datab[] is '0' zero_mant_datab := true; for i in 0 to width_man -1 loop if (datab(i) = '1') then zero_mant_datab := false; exit; end if; end loop; --check whether dataa is special input zero_dataa := false; den_dataa := false; inf_dataa := false; NaN_dataa := false; if (exp_dataa = 0) then if ((zero_mant_dataa = true) or (reduced_functionality /= "NO")) then zero_dataa := true; else den_dataa := true; end if; elsif (exp_dataa = (2**width_exp) -1) then if (zero_mant_dataa = true) then inf_dataa := true; else NaN_dataa := true; end if; end if; --check whether datab is special input zero_datab := false; den_datab := false; inf_datab := false; NaN_datab := false; if (exp_datab = 0) then if ((zero_mant_datab = true) or (reduced_functionality /= "NO")) then zero_datab := true; else den_datab := true; end if; elsif (exp_datab = (2**width_exp) -1) then if (zero_mant_datab = true) then inf_datab := true; else NaN_datab := true; end if; end if; --set status flag if special input exists no_multiply := false; if (NaN_dataa or NaN_datab or (inf_dataa and zero_datab) or (inf_datab and zero_dataa)) then temp_result(0)(WIDTH_MAN_EXP + 6) := '1'; --NaN temp_result(0)(WIDTH_MAN_EXP - 1 downto width_man -1) := (others => '1'); no_multiply := true; elsif (zero_dataa) then temp_result(0)(WIDTH_MAN_EXP + 3) := '1'; --zero result temp_result(0)(WIDTH_MAN_EXP downto 0) := (others => '0'); no_multiply := true; elsif (zero_datab) then temp_result(0)(WIDTH_MAN_EXP + 3) := '1'; --zero result temp_result(0)(WIDTH_MAN_EXP downto 0) := (others => '0'); no_multiply := true; elsif (inf_dataa) then temp_result(0)(WIDTH_MAN_EXP + 1) := '1'; --overflow temp_result(0)(WIDTH_MAN_EXP downto 0) := dataa; --result no_multiply := true; elsif (inf_datab) then temp_result(0)(WIDTH_MAN_EXP + 1) := '1'; --overflow temp_result(0)(WIDTH_MAN_EXP downto 0) := datab; --result no_multiply := true; end if; -- do multiplication if (no_multiply = false) then --perform exponent operation exp_result := (exp_dataa + exp_datab) - ((2**(width_exp -1)) - 1); -- mantissa multiplication --first operand for multiplication mant_dataa(width_man downto 0) := "1" & dataa(width_man - 1 downto 0); --second operand for multiplication mant_datab(width_man downto 0) := "1" & datab(width_man - 1 downto 0); --multiplication using add and shift algorithm for i in 0 to width_man loop cout := '0'; if (mant_dataa(i) = '1') then add_bits(mant_datab, mant_result, cout); end if; shift_right(cout, mant_result); end loop; sticky_bit := '0'; mant_result_msb := mant_result(mant_result'high); --Normalize the Result if (mant_result_msb = '1') then sticky_bit := mant_result(mant_result'low); shift_right('0', mant_result); exp_result := exp_result + 1; end if; round_bit := mant_result(width_man - 1); guard_bit := mant_result(width_man); no_rounding := false; -- check wether should perform rounding or not if (round_bit = '0') then no_rounding := true; else if (reduced_functionality = "NO") then for i in 0 to width_man - 2 loop sticky_bit := sticky_bit or mant_result(i); end loop; else sticky_bit := (mant_result(width_man - 2) and mant_result_msb); end if; if ((sticky_bit = '0') and (guard_bit = '0')) then no_rounding := true; end if; end if; if (no_rounding = false) then --do rounding carry := true; for i in width_man to mant_result'high loop if (carry = true) then if (mant_result(i) = '0') then mant_result(i) := '1'; carry := false; else mant_result(i) := '0'; end if; end if; end loop; --happen when bit pattern is 10.00... after rounding if (mant_result(mant_result'high) = '1') then shift_right('0', mant_result); exp_result := exp_result + 1; end if; end if; --Normalize the Result if ((not bit_all_0(mant_result)) and (mant_result(mant_result'high -1) = '0')) then while ((mant_result(mant_result'high -1) = '0') and (exp_result /= 0)) loop shift_left(mant_result); exp_result := exp_result - 1; end loop; elsif ((exp_result < 0) and (exp_result >= - (2 * width_man))) then while (exp_result /= 0) loop shift_right('0', mant_result); exp_result := exp_result + 1; end loop; end if; --set status flag "indefinite" if normal * denormal --(ignore other status port since we dont care the output if (den_dataa or den_datab) then temp_result(0)(WIDTH_MAN_EXP + 5) := '1'; --indefinite --set status flag if special output exists elsif (exp_result >= ((2**width_exp) - 1)) then temp_result(0)(WIDTH_MAN_EXP + 1) := '1'; --overflow elsif (exp_result < 0) then temp_result(0)(WIDTH_MAN_EXP + 2) := '1'; --underflow temp_result(0)(WIDTH_MAN_EXP + 3) := '1'; --zero elsif (exp_result = 0) then temp_result(0)(WIDTH_MAN_EXP + 2) := '1'; --underflow if (bit_all_0 (mant_result, width_man + 1, mant_result'high -1)) then temp_result(0)(WIDTH_MAN_EXP + 3) := '1'; --zero else temp_result(0)(WIDTH_MAN_EXP + 4) := '1'; --denormal end if; end if; --get result mantissa if (exp_result < 0) then --result underflow temp_result(0)(width_man - 1 downto 0) := (others => '0'); elsif (exp_result = 0) then --denormalized output if (reduced_functionality = "NO") then for i in (mant_result'high - 1) downto (mant_result'high - width_man) loop temp_result(0)(i - width_man - 1) := mant_result(i); end loop; else temp_result(0)(width_man - 1 downto 0) := (others => '0'); end if; elsif exp_result >= ((2**width_exp) -1) then --result overflow temp_result(0)(width_man - 1 downto 0) := (others => '0'); elsif (exp_result > 0) then --normalized output for i in (mant_result'high - 2) downto (mant_result'high - width_man - 1) loop temp_result(0)(i - width_man) := mant_result(i); end loop; end if; --get result exponent if (exp_result <= 0) then temp_result(0)(WIDTH_MAN_EXP -1 downto width_man) := (others => '0'); elsif (exp_result >= ((2**width_exp) -1)) then for i in width_man to (WIDTH_MAN_EXP -1) loop temp_result(0)(i) := '1'; end loop; else --convert integer to binary bit for i in width_man to (WIDTH_MAN_EXP -1) loop if ((exp_result mod 2) = 1) then temp_result(0)(i) := '1'; else temp_result(0)(i) := '0'; end if; exp_result := exp_result / 2; end loop; end if; end if; --get result sign temp_result(0)(WIDTH_MAN_EXP) := dataa(dataa'high) xor datab(datab'high); --output port result <= temp_result(LATENCY)(WIDTH_MAN_EXP downto 0 ); overflow <= temp_result(LATENCY)(WIDTH_MAN_EXP + 1 ); underflow <= temp_result(LATENCY)(WIDTH_MAN_EXP + 2 ); if (reduced_functionality = "NO") then zero <= temp_result(LATENCY)(WIDTH_MAN_EXP + 3 ); denormal <= temp_result(LATENCY)(WIDTH_MAN_EXP + 4 ); indefinite <= temp_result(LATENCY)(WIDTH_MAN_EXP + 5 ); else zero <= '0'; denormal <= '0'; indefinite <= '0'; end if; NaN <= temp_result(LATENCY)(WIDTH_MAN_EXP + 6 ); end if; end process MULTIPLY_FP; end behavior; -- altfp_mult -- END OF ARCHITECTURE -- START ENTITY HEADER --------------------------------------------------------- -- -- Entity Name : altsqrt -- -- Description : Parameterized integer square root megafunction. -- This module computes q[] and remainder so that -- q[]^2 + remainder[] == radical[] (remainder <= 2 * q[]) -- It can support the sequential mode(pipeline > 0) or -- combinational mode (pipeline = 0). -- -- Limitations : The radical is assumed to be unsigned integer. -- --Results expected : Square root of the radical and the remainder. -- END ENTITY HEADER ----------------------------------------------------------- -- LIBRARY USED library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; use work.ALTERA_COMMON_CONVERSION.all; -- ENTITY DECLARATION entity altsqrt is -- GENERIC DECLARATION generic ( q_port_width : integer := 1; -- The width of the q port r_port_width : integer := 1; -- The width of the remainder port width : integer := 1; -- The width of the radical pipeline : integer := 0; -- The latency for the output -- (0 for comb. mode) lpm_hint : string := "UNUSED"; lpm_type : string := "altsqrt" ); -- PORT DECLARATION port ( -- INPUT PORT DECLARATION -- Input port for the radical radical : in std_logic_vector(width - 1 downto 0); -- Clock port clk : in std_logic := '1'; -- Clock enable port ena : in std_logic := '1'; -- Asynchronous clear port aclr : in std_logic := '0'; -- OUTPUT PORT DECLARATION -- Output port for returning the square root of the radical q : out std_logic_vector( q_port_width - 1 downto 0) := (others => '0'); -- Output port for returning the remainder of the square root. remainder : out std_logic_vector( r_port_width - 1 downto 0) := (others => '0') ); end altsqrt; -- END OF ENTITY -- BEGINNING OF ARCHITECTURE architecture behavior of altsqrt is -- TYPE DECLARATION type PIPELINE_Q is array (pipeline downto 0) of std_logic_vector( q_port_width downto 0); type PIPELINE_R is array (pipeline downto 0) of std_logic_vector( r_port_width - 1 downto 0); begin -- PROCESS DECLARATION -- Perform square root calculation. -- In general, below are the steps to calculate the square root and the -- remainder. -- -- Start of with q = 0 and remainder= 0 -- For every iteration, do the same thing: -- 1) Shift in the next 2 bits of the radical into the remainder -- Eg. if the radical is b"101100". For the first iteration, -- the remainder will be equal to b"10". -- 2) Compare it to the 4* q + 1 -- 3) if the remainder is greater than or equal to 4*q + 1 -- remainder = remainder - (4*q + 1) -- q = 2*q + 1 -- otherwise -- q = 2*q SQUARE_ROOT: process(clk, ena, aclr, radical) variable value1 : integer := 0; variable value2 : integer := 0; variable head : integer := 0; variable i : integer := 0; variable q_value_temp : integer := 0; variable r_value_temp : integer := 0; variable index : integer := 0; variable q_index : integer := 0; variable q_temp : std_logic_vector (q_port_width - 1 downto 0) := (others => '0'); variable r_temp : std_logic_vector (r_port_width - 1 downto 0) := (others => '0'); variable q_pipeline : PIPELINE_Q := (others => (others => '0')); variable remainder_pipeline : PIPELINE_R := (others => (others => '0')); variable pipeline_int : integer := 1; begin if (pipeline = 0) then pipeline_int := 1; else pipeline_int := pipeline; end if; -- if asychoronous clear signal has been asserted if (aclr = '1') then -- reset variables and clear the output port q_pipeline := (others => (others => '0')); remainder_pipeline := (others => (others => '0')); q <= (others => '0'); remainder <= (others => '0'); -- When clk is enabled and is rising with no asyn. clear (reg mode) -- or radical has change (comb. mode), -- perform the square root calculation. elsif (((clk = '1') and (clk'last_value = '0') and clk'event and (ena = '1')) or (pipeline = 0)) then -- Check for illegal mode if (width < 1) then ASSERT FALSE REPORT "width (" & INT_TO_STR_ARITH(width) & ") must be greater than 0." SEVERITY ERROR; end if; -- Reset variables value1 := 0; value2 := 0; q_index := (width - 1) / 2; q_value_temp := 0; r_value_temp := 0; index := width; q_temp := (others => '0'); r_temp := (others => '0'); -- If the number of the bits of the radical is an odd number, -- Then for the first iteration, only the 1st bit will be shifted -- into the remainder. -- Eg. if the radical is b"11111", then the remainder is b"01". if ((width rem 2) = 1) then value1 := 0; if (radical(width - 1) = '1') then value2 := 1; else value2 := 0; end if; index := index + 1; else -- Otherwise, for the first iteration, the first two bits will be -- shifted into the remainder. -- Eg. if the radical is b"101111", then the remainder is b"10". if (radical(width - 1) = '1') then value1 := 1; else value1 := 0; end if; if (radical(width - 2) = '1') then value2 := 1; else value2 := 0; end if; end if; -- For every iteration while (index >= 2) loop -- Get the remainder value by shift in the next 2 bits -- of the radical into the remainder r_value_temp := (r_value_temp * 4) + (2 * value1) + value2; -- if remainder >= (4*q + 1) if (r_value_temp >= (4 * q_value_temp) + 1) then -- remainder = remainder - (4*q + 1) r_value_temp := r_value_temp - (4 * q_value_temp) - 1; -- q = 2*q + 1 q_value_temp := (2 * q_value_temp) + 1; -- set the q[q_index] = 1 q_temp(q_index) := '1'; else -- if remainder < (4*q + 1) -- q = 2*q q_value_temp := 2 * q_value_temp; -- set the q[q_index] = 0 q_temp(q_index) := '0'; end if; index := index - 2; -- if not the last iteration, get the next 2 bits of the radical if (index >= 2) then if (radical(index - 1) = '1') then value1 := 1; else value1 := 0; end if; if (radical(index - 2) = '1') then value2 := 1; else value2 := 0; end if; end if; -- Reduce the current index of the q by 1 q_index := q_index - 1; end loop; -- Get the binary bits of the remainder by converting integer to -- binary bits for i in 0 to (width + 1) / 2 loop if ((r_value_temp rem 2) = 1) then r_temp(i) := '1'; else r_temp(i) := '0'; end if; r_value_temp := r_value_temp / 2; end loop; -- Store current result into the pipeline to create latency remainder_pipeline(head) := r_temp; q_pipeline(head)(q_port_width - 1 downto 0) := q_temp; head := (head + 1) rem pipeline_int; -- Output value remainder <= remainder_pipeline(head); q <= q_pipeline(head)(q_port_width - 1 downto 0); end if; end process SQUARE_ROOT; end behavior; -- altsqrt -- END OF ARCHITECTURE -- START ENTITY HEADER --------------------------------------------------------- -- -- Entity Name : ALTCLKLOCK -- -- Description : Phase-Locked Loop (PLL) behavioral model. Supports basic -- PLL features such as multiplication and division of input -- clock frequency and phase shift. -- -- Limitations : Model supports NORMAL operation mode only. External -- feedback mode and zero-delay-buffer mode are not simulated. -- Applicable to APEX, Mercury and FLEX10KE device families -- only. -- -- Expected results : Up to 4 clock outputs (clock0, clock1, clock2, clock_ext). -- clock2 and clock_ext are for Mercury devices only. -- locked output indicates when PLL locks. -- -- END ENTITY HEADER ----------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use work.ALTERA_DEVICE_FAMILIES.all; -- ENTITY DECLARATION entity altclklock is generic( inclock_period : natural := 10000; -- units in ps inclock_settings : string := "UNUSED"; valid_lock_cycles : natural := 5; invalid_lock_cycles : natural := 5; valid_lock_multiplier : natural := 5; invalid_lock_multiplier : natural := 5; operation_mode : string := "NORMAL"; clock0_boost : natural := 1; clock0_divide : natural := 1; clock0_settings : string := "UNUSED"; clock0_time_delay : string := "0"; clock1_boost : natural := 1; clock1_divide : natural := 1; clock1_settings : string := "UNUSED"; clock1_time_delay : string := "0"; clock2_boost : natural := 1; clock2_divide : natural := 1; clock2_settings : string := "UNUSED"; clock2_time_delay : string := "0"; clock_ext_boost : natural := 1; clock_ext_divide : natural := 1; clock_ext_settings : string := "UNUSED"; clock_ext_time_delay : string := "0"; outclock_phase_shift : natural := 0; -- units in ps intended_device_family : string := "APEX20KE" ; lpm_type : string := "altclklock" ); port( inclock : in std_logic; -- required port, input reference clock inclocken : in std_logic := '1'; -- PLL enable signal fbin : in std_logic := '1'; -- feedback input for the PLL clock0 : out std_logic; -- clock0 output clock1 : out std_logic; -- clock1 output clock2 : out std_logic; -- clock2 output, for Mercury only clock_ext : out std_logic; -- external clock output, for Mercury only locked : out std_logic -- PLL lock signal ); -- -- function time_delay - converts time_delay in string format to time, and -- add result to outclock_phase_shift -- function time_delay (s : string) return time is -- VARIABLE DECLARATION variable outclock_phase_shift_adj : integer := 0; variable len : integer := s'length; variable sign : integer := 1; variable digit : integer := 0; begin for i in 1 to len loop case s(i) is when '-' => if (i = 1) then sign := -1; else ASSERT FALSE REPORT "Illegal Character "& s(i) & "in string parameter! " SEVERITY ERROR; end if; when '0' => digit := 0; when '1' => digit := 1; when '2' => digit := 2; when '3' => digit := 3; when '4' => digit := 4; when '5' => digit := 5; when '6' => digit := 6; when '7' => digit := 7; when '8' => digit := 8; when '9' => digit := 9; when others => ASSERT FALSE REPORT "Illegal Character "& s(i) & "in string parameter! " SEVERITY ERROR; end case; outclock_phase_shift_adj := (outclock_phase_shift_adj * 10) + digit; end loop; -- add outclock phase shift to the time delay outclock_phase_shift_adj := outclock_phase_shift + (sign * outclock_phase_shift_adj); -- adjust phase shift so that it is between 0 and 1 full inclock_period while (outclock_phase_shift_adj < 0) loop outclock_phase_shift_adj := outclock_phase_shift_adj + inclock_period; end loop; while (outclock_phase_shift_adj >= inclock_period) loop outclock_phase_shift_adj := outclock_phase_shift_adj - inclock_period; end loop; -- return the phase shift in ps return (outclock_phase_shift_adj * 1 ps); end; end altclklock; -- END ENTITY DECLARATION -- BEGINNING OF ARCHITECTURE BEHAVIOR architecture behavior of altclklock is -- SIGNAL DECLARATION SIGNAL pll_lock : std_logic := '0'; SIGNAL check_lock : std_logic := '0'; SIGNAL clk0_tmp : std_logic := 'X'; SIGNAL clk1_tmp : std_logic := 'X'; SIGNAL clk2_tmp : std_logic := 'X'; SIGNAL extclk_tmp : std_logic := 'X'; begin -- checking for invalid parameters MSG: process begin if (inclock_period <= 0) then ASSERT FALSE REPORT "The period of the input clock (inclock_period) must be greater than 0" SEVERITY ERROR; end if; if ((clock0_boost <= 0) or (clock0_divide <= 0)) then ASSERT FALSE REPORT "The multiplication and division factors for clock0 must be greater than 0" SEVERITY ERROR; end if; if ((clock1_boost <= 0) or (clock1_divide <= 0)) then ASSERT FALSE REPORT "The multiplication and division factors for clock1 must be greater than 0" SEVERITY ERROR; end if; if ((clock2_boost <= 0) or (clock2_divide <= 0)) then ASSERT FALSE REPORT "The multiplication and division factors for clock2 must be greater than 0" SEVERITY ERROR; end if; if ((clock_ext_boost <= 0) or (clock_ext_divide <= 0)) then ASSERT FALSE REPORT "The multiplication and division factors for clock_ext must be greater than 0" SEVERITY ERROR; end if; if ((IS_FAMILY_FLEX10KE(intended_device_family) = false) and (IS_FAMILY_APEX20K(intended_device_family) = false) and (IS_FAMILY_APEX20KE(intended_device_family) = false) and (IS_FAMILY_APEXII(intended_device_family) = false) and (IS_FAMILY_MERCURY(intended_device_family) = false)) then ASSERT FALSE REPORT "Device family specified by the intended_device_family parameter, "& intended_device_family &", may not be supported by altclklock" SEVERITY WARNING; end if; wait; end process MSG; LOCK: process(inclock, inclocken, pll_lock, check_lock) -- VARIABLE DECLARATION variable inclk_ps : time := 0 ps; variable violation : boolean := false; variable pll_lock_tmp : std_logic := '0'; variable start_lock_count, stop_lock_count : integer := 0; variable pll_last_rising_edge, pll_last_falling_edge : time := 0 ps; variable pll_rising_edge_count : integer := 0; variable pll_cycle, pll_duty_cycle : time := 0 ps; variable expected_next_clk_edge : time := 0 ps; variable clk_per_tolerance : time := 0 ps; variable last_synchronizing_rising_edge_for_clk0 : time := 0 ps; variable last_synchronizing_rising_edge_for_clk1 : time := 0 ps; variable last_synchronizing_rising_edge_for_clk2 : time := 0 ps; variable last_synchronizing_rising_edge_for_extclk : time := 0 ps; variable input_cycles_per_clk0 : integer := clock0_divide; variable input_cycles_per_clk1 : integer := clock1_divide; variable input_cycles_per_clk2 : integer := clock2_divide; variable input_cycles_per_extclk : integer := clock_ext_divide; variable input_cycle_count_to_sync0 : integer := 0; variable input_cycle_count_to_sync1 : integer := 0; variable input_cycle_count_to_sync2 : integer := 0; variable input_cycle_count_to_sync_extclk : integer := 0; variable init : boolean := true; variable output_value : std_logic := '0'; variable vco_per : time := 0 ps; variable high_time : time := 0 ps; variable low_time : time := 0 ps; variable sched_time : time := 0 ps; variable tmp_per : integer := 0; variable temp, tmp_rem, my_rem : integer := 0; variable inc : integer := 1; variable cycle_to_adjust : integer := 0; variable clk0_synchronizing_period, clk1_synchronizing_period : time; variable clk2_synchronizing_period, extclk_synchronizing_period : time; variable clk0_cycles_per_sync_period : integer := clock0_boost; variable clk1_cycles_per_sync_period : integer := clock1_boost; variable clk2_cycles_per_sync_period : integer := clock2_boost; variable extclk_cycles_per_sync_period : integer := clock_ext_boost; variable schedule_clk0, schedule_clk1 : boolean := false; variable schedule_clk2, schedule_extclk : boolean := false; variable clk0_phase_delay : time := time_delay(clock0_time_delay); variable clk1_phase_delay : time := time_delay(clock1_time_delay); variable clk2_phase_delay : time := time_delay(clock2_time_delay); variable extclk_phase_delay : time := time_delay(clock_ext_time_delay); begin if (init) then if ((clock0_boost rem clock0_divide) = 0) then clk0_cycles_per_sync_period := clock0_boost / clock0_divide; input_cycles_per_clk0 := 1; end if; if ((clock1_boost rem clock1_divide) = 0) then clk1_cycles_per_sync_period := clock1_boost / clock1_divide; input_cycles_per_clk1 := 1; end if; if ((clock2_boost rem clock2_divide) = 0) then clk2_cycles_per_sync_period := clock2_boost / clock2_divide; input_cycles_per_clk2 := 1; end if; if ((clock_ext_boost rem clock_ext_divide) = 0) then extclk_cycles_per_sync_period := clock_ext_boost / clock_ext_divide; input_cycles_per_extclk := 1; end if; if (IS_FAMILY_MERCURY(intended_device_family)) then clk_per_tolerance := (0.025 * real(inclock_period)) * 1 ps; else clk_per_tolerance := (0.1 * real(inclock_period)) * 1 ps; end if; init := false; end if; if (inclocken = '0') then pll_lock_tmp := '0'; pll_rising_edge_count := 0; elsif (inclock'event and inclock = '1') then if (pll_lock_tmp = '1') then check_lock <= not check_lock after (inclk_ps+clk_per_tolerance)/2.0; end if; if pll_rising_edge_count = 0 then -- at 1st rising edge inclk_ps := (inclock_period / 1) * 1 ps; pll_duty_cycle := inclk_ps/2; elsif pll_rising_edge_count = 1 then -- at 2nd rising edge pll_cycle := now - pll_last_rising_edge; -- calculate period if ((NOW - pll_last_rising_edge) < (inclk_ps - clk_per_tolerance) or (NOW - pll_last_rising_edge) > (inclk_ps + clk_per_tolerance)) then ASSERT FALSE REPORT "Inclock_Period Violation" SEVERITY WARNING; violation := true; if (pll_lock = '1') then stop_lock_count := stop_lock_count + 1; if (stop_lock_count = invalid_lock_cycles) then pll_lock_tmp := '0'; ASSERT FALSE REPORT "altclklock out of lock." SEVERITY WARNING; end if; else start_lock_count := 1; end if; else violation := false; end if; if ((now - pll_last_falling_edge) < (pll_duty_cycle - clk_per_tolerance/2) or (now - pll_last_falling_edge) > (pll_duty_cycle + clk_per_tolerance/2)) then ASSERT FALSE REPORT "Duty Cycle Violation" SEVERITY WARNING; violation := true; else violation := false; end if; else pll_cycle := now - pll_last_rising_edge; -- calculate period if ((now - pll_last_rising_edge) < (inclk_ps - clk_per_tolerance) or (now - pll_last_rising_edge) > (inclk_ps + clk_per_tolerance)) then ASSERT FALSE REPORT "Cycle Violation" SEVERITY WARNING; violation := true; if (pll_lock = '1') then stop_lock_count := stop_lock_count + 1; if (stop_lock_count = invalid_lock_cycles) then pll_lock_tmp := '0'; ASSERT FALSE REPORT "altclklock out of lock." SEVERITY WARNING; end if; else start_lock_count := 1; end if; else violation := false; end if; end if; pll_last_rising_edge := now; pll_rising_edge_count := pll_rising_edge_count +1; if (not violation) then if (pll_lock_tmp = '1') then input_cycle_count_to_sync0 := input_cycle_count_to_sync0 + 1; if (input_cycle_count_to_sync0 = input_cycles_per_clk0) then clk0_synchronizing_period := now - last_synchronizing_rising_edge_for_clk0; last_synchronizing_rising_edge_for_clk0 := now; schedule_clk0 := true; input_cycle_count_to_sync0 := 0; end if; input_cycle_count_to_sync1 := input_cycle_count_to_sync1 + 1; if (input_cycle_count_to_sync1 = input_cycles_per_clk1) then clk1_synchronizing_period := now - last_synchronizing_rising_edge_for_clk1; last_synchronizing_rising_edge_for_clk1 := now; schedule_clk1 := true; input_cycle_count_to_sync1 := 0; end if; input_cycle_count_to_sync2 := input_cycle_count_to_sync2 + 1; if (input_cycle_count_to_sync2 = input_cycles_per_clk2) then clk2_synchronizing_period := now - last_synchronizing_rising_edge_for_clk2; last_synchronizing_rising_edge_for_clk2 := now; schedule_clk2 := true; input_cycle_count_to_sync2 := 0; end if; input_cycle_count_to_sync_extclk := input_cycle_count_to_sync_extclk + 1; if (input_cycle_count_to_sync_extclk = input_cycles_per_extclk) then extclk_synchronizing_period := now - last_synchronizing_rising_edge_for_extclk; last_synchronizing_rising_edge_for_extclk := now; schedule_extclk := true; input_cycle_count_to_sync_extclk := 0; end if; else if ((IS_FAMILY_APEXII(intended_device_family) = false) or (pll_rising_edge_count-1 > 0)) then start_lock_count := start_lock_count + 1; if (start_lock_count >= valid_lock_cycles) then pll_lock_tmp := '1'; input_cycle_count_to_sync0 := 0; input_cycle_count_to_sync1 := 0; input_cycle_count_to_sync2 := 0; input_cycle_count_to_sync_extclk := 0; clk0_synchronizing_period := ((pll_cycle/1 ps) * input_cycles_per_clk0) * 1 ps; clk1_synchronizing_period := ((pll_cycle/1 ps) * input_cycles_per_clk1) * 1 ps; clk2_synchronizing_period := ((pll_cycle/1 ps) * input_cycles_per_clk2) * 1 ps; extclk_synchronizing_period := ((pll_cycle/1 ps) * input_cycles_per_extclk) * 1 ps; last_synchronizing_rising_edge_for_clk0 := now; last_synchronizing_rising_edge_for_clk1 := now; last_synchronizing_rising_edge_for_clk2 := now; last_synchronizing_rising_edge_for_extclk := now; schedule_clk0 := true; schedule_clk1 := true; schedule_clk2 := true; schedule_extclk := true; end if; end if; end if; else if (IS_FAMILY_MERCURY(intended_device_family)) then start_lock_count := 0; else start_lock_count := 1; end if; end if; elsif (inclock'event and inclock= '0') then if (pll_lock_tmp = '1') then check_lock <= not check_lock after (inclk_ps+clk_per_tolerance)/2.0; if (now > 0 ns and ((now - pll_last_rising_edge) < (pll_duty_cycle - clk_per_tolerance/2) or (now - pll_last_rising_edge) > (pll_duty_cycle + clk_per_tolerance/2))) then ASSERT FALSE REPORT "Duty Cycle Violation" SEVERITY WARNING; violation := true; if (pll_lock = '1') then stop_lock_count := stop_lock_count + 1; if (stop_lock_count = invalid_lock_cycles) then pll_lock_tmp := '0'; ASSERT FALSE REPORT "altclklock out of lock." SEVERITY WARNING; end if; end if; else violation := false; end if; elsif ((IS_FAMILY_APEXII(intended_device_family) = false) or (pll_rising_edge_count > 0)) then start_lock_count := start_lock_count + 1; end if; pll_last_falling_edge := now; else if pll_lock_tmp = '1' then if (inclock = '1') then expected_next_clk_edge := pll_last_rising_edge + (inclk_ps+clk_per_tolerance)/2.0; else expected_next_clk_edge := pll_last_falling_edge + (inclk_ps+clk_per_tolerance)/2.0; end if; violation := false; if (now < expected_next_clk_edge) then check_lock <= not check_lock after (expected_next_clk_edge - now); elsif (now = expected_next_clk_edge) then check_lock <= not check_lock after (inclk_ps+clk_per_tolerance)/2.0; else ASSERT FALSE REPORT "Inclock_Period Violation" SEVERITY WARNING; violation := true; if (pll_lock = '1') then stop_lock_count := stop_lock_count + 1; if (stop_lock_count = invalid_lock_cycles) then pll_lock_tmp := '0'; ASSERT FALSE REPORT "altclklock out of lock." SEVERITY WARNING; else check_lock <= not check_lock after (inclk_ps/2.0); end if; end if; end if; end if; end if; pll_lock <= pll_lock_tmp; if (pll_lock'event and pll_lock = '0') then if (IS_FAMILY_APEX20KE(intended_device_family)) then start_lock_count := 0; else start_lock_count := 1; end if; stop_lock_count := 0; clk0_tmp <= 'X'; clk1_tmp <= 'X'; clk2_tmp <= 'X'; extclk_tmp <= 'X'; end if; -- clock0 output if (schedule_clk0 = true) then -- initialize variables sched_time := clk0_phase_delay; cycle_to_adjust := 0; inc := 1; output_value := '1'; temp := clk0_synchronizing_period / 1 ps; my_rem := temp rem clk0_cycles_per_sync_period; -- schedule number of output clock -- cycles in this loop in order to synchronize the output clock to the -- input clock - to get rid of drifting for cases where the input clock -- period is not always divisible for i in 1 to clk0_cycles_per_sync_period loop tmp_per := temp/clk0_cycles_per_sync_period; if ((my_rem /= 0) and (inc <= my_rem)) then tmp_rem := (clk0_cycles_per_sync_period * inc) rem my_rem; cycle_to_adjust := (clk0_cycles_per_sync_period * inc) / my_rem; if (tmp_rem /= 0) then cycle_to_adjust := cycle_to_adjust + 1; end if; end if; -- if this cycle is the one to adjust the output period in, then -- increment the period by 1 unit if (cycle_to_adjust = i) then tmp_per := tmp_per + 1; inc := inc + 1; end if; -- adjust the high and low cycle period vco_per := tmp_per * 1 ps; high_time := (tmp_per / 2) * 1 ps; if ((tmp_per rem 2) /= 0) then high_time := high_time + 1 ps; end if; low_time := vco_per - high_time; -- schedule the high and low cycle of 1 output clock period for j in 1 to 2 loop clk0_tmp <= transport output_value after sched_time; output_value := not output_value; if (output_value = '0') then sched_time := sched_time + high_time; elsif (output_value = '1') then sched_time := sched_time + low_time; end if; end loop; end loop; -- reset schedule_clk0 schedule_clk0 := false; end if; -- schedule_clk0 if (schedule_clk1 = true) then -- initialize variables sched_time := clk1_phase_delay; cycle_to_adjust := 0; inc := 1; output_value := '1'; temp := clk1_synchronizing_period / 1 ps; my_rem := temp rem clk1_cycles_per_sync_period; -- schedule number of output clock -- cycles in this loop in order to synchronize the output clock to the -- input clock - to get rid of drifting for cases where the input clock -- period is not always divisible for i in 1 to clk1_cycles_per_sync_period loop tmp_per := temp/clk1_cycles_per_sync_period; if ((my_rem /= 0) and (inc <= my_rem)) then tmp_rem := (clk1_cycles_per_sync_period * inc) rem my_rem; cycle_to_adjust := (clk1_cycles_per_sync_period * inc) / my_rem; if (tmp_rem /= 0) then cycle_to_adjust := cycle_to_adjust + 1; end if; end if; -- if this cycle is the one to adjust the output period in, then -- increment the period by 1 unit if (cycle_to_adjust = i) then tmp_per := tmp_per + 1; inc := inc + 1; end if; -- adjust the high and low cycle period vco_per := tmp_per * 1 ps; high_time := (tmp_per/2) * 1 ps; if ((tmp_per rem 2) /= 0) then high_time := high_time + 1 ps; end if; low_time := vco_per - high_time; -- schedule the high and low cycle of 1 output clock period for j in 1 to 2 loop clk1_tmp <= transport output_value after sched_time; output_value := not output_value; if (output_value = '0') then sched_time := sched_time + high_time; elsif (output_value = '1') then sched_time := sched_time + low_time; end if; end loop; end loop; -- reset schedule_clk1 schedule_clk1 := false; end if; -- schedule_clk1 -- for Mercury devices only if (IS_FAMILY_MERCURY(intended_device_family)) then -- clock2 output if (schedule_clk2 = true) then -- initialize variables sched_time := clk2_phase_delay; cycle_to_adjust := 0; inc := 1; output_value := '1'; temp := clk2_synchronizing_period/1 ps; my_rem := temp rem clk2_cycles_per_sync_period; -- schedule number of output clock -- cycles in this loop in order to synchronize the output clock to the -- input clock - to get rid of drifting for cases where the input clock -- period is not always divisible for i in 1 to clk2_cycles_per_sync_period loop tmp_per := temp/clk2_cycles_per_sync_period; if ((my_rem /= 0) and (inc <= my_rem)) then tmp_rem := (clk2_cycles_per_sync_period * inc) rem my_rem; cycle_to_adjust := (clk2_cycles_per_sync_period * inc) / my_rem; if (tmp_rem /= 0) then cycle_to_adjust := cycle_to_adjust + 1; end if; end if; -- if this cycle is the one to adjust the output period in, then -- increment the period by 1 unit if (cycle_to_adjust = i) then tmp_per := tmp_per + 1; inc := inc + 1; end if; -- adjust the high and low cycle period vco_per := tmp_per * 1 ps; high_time := (tmp_per/2) * 1 ps; if ((tmp_per rem 2) /= 0) then high_time := high_time + 1 ps; end if; low_time := vco_per - high_time; -- schedule the high and low cycle of 1 output clock period for j in 1 to 2 loop clk2_tmp <= transport output_value after sched_time; output_value := not output_value; if (output_value = '0') then sched_time := sched_time + high_time; elsif (output_value = '1') then sched_time := sched_time + low_time; end if; end loop; end loop; -- reset schedule_clk2 schedule_clk2 := false; end if; -- schedule_clk2 -- clock_ext output if (schedule_extclk = true) then -- initialize variables sched_time := extclk_phase_delay; cycle_to_adjust := 0; inc := 1; output_value := '1'; temp := extclk_synchronizing_period/1 ps; my_rem := temp rem extclk_cycles_per_sync_period; -- schedule number of output clock -- cycles in this loop in order to synchronize the output clock to the -- input clock - to get rid of drifting for cases where the input clock -- period is not always divisible for i in 1 to extclk_cycles_per_sync_period loop tmp_per := temp/extclk_cycles_per_sync_period; if ((my_rem /= 0) and (inc <= my_rem)) then tmp_rem := (extclk_cycles_per_sync_period * inc) rem my_rem; cycle_to_adjust := (extclk_cycles_per_sync_period * inc) / my_rem; if (tmp_rem /= 0) then cycle_to_adjust := cycle_to_adjust + 1; end if; end if; -- if this cycle is the one to adjust the output period in, then -- increment the period by 1 unit if (cycle_to_adjust = i) then tmp_per := tmp_per + 1; inc := inc + 1; end if; -- adjust the high and low cycle period vco_per := tmp_per * 1 ps; high_time := (tmp_per/2) * 1 ps; if ((tmp_per rem 2) /= 0) then high_time := high_time + 1 ps; end if; low_time := vco_per - high_time; -- schedule the high and low cycle of 1 output clock period for j in 1 to 2 loop extclk_tmp <= transport output_value after sched_time; output_value := not output_value; if (output_value = '0') then sched_time := sched_time + high_time; elsif (output_value = '1') then sched_time := sched_time + low_time; end if; end loop; end loop; -- reset schedule_extclk schedule_extclk := false; end if; -- schedule_extclk end if; -- for Mercury only end process LOCK; clock0 <= clk0_tmp; clock1 <= clk1_tmp; clock2 <= clk2_tmp; clock_ext <= extclk_tmp; locked <= pll_lock; end behavior; -- END ARCHITECTURE BEHAVIOR -- START ENTITY NAME ----------------------------------------------------------- -- -- Entity Name : ALTDDIO_IN -- -- Description : Double Data Rate (DDR) input behavioural model. Receives -- data on both edges of the reference clock. -- -- Limitations : Not available for FLEX, MAX, APEX20K and APEX20KE device -- families. -- -- Expected results : Data sampled from the datain port at the rising edge of -- the reference clock (dataout_h) and at the falling edge of -- the reference clock (dataout_l). -- -- END ENTITY NAME ------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use work.ALTERA_DEVICE_FAMILIES.all; -- ENTITY DECLARATION entity altddio_in is generic ( width : positive; -- required parameter intended_device_family : string := "MERCURY"; power_up_high : string := "OFF"; lpm_type : string := "altddio_in" ); port ( datain : in std_logic_vector(width-1 downto 0); -- required port, DDR -- input data inclock : in std_logic := '0'; -- input reference clock inclocken : in std_logic := '1'; -- input clock enable signal aset : in std_logic := '0'; -- asynchronous set aclr : in std_logic := '0'; -- asynchronous clear dataout_h : out std_logic_vector(width-1 downto 0); --data sampled at --rising edge of inclock dataout_l : out std_logic_vector(width-1 downto 0) --data sampled at --falling edge of inclock ); end altddio_in; -- END ENTITY DECLARATION -- BEGINNING OF ARCHITECTURE BEHAVE architecture behave of altddio_in is begin -- checking for invalid parameters MSG: process begin if (width <= 0) then ASSERT FALSE REPORT "The width parameter must be greater than 0" SEVERITY ERROR; end if; if (IS_VALID_FAMILY(intended_device_family) = false) then ASSERT FALSE REPORT intended_device_family & " is not a valid device family!" SEVERITY ERROR; end if; if (not (IS_FAMILY_APEXII(intended_device_family) or IS_FAMILY_MERCURY(intended_device_family) or IS_FAMILY_ACEX2K(intended_device_family) or IS_FAMILY_STRATIXGX(intended_device_family) or IS_FAMILY_STRATIX(intended_device_family) or IS_FAMILY_STRATIXII(intended_device_family))) then ASSERT FALSE REPORT "Megafunction altddio_out is not supported in " & intended_device_family &"!" SEVERITY ERROR; end if; wait; end process MSG; process (inclock, aset, aclr) -- VARIABLE DECLARATION variable dataout_h_tmp : std_logic_vector(width-1 downto 0) := (OTHERS=>'0'); variable dataout_l_tmp : std_logic_vector(width-1 downto 0) := (OTHERS=>'0'); variable datain_latched : std_logic_vector(width-1 downto 0) := (OTHERS=>'0'); variable need_init : boolean := true; begin -- power up registers according the power_up_high parameter setting if ((NOW = 0 ps) or (need_init = true)) then if (power_up_high = "OFF") then dataout_h_tmp := (others => '0'); dataout_l_tmp := (others => '0'); datain_latched := (others => '0'); else dataout_h_tmp := (others => '1'); dataout_l_tmp := (others => '1'); datain_latched := (others => '1'); end if; need_init := false; end if; -- asynchronous clear is asserted if (aclr = '1') then dataout_h_tmp := (others => '0'); dataout_l_tmp := (others => '0'); datain_latched := (others => '0'); -- else asynchronous set is asserted elsif (aset = '1') then dataout_h_tmp := (others => '1'); dataout_l_tmp := (others => '1'); datain_latched := (others => '1'); -- not being cleared or preset -- rising edge of inclock elsif (inclock'event and (inclock = '1')) then if (inclocken = '1') then dataout_h_tmp := datain; dataout_l_tmp := datain_latched; end if; -- falling edge of inclock elsif (inclock'event and (inclock = '0')) then if (IS_FAMILY_APEXII(intended_device_family) or IS_FAMILY_ACEX2K(intended_device_family) or IS_FAMILY_STRATIXGX(intended_device_family) or IS_FAMILY_STRATIX(intended_device_family) or IS_FAMILY_STRATIXII(intended_device_family)) then if (inclocken = '1') then datain_latched := datain; end if; elsif (IS_FAMILY_MERCURY(intended_device_family)) then datain_latched := datain; else -- for future families datain_latched := datain; end if; end if; -- assign variables to output ports dataout_l <= dataout_l_tmp; dataout_h <= dataout_h_tmp; end process; end behave; -- END ARCHITECTURE BEHAVE -- START ENTITY NAME ----------------------------------------------------------- -- -- Entity Name : ALTDDIO_OUT -- -- Description : Double Data Rate (DDR) output behavioural model. -- Transmits data on both edges of the reference clock. -- -- Limitations : Not available for FLEX, MAX, APEX20K and APEX20KE device -- families. -- -- Expected results : Double data rate output on dataout. -- --END ENTITY NAME ------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use work.ALTERA_DEVICE_FAMILIES.all; -- ENTITY DECLARATION entity altddio_out is generic ( width : positive; -- required parameter power_up_high : string := "OFF"; oe_reg : string := "UNUSED"; extend_oe_disable : string := "UNUSED"; intended_device_family : string := "MERCURY"; lpm_type : string := "altddio_out" ); port ( datain_h : in std_logic_vector(width-1 downto 0);--required port, data --input for the rising --edge of outclock datain_l : in std_logic_vector(width-1 downto 0);--required port, data --input for the falling --edge of outclock outclock : in std_logic; -- required port, input reference clock to output -- data by outclocken : in std_logic := '1'; -- clock enable signal for outclock aset : in std_logic := '0'; -- asynchronous set aclr : in std_logic := '0'; -- asynchronous clear oe : in std_logic := '1'; -- output enable for dataout dataout : out std_logic_vector(width-1 downto 0) -- DDR data output ); end altddio_out; -- END ENTITY DECLARATION -- BEGINNING OF ARCHITECTURE BEHAVE architecture behave of altddio_out is -- SIGNAL DECLARATION signal dataout_h : std_logic_vector(width-1 downto 0) := (OTHERS=>'0'); signal dataout_l : std_logic_vector(width-1 downto 0) := (OTHERS=>'0'); signal oe_rgd : std_logic := '0'; signal oe_reg_ext : std_logic := '0'; signal apexii_oe : std_logic; signal output_enable : std_logic; begin -- checking for invalid parameters MSG: process begin if (width <= 0) then ASSERT FALSE REPORT "The width parameter must be greater than 0" SEVERITY ERROR; end if; if (IS_VALID_FAMILY(intended_device_family) = false) then ASSERT FALSE REPORT intended_device_family & " is not a valid device family!" SEVERITY ERROR; end if; if (not (IS_FAMILY_APEXII(intended_device_family) or IS_FAMILY_MERCURY(intended_device_family) or IS_FAMILY_ACEX2K(intended_device_family) or IS_FAMILY_STRATIXGX(intended_device_family) or IS_FAMILY_STRATIX(intended_device_family) or IS_FAMILY_STRATIXII(intended_device_family))) then ASSERT FALSE REPORT "Megafunction altddio_out is not supported in " & intended_device_family &"!" SEVERITY ERROR; end if; wait; end process MSG; -- output enable signals output_enable <= apexii_oe when (IS_FAMILY_APEXII(intended_device_family) or IS_FAMILY_ACEX2K(intended_device_family) or IS_FAMILY_STRATIXGX(intended_device_family) or IS_FAMILY_STRATIX(intended_device_family) or IS_FAMILY_STRATIXII(intended_device_family)) else oe; apexii_oe <= (oe_reg_ext and oe_rgd) when (extend_oe_disable = "ON") else oe_rgd when ((oe_reg = "REGISTERED") and (extend_oe_disable /= "ON")) else oe; REGS: process (outclock, aset, aclr) -- VARIABLE DECLARATION variable need_init : boolean := true; begin -- power up the registers according to the power_up_high parameter setting if ((NOW = 0 ps) or (need_init = true)) then if (power_up_high = "OFF") then dataout_h <= (others => '0'); dataout_l <= (others => '0'); oe_rgd <= '0'; oe_reg_ext <= '0'; else dataout_h <= (others => '1'); dataout_l <= (others => '1'); oe_rgd <= '1'; oe_reg_ext <= '1'; end if; need_init := false; end if; -- asynchronous clear is asserted if (aclr = '1') then dataout_h <= (others => '0'); dataout_l <= (others => '0'); oe_rgd <= '0'; oe_reg_ext <= '0'; -- else if asynchronous set is asserted elsif (aset = '1') then dataout_h <= (others => '1'); dataout_l <= (others => '1'); oe_rgd <= '1'; oe_reg_ext <= '1'; -- else outclock is triggered elsif (outclocken = '1') then -- rising edge of outclock if (outclock = '1') then dataout_h <= datain_h; dataout_l <= datain_l; oe_rgd <= oe; else -- falling edge of outclock oe_reg_ext <= oe_rgd; end if; end if; end process REGS; DATA_OUTPUT: process(outclock, dataout_h, dataout_l, output_enable) begin if (output_enable = '1') then if (outclock = '1') then dataout <= dataout_h; else dataout <= dataout_l; end if; else -- output is not enabled dataout <= (others => 'Z'); end if; end process DATA_OUTPUT; end behave; -- END ARCHITECTURE BEHAVE -- START ENTITY NAME ----------------------------------------------------------- -- -- Entity Name : ALTDDIO_BIDIR -- -- Description : Double Data Rate (DDR) bi-directional behavioural model. -- Transmits and receives data on both edges of the reference -- clock. -- -- Limitations : Not available for FLEX, MAX, APEX20K and APEX20KE device -- families. -- -- Expected results : Data output sampled from padio port on rising edge of -- inclock signal (dataout_h) and falling edge of inclock -- signal (dataout_l). Combinatorial output fed by padio -- directly (combout). -- --END ENTITY NAME -------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; -- ENTITY DECLARATION entity altddio_bidir is generic( width : positive; -- required parameter power_up_high : string := "OFF"; oe_reg : string := "UNUSED"; extend_oe_disable : string := "UNUSED"; implement_input_in_lcell : string := "UNUSED"; intended_device_family : string := "MERCURY"; lpm_type : string := "altddio_bidir" ); port ( datain_h : in std_logic_vector(width-1 downto 0); --input data to be --output of padio port --at the rising edge of --outclock datain_l : in std_logic_vector(width-1 downto 0); --input data to be --output of padio port --at the falling edge of --outclock inclock : in std_logic := '0'; -- input reference clock to sample DDR input. inclocken : in std_logic := '1'; -- inclock enable outclock : in std_logic; -- input reference clock to register data output outclocken : in std_logic := '1'; -- outclock enable aset : in std_logic := '0'; -- asynchronour set aclr : in std_logic := '0'; -- asynchronous clear oe : in std_logic := '1'; -- output enable for padio port dataout_h : out std_logic_vector(width-1 downto 0); --data sampled from the --padio port at the --rising edge of --inclock dataout_l : out std_logic_vector(width-1 downto 0); --data sampled from the --padio port at the --falling edge of --inclock combout : out std_logic_vector(width-1 downto 0); --combinatorial output --directly fed by padio dqsundelayedout : out std_logic_vector(width-1 downto 0); -- undelayed DQS signal to -- the PLD core padio : inout std_logic_vector(width-1 downto 0) --bidirectional DDR --port ); end altddio_bidir; -- END ENTITY DECLARATION -- BEGINNING ARCHITECTURE STRUCT architecture struct of altddio_bidir is -- COMPONENT DECLARATION component altddio_in generic ( width : positive := 1; intended_device_family : string := "MERCURY"; power_up_high : string := "OFF" ); port ( datain : in std_logic_vector(width-1 downto 0); inclock : in std_logic; inclocken : in std_logic := '1'; aset : in std_logic := '0'; aclr : in std_logic := '0'; dataout_h : out std_logic_vector(width-1 downto 0); dataout_l : out std_logic_vector(width-1 downto 0) ); end component; component altddio_out generic ( width : positive := 1; power_up_high : string := "OFF"; intended_device_family : string := "MERCURY"; oe_reg : string := "UNUSED"; extend_oe_disable : string := "UNUSED" ); port ( datain_h : in std_logic_vector(width-1 downto 0); datain_l : in std_logic_vector(width-1 downto 0); outclock : in std_logic; outclocken : in std_logic := '1'; aset : in std_logic := '0'; aclr : in std_logic := '0'; oe : in std_logic := '1'; dataout : out std_logic_vector(width-1 downto 0) ); end component; begin -- checking for invalid parameters MSG: process begin if (width <= 0) then ASSERT FALSE REPORT "The width parameter must be greater than 0" SEVERITY ERROR; end if; wait; end process MSG; -- COMPONENT INSTANTIATION U1: altddio_in generic map ( width => width, intended_device_family => intended_device_family, power_up_high => power_up_high ) port map ( datain => padio, inclock => inclock, inclocken => inclocken, aset => aset, aclr => aclr, dataout_h => dataout_h, dataout_l => dataout_l ); U2: altddio_out generic map ( width => width, power_up_high => power_up_high, intended_device_family => intended_device_family, oe_reg => oe_reg, extend_oe_disable => extend_oe_disable ) port map ( datain_h => datain_h, datain_l => datain_l, outclock => outclock, outclocken => outclocken, aset => aset, aclr => aclr, oe => oe, dataout => padio ); -- assign padio to feed combout port combout <= padio; dqsundelayedout <= padio; end struct; -- END ARCHITECTURE STRUCT Library ieee; use ieee.std_logic_1164.all; -- START PACKAGE HEADER -------------------------------------------------------- -- -- Package Name : pllpack -- -- Description : Used by altpll model to calculate required advanced parameters -- for PLL simulation. Also has functions to do string->integer, -- integer->string conversions. -- -- END PACKAGE HEADER ---------------------------------------------------------- -- PACKAGE DECLARATION package pllpack is -- FUNCTION DECLARATION function alt_conv_integer(arg : in std_logic_vector) return integer; function gcd (X: integer; Y: integer) return integer; function lcm (A1: integer; A2: integer; A3: integer; A4: integer; A5: integer; A6: integer; A7: integer; A8: integer; A9: integer; A10: integer; P: integer) return integer; function output_counter_value (clk_divide: integer; clk_mult : integer; M: integer; N: integer ) return integer; function counter_mode (duty_cycle: integer; output_counter_value: integer) return string; function counter_high (output_counter_value: integer := 1; duty_cycle: integer) return integer; function counter_low (output_counter_value: integer; duty_cycle: integer) return integer; function mintimedelay (t1: integer; t2: integer; t3: integer; t4: integer; t5: integer; t6: integer; t7: integer; t8: integer; t9: integer; t10: integer) return integer; function maxnegabs (t1: integer; t2: integer; t3: integer; t4: integer; t5: integer; t6: integer; t7: integer; t8: integer; t9: integer; t10: integer) return integer; function counter_time_delay (clk_time_delay: integer; m_time_delay: integer; n_time_delay: integer) return integer; function get_phase_degree (phase_shift: integer; clk_period: integer) return integer; function counter_initial (tap_phase: integer; m: integer; n: integer) return integer; function counter_ph (tap_phase: integer; m : integer; n: integer) return integer; function ph_adjust (tap_phase: integer; ph_base : integer) return integer; function translate_string (mode : string) return string; function str2int (s : string) return integer; function int2str (value : integer) return string; end pllpack; -- BEGINNING OF PACKAGE package body pllpack is -- convert std_logic_vector to integer function alt_conv_integer(arg : in std_logic_vector) return integer is variable result : integer := 0; begin result := 0; for i in arg'range loop if arg(i) = '1' then result := result + 2**i; end if; end loop; return result; end alt_conv_integer; -- find the greatest common denominator of X and Y function gcd (X: integer; Y: integer) return integer is variable L, S, R, G : integer := 1; begin if (X < Y) then -- find which is smaller. S := X; L := Y; else S := Y; L := X; end if; R := S; while ( R > 1) loop S := L; L := R; R := S rem L; -- divide bigger number by smaller. -- remainder becomes smaller number. end loop; if (R = 0) then -- if evenly divisible then L is gcd else it is 1. G := L; else G := R; end if; return G; end gcd; -- find the least common multiple of A1 to A10 function lcm (A1: integer; A2: integer; A3: integer; A4: integer; A5: integer; A6: integer; A7: integer; A8: integer; A9: integer; A10: integer; P: integer) return integer is variable M1, M2, M3, M4, M5 , M6, M7, M8, M9, R: integer := 1; begin M1 := (A1 * A2)/gcd(A1, A2); M2 := (M1 * A3)/gcd(M1, A3); M3 := (M2 * A4)/gcd(M2, A4); M4 := (M3 * A5)/gcd(M3, A5); M5 := (M4 * A6)/gcd(M4, A6); M6 := (M5 * A7)/gcd(M5, A7); M7 := (M6 * A8)/gcd(M6, A8); M8 := (M7 * A9)/gcd(M7, A9); M9 := (M8 * A10)/gcd(M8, A10); if (M9 < 3) then R := 10; elsif ((M9 < 10) and (M9 >= 3)) then R := 4 * M9; else R := M9 ; end if; return R; end lcm; -- find the factor of division of the output clock frequency compared to the VCO function output_counter_value (clk_divide: integer; clk_mult: integer ; M: integer; N: integer ) return integer is variable R: integer := 1; begin R := (clk_divide * M)/(clk_mult * N); return R; end output_counter_value; -- find the mode of each PLL counter - bypass, even or odd function counter_mode (duty_cycle: integer; output_counter_value: integer) return string is variable R: string (1 to 6) := " "; variable counter_value: integer := 1; begin counter_value := (2*duty_cycle*output_counter_value)/100; if output_counter_value = 1 then R := "bypass"; elsif (counter_value REM 2) = 0 then R := " even"; else R := " odd"; end if; return R; end counter_mode; -- find the number of VCO clock cycles to hold the output clock high function counter_high (output_counter_value: integer := 1; duty_cycle: integer) return integer is variable R: integer := 1; variable half_cycle_high : integer := 1; begin half_cycle_high := (duty_cycle * output_counter_value *2)/100 ; if (half_cycle_high REM 2 = 0) then R := half_cycle_high/2 ; else R := (half_cycle_high/2) + 1; end if; return R; end; -- find the number of VCO clock cycles to hold the output clock low function counter_low (output_counter_value: integer; duty_cycle: integer) return integer is variable R, R1: integer := 1; variable half_cycle_high : integer := 1; begin half_cycle_high := (duty_cycle * output_counter_value*2)/100 ; if (half_cycle_high REM 2 = 0) then R1 := half_cycle_high/2 ; else R1 := (half_cycle_high/2) + 1; end if; R := output_counter_value - R1; return R; end; -- find the smallest time delay amongst t1 to t10 function mintimedelay (t1: integer; t2: integer; t3: integer; t4: integer; t5: integer; t6: integer; t7: integer; t8: integer; t9: integer; t10: integer) return integer is variable m1,m2,m3,m4,m5,m6,m7,m8,m9 : integer := 0; begin if (t1 < t2) then m1 := t1; else m1 := t2; end if; if (m1 < t3) then m2 := m1; else m2 := t3; end if; if (m2 < t4) then m3 := m2; else m3 := t4; end if; if (m3 < t5) then m4 := m3; else m4 := t5; end if; if (m4 < t6) then m5 := m4; else m5 := t6; end if; if (m5 < t7) then m6 := m5; else m6 := t7; end if; if (m6 < t8) then m7 := m6; else m7 := t8; end if; if (m7 < t9) then m8 := m7; else m8 := t9; end if; if (m8 < t10) then m9 := m8; else m9 := t10; end if; if (m9 > 0) then return m9; else return 0; end if; end; -- find the numerically largest negative number, and return its absolute value function maxnegabs (t1: integer; t2: integer; t3: integer; t4: integer; t5: integer; t6: integer; t7: integer; t8: integer; t9: integer; t10: integer) return integer is variable m1,m2,m3,m4,m5,m6,m7,m8,m9 : integer := 0; begin if (t1 < t2) then m1 := t1; else m1 := t2; end if; if (m1 < t3) then m2 := m1; else m2 := t3; end if; if (m2 < t4) then m3 := m2; else m3 := t4; end if; if (m3 < t5) then m4 := m3; else m4 := t5; end if; if (m4 < t6) then m5 := m4; else m5 := t6; end if; if (m5 < t7) then m6 := m5; else m6 := t7; end if; if (m6 < t8) then m7 := m6; else m7 := t8; end if; if (m7 < t9) then m8 := m7; else m8 := t9; end if; if (m8 < t10) then m9 := m8; else m9 := t10; end if; if (m9 < 0) then return (0 - m9); else return 0; end if; end; -- adjust the phase (tap_phase) with the largest negative number (ph_base) function ph_adjust (tap_phase: integer; ph_base : integer) return integer is begin return (tap_phase + ph_base); end; -- find the time delay for each PLL counter function counter_time_delay (clk_time_delay: integer; m_time_delay: integer; n_time_delay: integer) return integer is variable R: integer := 0; begin R := clk_time_delay + m_time_delay - n_time_delay; return R; end; -- calculate the given phase shift (in ps) in terms of degrees function get_phase_degree (phase_shift: integer; clk_period: integer) return integer is variable result: integer := 0; begin result := ( phase_shift * 360 ) / clk_period; -- to round up the calculation result if (result > 0) then result := result + 1; elsif (result < 0) then result := result - 1; else result := 0; end if; return result; end; -- find the number of VCO clock cycles to wait initially before the first rising -- edge of the output clock function counter_initial (tap_phase: integer; m: integer; n: integer) return integer is variable R: integer; variable R1: real; begin R1 := (real(abs(tap_phase)) * real(m))/(360.0 * real(n)) + 0.5; -- Note NCSim VHDL had problem in rounding up for 0.5 - 0.99. -- This checking will ensure that the rounding up is done. if (R1 >= 0.5) and (R1 <= 1.0) then R1 := 1.0; end if; R := integer(R1); return R; end; -- find which VCO phase tap (0 to 7) to align the rising edge of the output clock to function counter_ph (tap_phase: integer; m: integer; n: integer) return integer is variable R: integer := 0; begin -- 0.5 is added for proper rounding of the tap_phase. R := (integer(real(tap_phase * m / n)+ 0.5) REM 360)/45; return R; end; -- convert given string to length 6 by padding with spaces function translate_string (mode : string) return string is variable new_mode : string (1 to 6) := " "; begin if (mode = "bypass") then new_mode := "bypass"; elsif (mode = "even") then new_mode := " even"; elsif (mode = "odd") then new_mode := " odd"; end if; return new_mode; end; -- convert integer to string function int2str( value : integer ) return string is variable ivalue : integer := 0; variable index : integer := 1; variable digit : integer := 0; variable temp: string(10 downto 1) := "0000000000"; begin ivalue := value; index := 1; while (ivalue > 0) loop digit := ivalue mod 10; ivalue := ivalue/10; case digit is when 0 => temp(index) := '0'; when 1 => temp(index) := '1'; when 2 => temp(index) := '2'; when 3 => temp(index) := '3'; when 4 => temp(index) := '4'; when 5 => temp(index) := '5'; when 6 => temp(index) := '6'; when 7 => temp(index) := '7'; when 8 => temp(index) := '8'; when 9 => temp(index) := '9'; when others => ASSERT FALSE REPORT "Illegal number!" SEVERITY ERROR; end case; index := index + 1; end loop; if (value < 0) then return ('-'& temp(index downto 1)); else return temp(index downto 1); end if; end int2str; -- convert string to integer function str2int (s : string) return integer is variable len : integer := s'length; variable newdigit : integer := 0; variable sign : integer := 1; variable digit : integer := 0; begin for i in 1 to len loop case s(i) is when '-' => if i = 1 then sign := -1; else ASSERT FALSE REPORT "Illegal Character "& s(i) & "i n string parameter! " SEVERITY ERROR; end if; when '0' => digit := 0; when '1' => digit := 1; when '2' => digit := 2; when '3' => digit := 3; when '4' => digit := 4; when '5' => digit := 5; when '6' => digit := 6; when '7' => digit := 7; when '8' => digit := 8; when '9' => digit := 9; when others => ASSERT FALSE REPORT "Illegal Character "& s(i) & "in string parameter! " SEVERITY ERROR; end case; newdigit := newdigit * 10 + digit; end loop; return (sign*newdigit); end; end pllpack; -- END OF PACKAGE pllpack library ieee; use ieee.std_logic_1164.all; -- DFFP entity DFFP is port( CLK : in std_logic; ENA : in std_logic := '1'; D : in std_logic; CLRN : in std_logic := '1'; PRN : in std_logic := '1'; Q : out std_logic ); end DFFP; architecture behave of DFFP is begin process (CLK, PRN, CLRN) begin if (PRN = '0') then Q <= '1'; elsif (CLRN = '0') then Q <= '0'; elsif (CLK'event and (ENA = '1')) then Q <= D; end if; end process; end behave; --/////////////////////////////////////////////////////////////////////////// -- -- Entity Name : MF_mn_cntr -- -- Description : Simulation model for the M and N counter. This is a -- common model for the input counter and the loop feedback -- counter of the Stratix PLL and Stratix II PLL. -- --/////////////////////////////////////////////////////////////////////////// library ieee; use IEEE.std_logic_1164.all; entity MF_mn_cntr is port ( clk : IN std_logic; reset : IN std_logic := '0'; cout : OUT std_logic; initial_value : IN integer := 1; modulus : IN integer := 1; time_delay : IN integer := 0; ph : IN integer := 0 ); end MF_mn_cntr; architecture behave of MF_mn_cntr is begin process (clk, reset) variable count : integer := 1; variable first_rising_edge : boolean := true; variable tmp_cout : std_logic; begin if (reset = '1') then count := 1; tmp_cout := '0'; first_rising_edge := true; elsif (clk'event and clk = '1' and first_rising_edge) then first_rising_edge := false; tmp_cout := clk; elsif (not first_rising_edge) then if (count < modulus) then count := count + 1; else count := 1; tmp_cout := not tmp_cout; end if; end if; cout <= transport tmp_cout after time_delay * 1 ps; end process; end behave; --///////////////////////////////////////////////////////////////////////////// -- -- Entity Name : stx_scale_cntr -- -- Description : Simulation model for the output scale-down counters. -- This is a common model for the L0, L1, G0, G1, G2, G3, E0, -- E1, E2 and E3 output counters of the Stratix PLL. -- --///////////////////////////////////////////////////////////////////////////// library ieee; use IEEE.std_logic_1164.all; entity stx_scale_cntr is port ( clk : IN std_logic; reset : IN std_logic := '0'; initial : IN integer := 1; high : IN integer := 1; low : IN integer := 1; mode : IN string := "bypass"; time_delay : IN integer := 0; ph_tap : IN natural := 0; cout : OUT std_logic ); end stx_scale_cntr; architecture behave of stx_scale_cntr is begin process (clk, reset) variable tmp_cout : std_logic := '0'; variable count : integer := 1; variable output_shift_count : integer := 0; variable first_rising_edge : boolean := false; variable high_reg : integer := 0; variable low_reg : integer := 0; variable init : boolean := true; begin if (reset = '1') then count := 1; output_shift_count := 0; tmp_cout := '0'; first_rising_edge := false; elsif (clk'event) then if (init) then init := false; high_reg := high; low_reg := low; end if; if (mode = " off") then tmp_cout := '0'; elsif (mode = "bypass") then tmp_cout := clk; elsif (not first_rising_edge) then if (clk = '1') then output_shift_count := output_shift_count + 1; if (output_shift_count = initial) then tmp_cout := clk; first_rising_edge := true; end if; end if; elsif (output_shift_count < initial) then if (clk = '1') then output_shift_count := output_shift_count + 1; end if; else count := count + 1; if (mode = " even" and (count = (high_reg*2) + 1)) then tmp_cout := '0'; low_reg := low; elsif (mode = " odd" and (count = high_reg*2)) then tmp_cout := '0'; low_reg := low; elsif (count = (high_reg + low_reg)*2 + 1) then tmp_cout := '1'; count := 1; -- reset count high_reg := high; end if; end if; end if; cout <= transport tmp_cout after time_delay * 1 ps; end process; end behave; --///////////////////////////////////////////////////////////////////////////// -- -- Entity Name : arm_scale_cntr -- -- Description : Simulation model for the output scale-down counters. -- This is a common model for the C0, C1, C2, C3, C4 and C5 -- output counters of the Stratix II PLL. -- --///////////////////////////////////////////////////////////////////////////// library ieee; use IEEE.std_logic_1164.all; entity arm_scale_cntr is port ( clk : IN std_logic; reset : IN std_logic := '0'; initial : IN integer := 1; high : IN integer := 1; low : IN integer := 1; mode : IN string := "bypass"; ph_tap : IN integer := 0; cout : OUT std_logic ); end arm_scale_cntr; architecture behave of arm_scale_cntr is begin process (clk, reset) variable tmp_cout : std_logic := '0'; variable count : integer := 1; variable output_shift_count : integer := 1; variable first_rising_edge : boolean := false; begin if (reset = '1') then count := 1; output_shift_count := 1; tmp_cout := '0'; first_rising_edge := false; elsif (clk'event) then if (mode = " off") then tmp_cout := '0'; elsif (mode = "bypass") then tmp_cout := clk; first_rising_edge := true; elsif (not first_rising_edge) then if (clk = '1') then if (output_shift_count = initial) then tmp_cout := clk; first_rising_edge := true; else output_shift_count := output_shift_count + 1; end if; end if; elsif (output_shift_count < initial) then if (clk = '1') then output_shift_count := output_shift_count + 1; end if; else count := count + 1; if (mode = " even" and (count = (high*2) + 1)) then tmp_cout := '0'; elsif (mode = " odd" and (count = high*2)) then tmp_cout := '0'; elsif (count = (high + low)*2 + 1) then tmp_cout := '1'; count := 1; -- reset count end if; end if; end if; cout <= transport tmp_cout; end process; end behave; --///////////////////////////////////////////////////////////////////////////// -- -- Entity Name : MF_pll_reg -- -- Description : Simulation model for a simple DFF. -- This is required for the generation of the bit slip-signals. -- No timing, powers upto 0. -- --///////////////////////////////////////////////////////////////////////////// LIBRARY ieee; USE IEEE.std_logic_1164.all; ENTITY MF_pll_reg is PORT ( clk : in std_logic; ena : in std_logic := '1'; d : in std_logic; clrn : in std_logic := '1'; prn : in std_logic := '1'; q : out std_logic ); end MF_pll_reg; ARCHITECTURE behave of MF_pll_reg is begin process (clk, prn, clrn) variable q_reg : std_logic := '0'; begin if (prn = '0') then q_reg := '1'; elsif (clrn = '0') then q_reg := '0'; elsif (clk'event and clk = '1' and (ena = '1')) then q_reg := D; end if; Q <= q_reg; end process; end behave; --/////////////////////////////////////////////////////////////////////////// -- -- START ENTITY HEADER --------------------------------------------------------- -- -- Entity Name : MF_STRATIX_PLL -- -- Description : The behavioral model for Stratix PLL -- -- Limitations : Applies to the Stratix and Stratix GX device families -- No support for spread spectrum feature in the model -- -- Expected results : Up to 10 output clocks, each defined by its own set of -- parameters. Locked output (active high) indicates when the -- PLL locks. clkbad, clkloss and activeclock are used for -- clock switchover to inidicate which input clock has gone -- bad, when the clock switchover initiates and which input -- clock is being used as the reference, respectively. -- scandataout is the data output of the serial scan chain. -- -- END ENTITY HEADER ----------------------------------------------------------- library ieee, altera_mf; use IEEE.std_logic_1164.all; use work.pllpack.all; use altera_mf.altera_mf_components.all; entity MF_stratix_pll is generic ( operation_mode : string := "normal"; qualify_conf_done : string := "off"; compensate_clock : string := "clk0"; pll_type : string := "auto"; -- EGPP/FAST/AUTO scan_chain : string := "long"; clk0_multiply_by : integer := 1; clk0_divide_by : integer := 1; clk0_phase_shift : string := "0"; clk0_time_delay : string := "0"; clk0_duty_cycle : integer := 50; clk1_multiply_by : integer := 1; clk1_divide_by : integer := 1; clk1_phase_shift : string := "0"; clk1_time_delay : string := "0"; clk1_duty_cycle : integer := 50; clk2_multiply_by : integer := 1; clk2_divide_by : integer := 1; clk2_phase_shift : string := "0"; clk2_time_delay : string := "0"; clk2_duty_cycle : integer := 50; clk3_multiply_by : integer := 1; clk3_divide_by : integer := 1; clk3_phase_shift : string := "0"; clk3_time_delay : string := "0"; clk3_duty_cycle : integer := 50; clk4_multiply_by : integer := 1; clk4_divide_by : integer := 1; clk4_phase_shift : string := "0"; clk4_time_delay : string := "0"; clk4_duty_cycle : integer := 50; clk5_multiply_by : integer := 1; clk5_divide_by : integer := 1; clk5_phase_shift : string := "0"; clk5_time_delay : string := "0"; clk5_duty_cycle : integer := 50; extclk0_multiply_by : integer := 1; extclk0_divide_by : integer := 1; extclk0_phase_shift : string := "0"; extclk0_time_delay : string := "0"; extclk0_duty_cycle : integer := 50; extclk1_multiply_by : integer := 1; extclk1_divide_by : integer := 1; extclk1_phase_shift : string := "0"; extclk1_time_delay : string := "0"; extclk1_duty_cycle : integer := 50; extclk2_multiply_by : integer := 1; extclk2_divide_by : integer := 1; extclk2_phase_shift : string := "0"; extclk2_time_delay : string := "0"; extclk2_duty_cycle : integer := 50; extclk3_multiply_by : integer := 1; extclk3_divide_by : integer := 1; extclk3_phase_shift : string := "0"; extclk3_time_delay : string := "0"; extclk3_duty_cycle : integer := 50; primary_clock : string := "inclk0"; inclk0_input_frequency : integer := 10000; inclk1_input_frequency : integer := 10000; gate_lock_signal : string := "no"; gate_lock_counter : integer := 1; valid_lock_multiplier : integer := 5; invalid_lock_multiplier : integer := 5; switch_over_on_lossclk : string := "off"; switch_over_on_gated_lock : string := "off"; switch_over_counter : integer := 1; enable_switch_over_counter : string := "off"; feedback_source : string := "extclk0"; bandwidth_type : string := "auto"; bandwidth : integer := 0; spread_frequency : integer := 0; down_spread : string := "0.0"; pfd_min : integer := 0; pfd_max : integer := 0; vco_min : integer := 0; vco_max : integer := 0; vco_center : integer := 0; -- ADVANCED USER PARAMETERS m_initial : integer := 1; m : integer := 1; n : integer := 1; m2 : integer := 1; n2 : integer := 1; ss : integer := 0; l0_high : integer := 1; l0_low : integer := 1; l0_initial : integer := 1; l0_mode : string := "bypass"; l0_ph : integer := 0; l0_time_delay : integer := 0; l1_high : integer := 1; l1_low : integer := 1; l1_initial : integer := 1; l1_mode : string := "bypass"; l1_ph : integer := 0; l1_time_delay : integer := 0; g0_high : integer := 1; g0_low : integer := 1; g0_initial : integer := 1; g0_mode : string := "bypass"; g0_ph : integer := 0; g0_time_delay : integer := 0; g1_high : integer := 1; g1_low : integer := 1; g1_initial : integer := 1; g1_mode : string := "bypass"; g1_ph : integer := 0; g1_time_delay : integer := 0; g2_high : integer := 1; g2_low : integer := 1; g2_initial : integer := 1; g2_mode : string := "bypass"; g2_ph : integer := 0; g2_time_delay : integer := 0; g3_high : integer := 1; g3_low : integer := 1; g3_initial : integer := 1; g3_mode : string := "bypass"; g3_ph : integer := 0; g3_time_delay : integer := 0; e0_high : integer := 1; e0_low : integer := 1; e0_initial : integer := 1; e0_mode : string := "bypass"; e0_ph : integer := 0; e0_time_delay : integer := 0; e1_high : integer := 1; e1_low : integer := 1; e1_initial : integer := 1; e1_mode : string := "bypass"; e1_ph : integer := 0; e1_time_delay : integer := 0; e2_high : integer := 1; e2_low : integer := 1; e2_initial : integer := 1; e2_mode : string := "bypass"; e2_ph : integer := 0; e2_time_delay : integer := 0; e3_high : integer := 1; e3_low : integer := 1; e3_initial : integer := 1; e3_mode : string := "bypass"; e3_ph : integer := 0; e3_time_delay : integer := 0; m_ph : integer := 0; m_time_delay : integer := 0; n_time_delay : integer := 0; extclk0_counter : string := "e0"; extclk1_counter : string := "e1"; extclk2_counter : string := "e2"; extclk3_counter : string := "e3"; clk0_counter : string := "g0"; clk1_counter : string := "g1"; clk2_counter : string := "g2"; clk3_counter : string := "g3"; clk4_counter : string := "l0"; clk5_counter : string := "l1"; -- LVDS mode parameters enable0_counter : string := "l0"; enable1_counter : string := "l0"; charge_pump_current : integer := 0; loop_filter_r : string := "1.0"; loop_filter_c : integer := 1; common_rx_tx : string := "off"; rx_outclock_resource : string := "auto"; use_vco_bypass : string := "false"; use_dc_coupling : string := "false"; pll_compensation_delay : integer := 0; simulation_type : string := "timing"; skip_vco : string := "off" ); port ( inclk : in std_logic_vector(1 downto 0); fbin : in std_logic; ena : in std_logic; clkswitch : in std_logic; areset : in std_logic; pfdena : in std_logic; clkena : in std_logic_vector(5 downto 0); extclkena : in std_logic_vector(3 downto 0); scanaclr : in std_logic; scandata : in std_logic; scanclk : in std_logic; clk : out std_logic_vector(5 downto 0); extclk : out std_logic_vector(3 downto 0); clkbad : out std_logic_vector(1 downto 0); activeclock : out std_logic; locked : out std_logic; clkloss : out std_logic; scandataout : out std_logic; -- lvds specific ports comparator : in std_logic := '0'; enable0 : out std_logic; enable1 : out std_logic ); END MF_stratix_pll; ARCHITECTURE vital_pll of MF_stratix_pll is -- internal advanced parameter signals signal i_vco_min : natural; signal i_vco_max : natural; signal i_vco_center : natural; signal i_pfd_min : natural; signal i_pfd_max : natural; signal l0_ph_val : natural; signal l1_ph_val : natural; signal g0_ph_val : natural; signal g1_ph_val : natural; signal g2_ph_val : natural; signal g3_ph_val : natural; signal e0_ph_val : natural; signal e1_ph_val : natural; signal e2_ph_val : natural; signal e3_ph_val : natural; signal i_extclk3_counter : string(1 to 2) := "e3"; signal i_extclk2_counter : string(1 to 2) := "e2"; signal i_extclk1_counter : string(1 to 2) := "e1"; signal i_extclk0_counter : string(1 to 2) := "e0"; signal i_clk5_counter : string(1 to 2) := "l1"; signal i_clk4_counter : string(1 to 2) := "l0"; signal i_clk3_counter : string(1 to 2) := "g3"; signal i_clk2_counter : string(1 to 2) := "g2"; signal i_clk1_counter : string(1 to 2) := "g1"; signal i_clk0_counter : string(1 to 2) := "g0"; signal i_charge_pump_current : natural; signal i_loop_filter_r : natural; -- end internal advanced parameter signals -- CONSTANTS CONSTANT EGPP_SCAN_CHAIN : integer := 289; CONSTANT GPP_SCAN_CHAIN : integer := 193; CONSTANT TRST : time := 5000 ps; CONSTANT TRSTCLK : time := 5000 ps; -- signals signal vcc : std_logic := '1'; signal fbclk : std_logic; signal refclk : std_logic; signal l0_clk : std_logic; signal l1_clk : std_logic; signal g0_clk : std_logic; signal g1_clk : std_logic; signal g2_clk : std_logic; signal g3_clk : std_logic; signal e0_clk : std_logic; signal e1_clk : std_logic; signal e2_clk : std_logic; signal e3_clk : std_logic; signal vco_out : std_logic_vector(7 downto 0) := (OTHERS => '0'); -- signals to assign values to counter params signal m_val : integer := 1; signal m2_val : integer := 1; signal n_val : integer := 1; signal n2_val : integer := 1; signal m_time_delay_val, n_time_delay_val : integer := 0; signal m_ph_val : integer := 0; signal m_initial_val : integer := m_initial; signal l0_initial_val : integer := l0_initial; signal l1_initial_val : integer := l1_initial; signal l0_high_val : integer := l0_high; signal l1_high_val : integer := l1_high; signal l0_low_val : integer := l0_low; signal l1_low_val : integer := l1_low; signal l0_mode_val : string(1 to 6) := "bypass"; signal l1_mode_val : string(1 to 6) := "bypass"; signal l0_time_delay_val : integer := l0_time_delay; signal l1_time_delay_val : integer := l1_time_delay; signal g0_initial_val : integer := g0_initial; signal g1_initial_val : integer := g1_initial; signal g2_initial_val : integer := g2_initial; signal g3_initial_val : integer := g3_initial; signal g0_high_val : integer := g0_high; signal g1_high_val : integer := g1_high; signal g2_high_val : integer := g2_high; signal g3_high_val : integer := g3_high; signal g0_mode_val : string(1 to 6) := "bypass"; signal g1_mode_val : string(1 to 6) := "bypass"; signal g2_mode_val : string(1 to 6) := "bypass"; signal g3_mode_val : string(1 to 6) := "bypass"; signal g0_low_val : integer := g0_low; signal g1_low_val : integer := g1_low; signal g2_low_val : integer := g2_low; signal g3_low_val : integer := g3_low; signal g0_time_delay_val : integer := g0_time_delay; signal g1_time_delay_val : integer := g1_time_delay; signal g2_time_delay_val : integer := g2_time_delay; signal g3_time_delay_val : integer := g3_time_delay; signal e0_initial_val : integer := e0_initial; signal e1_initial_val : integer := e1_initial; signal e2_initial_val : integer := e2_initial; signal e3_initial_val : integer := e3_initial; signal e0_high_val : integer := e0_high; signal e1_high_val : integer := e1_high; signal e2_high_val : integer := e2_high; signal e3_high_val : integer := e3_high; signal e0_low_val : integer := e0_low; signal e1_low_val : integer := e1_low; signal e2_low_val : integer := e2_low; signal e3_low_val : integer := e3_low; signal e0_time_delay_val : integer := e0_time_delay; signal e1_time_delay_val : integer := e1_time_delay; signal e2_time_delay_val : integer := e2_time_delay; signal e3_time_delay_val : integer := e3_time_delay; signal e0_mode_val : string(1 to 6) := "bypass"; signal e1_mode_val : string(1 to 6) := "bypass"; signal e2_mode_val : string(1 to 6) := "bypass"; signal e3_mode_val : string(1 to 6) := "bypass"; signal m_mode_val : string(1 to 6) := " "; signal m2_mode_val : string(1 to 6) := " "; signal n_mode_val : string(1 to 6) := " "; signal n2_mode_val : string(1 to 6) := " "; signal cntr_e0_initial : integer := 1; signal cntr_e1_initial : integer := 1; signal cntr_e2_initial : integer := 1; signal cntr_e3_initial : integer := 1; signal ext_fbk_delay : integer := 0; signal cntr_e0_delay : integer := 0; signal cntr_e1_delay : integer := 0; signal cntr_e2_delay : integer := 0; signal cntr_e3_delay : integer := 0; signal transfer : std_logic := '0'; signal scan_data : std_logic_vector(288 downto 0) := (OTHERS => '0'); signal ena0 : std_logic; signal ena1 : std_logic; signal ena2 : std_logic; signal ena3 : std_logic; signal ena4 : std_logic; signal ena5 : std_logic; signal extena0 : std_logic; signal extena1 : std_logic; signal extena2 : std_logic; signal extena3 : std_logic; signal clk0_tmp : std_logic; signal clk1_tmp : std_logic; signal clk2_tmp : std_logic; signal clk3_tmp : std_logic; signal clk4_tmp : std_logic; signal clk5_tmp : std_logic; signal extclk0_tmp : std_logic; signal extclk1_tmp : std_logic; signal extclk2_tmp : std_logic; signal extclk3_tmp : std_logic; signal not_clk0_tmp : std_logic; signal not_clk1_tmp : std_logic; signal not_clk2_tmp : std_logic; signal not_clk3_tmp : std_logic; signal not_clk4_tmp : std_logic; signal not_clk5_tmp : std_logic; signal not_extclk0_tmp : std_logic; signal not_extclk1_tmp : std_logic; signal not_extclk2_tmp : std_logic; signal not_extclk3_tmp : std_logic; signal clkin : std_logic := '0'; signal gate_locked : std_logic := '0'; signal lock : std_logic := '0'; signal about_to_lock : boolean := false; signal quiet_period_violation : boolean := false; signal reconfig_err : boolean := false; signal scanclr_violation : boolean := false; signal scanclr_clk_violation : boolean := false; signal inclk_l0 : std_logic; signal inclk_l1 : std_logic; signal inclk_g0 : std_logic; signal inclk_g1 : std_logic; signal inclk_g2 : std_logic; signal inclk_g3 : std_logic; signal inclk_e0 : std_logic; signal inclk_e1 : std_logic; signal inclk_e2 : std_logic; signal inclk_e3 : std_logic; signal inclk_m : std_logic; signal devpor : std_logic; signal devclrn : std_logic; signal inclk0_ipd : std_logic; signal inclk1_ipd : std_logic; signal ena_ipd : std_logic; signal pfdena_ipd : std_logic; signal comparator_ipd : std_logic; signal areset_ipd : std_logic; signal fbin_ipd : std_logic; signal clkena0_ipd : std_logic; signal clkena1_ipd : std_logic; signal clkena2_ipd : std_logic; signal clkena3_ipd : std_logic; signal clkena4_ipd : std_logic; signal clkena5_ipd : std_logic; signal extclkena0_ipd : std_logic; signal extclkena1_ipd : std_logic; signal extclkena2_ipd : std_logic; signal extclkena3_ipd : std_logic; signal scanclk_ipd : std_logic; signal scanaclr_ipd : std_logic; signal scandata_ipd : std_logic; signal clkswitch_ipd : std_logic; signal lvds_dffa_clk : std_logic; signal lvds_dffb_clk : std_logic; signal lvds_dffc_clk : std_logic; signal lvds_dffd_clk : std_logic; signal dffa_out : std_logic := '0'; signal dffb_out : std_logic := '0'; signal dffc_out : std_logic := '0'; signal dffd_out : std_logic := '0'; signal nce_temp : std_logic := '0'; signal nce_l0 : std_logic := '0'; signal nce_l1 : std_logic := '0'; signal inclk_l0_dly1 : std_logic := '0'; signal inclk_l0_dly2 : std_logic := '0'; signal inclk_l0_dly3 : std_logic := '0'; signal inclk_l0_dly4 : std_logic := '0'; signal inclk_l0_dly5 : std_logic := '0'; signal inclk_l0_dly6 : std_logic := '0'; signal inclk_l1_dly1 : std_logic := '0'; signal inclk_l1_dly2 : std_logic := '0'; signal inclk_l1_dly3 : std_logic := '0'; signal inclk_l1_dly4 : std_logic := '0'; signal inclk_l1_dly5 : std_logic := '0'; signal inclk_l1_dly6 : std_logic := '0'; signal sig_offset : time := 0 ps; signal sig_refclk_time : time := 0 ps; signal sig_fbclk_period : time := 0 ps; signal sig_vco_period_was_phase_adjusted : boolean := false; signal sig_phase_adjust_was_scheduled : boolean := false; signal sig_stop_vco : std_logic := '0'; signal sig_m_times_vco_period : time := 0 ps; signal sig_new_m_times_vco_period : time := 0 ps; signal sig_got_refclk_posedge : boolean := false; signal sig_got_fbclk_posedge : boolean := false; signal sig_got_second_refclk : boolean := false; signal m_delay : integer := 0; signal n_delay : integer := 0; signal sig_curr_clock : string(1 to 6) := primary_clock; signal inclk1_tmp : std_logic := '0'; signal scan_chain_length : integer := GPP_SCAN_CHAIN; signal ext_fbk_cntr_high : integer := 0; signal ext_fbk_cntr_low : integer := 0; signal ext_fbk_cntr_delay : integer := 0; signal ext_fbk_cntr_ph : integer := 0; signal ext_fbk_cntr_initial : integer := 1; signal ext_fbk_cntr : string(1 to 2) := "e0"; signal ext_fbk_cntr_mode : string(1 to 6) := "bypass"; signal enable0_tmp : std_logic := '0'; signal enable1_tmp : std_logic := '0'; signal reset_low : std_logic := '0'; signal scandataout_tmp : std_logic := '0'; signal sig_refclk_period : time := (inclk0_input_frequency * 1 ps) * n; signal schedule_vco : std_logic := '0'; signal areset_ena_sig : std_logic := '0'; COMPONENT MF_mn_cntr PORT ( clk : IN std_logic; reset : IN std_logic; cout : OUT std_logic; initial_value : IN integer := 1; modulus : IN integer; time_delay : IN integer; ph : IN integer := 0 ); END COMPONENT; COMPONENT stx_scale_cntr PORT ( clk : IN std_logic; reset : IN std_logic; cout : OUT std_logic; initial : IN integer := 1; high : IN integer := 1; low : IN integer := 1; mode : IN string := "bypass"; time_delay : IN integer := 0; ph_tap : IN natural ); END COMPONENT; component DFFP port( Q : out STD_LOGIC := '0'; D : in STD_LOGIC := '1'; CLRN : in STD_LOGIC := '1'; PRN : in STD_LOGIC := '1'; CLK : in STD_LOGIC := '0'; ENA : in STD_LOGIC := '1' ); end component; COMPONENT MF_PLL_REG PORT( Q : out STD_LOGIC := '0'; D : in STD_LOGIC := '1'; CLRN : in STD_LOGIC := '1'; PRN : in STD_LOGIC := '1'; CLK : in STD_LOGIC := '0'; ENA : in STD_LOGIC := '1'); END COMPONENT; begin ---------------------- -- INPUT PATH DELAYs ---------------------- WireDelay : block begin inclk0_ipd <= inclk(0); inclk1_ipd <= inclk(1); areset_ipd <= areset; ena_ipd <= ena; fbin_ipd <= fbin; pfdena_ipd <= pfdena; clkena0_ipd <= clkena(0); clkena1_ipd <= clkena(1); clkena2_ipd <= clkena(2); clkena3_ipd <= clkena(3); clkena4_ipd <= clkena(4); clkena5_ipd <= clkena(5); extclkena0_ipd <= extclkena(0); extclkena1_ipd <= extclkena(1); extclkena2_ipd <= extclkena(2); extclkena3_ipd <= extclkena(3); scanclk_ipd <= scanclk; scanaclr_ipd <= scanaclr; scandata_ipd <= scandata; comparator_ipd <= comparator; clkswitch_ipd <= clkswitch; end block; -- User to Advanced parameter conversion i_extclk3_counter <= "e3" when m=0 else extclk3_counter; i_extclk2_counter <= "e2" when m=0 else extclk2_counter; i_extclk1_counter <= "e1" when m=0 else extclk1_counter; i_extclk0_counter <= "e0" when m=0 else extclk0_counter; i_clk5_counter <= "l1" when m=0 else clk5_counter; i_clk4_counter <= "l0" when m=0 else clk4_counter; i_clk3_counter <= "g3" when m=0 else clk3_counter; i_clk2_counter <= "g2" when m=0 else clk2_counter; i_clk1_counter <= "g1" when m=0 else clk1_counter; i_clk0_counter <= "l0" when m=0 and pll_type = "lvds" else "g0" when m=0 else clk0_counter; -- end parameter conversion inclk_m <= extclk0_tmp when operation_mode = "external_feedback" and feedback_source = "extclk0" else extclk1_tmp when operation_mode = "external_feedback" and feedback_source = "extclk1" else extclk2_tmp when operation_mode = "external_feedback" and feedback_source = "extclk2" else extclk3_tmp when operation_mode = "external_feedback" and feedback_source = "extclk3" else vco_out(m_ph_val); ext_fbk_cntr <= "e0" when (feedback_source = "extclk0" and extclk0_counter = "e0") or (feedback_source = "extclk1" and extclk1_counter = "e0") or (feedback_source = "extclk2" and extclk2_counter = "e0") or (feedback_source = "extclk3" and extclk3_counter = "e0") else "e1" when (feedback_source = "extclk0" and extclk0_counter = "e1") or (feedback_source = "extclk1" and extclk1_counter = "e1") or (feedback_source = "extclk2" and extclk2_counter = "e1") or (feedback_source = "extclk3" and extclk3_counter = "e1") else "e2" when (feedback_source = "extclk0" and extclk0_counter = "e2") or (feedback_source = "extclk1" and extclk1_counter = "e2") or (feedback_source = "extclk2" and extclk2_counter = "e2") or (feedback_source = "extclk3" and extclk3_counter = "e2") else "e3" when (feedback_source = "extclk0" and extclk0_counter = "e3") or (feedback_source = "extclk1" and extclk1_counter = "e3") or (feedback_source = "extclk2" and extclk2_counter = "e3") or (feedback_source = "extclk3" and extclk3_counter = "e3") else "e0"; ext_fbk_cntr_high <= e0_high_val when ext_fbk_cntr = "e0" else e1_high_val when ext_fbk_cntr = "e1" else e2_high_val when ext_fbk_cntr = "e2" else e3_high_val when ext_fbk_cntr = "e3" else 1; ext_fbk_cntr_low <= e0_low_val when ext_fbk_cntr = "e0" else e1_low_val when ext_fbk_cntr = "e1" else e2_low_val when ext_fbk_cntr = "e2" else e3_low_val when ext_fbk_cntr = "e3" else 1; ext_fbk_cntr_delay <= e0_time_delay_val when ext_fbk_cntr = "e0" else e1_time_delay_val when ext_fbk_cntr = "e1" else e2_time_delay_val when ext_fbk_cntr = "e2" else e3_time_delay_val when ext_fbk_cntr = "e3" else 0; ext_fbk_cntr_ph <= e0_ph_val when ext_fbk_cntr = "e0" else e1_ph_val when ext_fbk_cntr = "e1" else e2_ph_val when ext_fbk_cntr = "e2" else e3_ph_val when ext_fbk_cntr = "e3" else 0; ext_fbk_cntr_initial <= e0_initial_val when ext_fbk_cntr = "e0" else e1_initial_val when ext_fbk_cntr = "e1" else e2_initial_val when ext_fbk_cntr = "e2" else e3_initial_val when ext_fbk_cntr = "e3" else 0; ext_fbk_cntr_mode <= e0_mode_val when ext_fbk_cntr = "e0" else e1_mode_val when ext_fbk_cntr = "e1" else e2_mode_val when ext_fbk_cntr = "e2" else e3_mode_val when ext_fbk_cntr = "e3" else e0_mode_val; areset_ena_sig <= areset_ipd or (not ena_ipd) or sig_stop_vco; m1 : MF_mn_cntr port map (clk => inclk_m, reset => areset_ena_sig, cout => fbclk, initial_value => m_initial_val, modulus => m_val, time_delay => m_delay, ph => m_ph_val ); -- add delta delay to inclk1 to ensure inclk0 and inclk1 are processed -- in different simulation deltas. inclk1_tmp <= inclk1_ipd; process (inclk0_ipd, inclk1_tmp, clkswitch_ipd) variable input_value : std_logic := '0'; variable current_clock : string(1 to 6) := primary_clock; variable clk0_count, clk1_count : integer := 0; variable clk0_is_bad, clk1_is_bad : std_logic := '0'; variable primary_clk_is_bad : boolean := false; variable current_clk_is_bad : boolean := false; variable got_curr_clk_falling_edge_after_clkswitch : boolean := false; variable switch_over_count : integer := 0; variable active_clock : std_logic := '0'; variable external_switch : boolean := false; begin if (now = 0 ps) then if (current_clock = "inclk1") then active_clock := '1'; end if; end if; if (clkswitch_ipd'event and clkswitch_ipd = '1') then external_switch := true; end if; -- save the current inclk event value if (inclk0_ipd'event) then input_value := inclk0_ipd; elsif (inclk1_tmp'event) then input_value := inclk1_tmp; end if; -- check if either input clk is bad if (inclk0_ipd'event and inclk0_ipd = '1') then clk0_count := clk0_count + 1; clk0_is_bad := '0'; clk1_count := 0; if (clk0_count > 2) then -- no event on other clk for 2 cycles clk1_is_bad := '1'; if (current_clock = "inclk1") then current_clk_is_bad := true; end if; end if; end if; if (inclk1_tmp'event and inclk1_tmp = '1') then clk1_count := clk1_count + 1; clk1_is_bad := '0'; clk0_count := 0; if (clk1_count > 2) then -- no event on other clk for 2 cycles clk0_is_bad := '1'; if (current_clock = "inclk0") then current_clk_is_bad := true; end if; end if; end if; -- check if the bad clk is the primary clock if ((primary_clock = "inclk0" and clk0_is_bad = '1') or (primary_clock = "inclk1" and clk1_is_bad = '1')) then primary_clk_is_bad := true; else primary_clk_is_bad := false; end if; -- actual switching if (inclk0_ipd'event and current_clock = "inclk0") then if (external_switch) then if (not got_curr_clk_falling_edge_after_clkswitch) then if (inclk0_ipd = '0') then got_curr_clk_falling_edge_after_clkswitch := true; end if; clkin <= transport inclk0_ipd; end if; else clkin <= transport inclk0_ipd; end if; elsif (inclk1_tmp'event and current_clock = "inclk1") then if (external_switch) then if (not got_curr_clk_falling_edge_after_clkswitch) then if (inclk1_tmp = '0') then got_curr_clk_falling_edge_after_clkswitch := true; end if; clkin <= transport inclk1_tmp; end if; else clkin <= transport inclk1_tmp; end if; else if (input_value = '1' and switch_over_on_lossclk = "on" and enable_switch_over_counter = "on" and primary_clk_is_bad) then switch_over_count := switch_over_count + 1; end if; if (input_value = '0') then if (external_switch and (got_curr_clk_falling_edge_after_clkswitch or current_clk_is_bad)) or (switch_over_on_lossclk = "on" and primary_clk_is_bad and (enable_switch_over_counter = "off" or switch_over_count = switch_over_counter)) then got_curr_clk_falling_edge_after_clkswitch := false; if (current_clock = "inclk0") then current_clock := "inclk1"; else current_clock := "inclk0"; end if; active_clock := not active_clock; switch_over_count := 0; external_switch := false; current_clk_is_bad := false; end if; end if; end if; -- schedule outputs clkbad(0) <= clk0_is_bad; clkbad(1) <= clk1_is_bad; if (switch_over_on_lossclk = "on" and clkswitch_ipd /= '1') then if (primary_clk_is_bad) then -- assert clkloss clkloss <= '1'; else clkloss <= '0'; end if; else clkloss <= clkswitch_ipd; end if; activeclock <= active_clock; end process; n1 : MF_mn_cntr port map (clk => clkin, reset => areset_ipd, cout => refclk, initial_value => n_val, modulus => n_val, time_delay => n_time_delay_val); inclk_l0 <= vco_out(l0_ph_val); l0 : stx_scale_cntr port map (clk => inclk_l0, reset => areset_ena_sig, cout => l0_clk, initial => l0_initial_val, high => l0_high_val, low => l0_low_val, mode => l0_mode_val, time_delay => l0_time_delay_val, ph_tap => l0_ph_val); inclk_l1 <= vco_out(l1_ph_val); l1 : stx_scale_cntr port map (clk => inclk_l1, reset => areset_ena_sig, cout => l1_clk, initial => l1_initial_val, high => l1_high_val, low => l1_low_val, mode => l1_mode_val, time_delay => l1_time_delay_val, ph_tap => l1_ph_val); inclk_g0 <= vco_out(g0_ph_val); g0 : stx_scale_cntr port map (clk => inclk_g0, reset => areset_ena_sig, cout => g0_clk, initial => g0_initial_val, high => g0_high_val, low => g0_low_val, mode => g0_mode_val, time_delay => g0_time_delay_val, ph_tap => g0_ph_val); process(g0_clk, l0_clk, l1_clk) begin if (g0_clk'event and g0_clk = '1') then dffa_out <= comparator_ipd; end if; if (l0_clk'event and l0_clk = '1' and enable0_counter = "l0") then dffb_out <= dffa_out; dffc_out <= dffb_out; dffd_out <= nce_temp; end if; if (l1_clk'event and l1_clk = '1' and enable0_counter = "l1") then dffb_out <= dffa_out; dffc_out <= dffb_out; dffd_out <= nce_temp; end if; end process; nce_temp <= (not dffc_out) and dffb_out; nce_l0 <= dffd_out when enable0_counter = "l0" else '0'; nce_l1 <= dffd_out when enable0_counter = "l1" else '0'; inclk_g1 <= vco_out(g1_ph_val); g1 : stx_scale_cntr port map (clk => inclk_g1, reset => areset_ena_sig, cout => g1_clk, initial => g1_initial_val, high => g1_high_val, low => g1_low_val, mode => g1_mode_val, time_delay => g1_time_delay_val, ph_tap => g1_ph_val); inclk_g2 <= vco_out(g2_ph_val); g2 : stx_scale_cntr port map (clk => inclk_g2, reset => areset_ena_sig, cout => g2_clk, initial => g2_initial_val, high => g2_high_val, low => g2_low_val, mode => g2_mode_val, time_delay => g2_time_delay_val, ph_tap => g2_ph_val); inclk_g3 <= vco_out(g3_ph_val); g3 : stx_scale_cntr port map (clk => inclk_g3, reset => areset_ena_sig, cout => g3_clk, initial => g3_initial_val, high => g3_high_val, low => g3_low_val, mode => g3_mode_val, time_delay => g3_time_delay_val, ph_tap => g3_ph_val); inclk_e0 <= vco_out(e0_ph_val); cntr_e0_initial <= 1 when operation_mode = "external_feedback" and ext_fbk_cntr = "e0" else e0_initial_val; cntr_e0_delay <= ext_fbk_delay when operation_mode = "external_feedback" and ext_fbk_cntr = "e0" else e0_time_delay_val; e0 : stx_scale_cntr port map (clk => inclk_e0, reset => areset_ena_sig, cout => e0_clk, initial => cntr_e0_initial, high => e0_high_val, low => e0_low_val, mode => e0_mode_val, time_delay => cntr_e0_delay, ph_tap => e0_ph_val); inclk_e1 <= vco_out(e1_ph_val); cntr_e1_initial <= 1 when operation_mode = "external_feedback" and ext_fbk_cntr = "e1" else e1_initial_val; cntr_e1_delay <= ext_fbk_delay when operation_mode = "external_feedback" and ext_fbk_cntr = "e1" else e1_time_delay_val; e1 : stx_scale_cntr port map (clk => inclk_e1, reset => areset_ena_sig, cout => e1_clk, initial => cntr_e1_initial, high => e1_high_val, low => e1_low_val, mode => e1_mode_val, time_delay => cntr_e1_delay, ph_tap => e1_ph_val); inclk_e2 <= vco_out(e2_ph_val); cntr_e2_initial <= 1 when operation_mode = "external_feedback" and ext_fbk_cntr = "e2" else e2_initial_val; cntr_e2_delay <= ext_fbk_delay when operation_mode = "external_feedback" and ext_fbk_cntr = "e2" else e2_time_delay_val; e2 : stx_scale_cntr port map (clk => inclk_e2, reset => areset_ena_sig, cout => e2_clk, initial => cntr_e2_initial, high => e2_high_val, low => e2_low_val, mode => e2_mode_val, time_delay => cntr_e2_delay, ph_tap => e2_ph_val); inclk_e3 <= vco_out(e3_ph_val); cntr_e3_initial <= 1 when operation_mode = "external_feedback" and ext_fbk_cntr = "e3" else e3_initial_val; cntr_e3_delay <= ext_fbk_delay when operation_mode = "external_feedback" and ext_fbk_cntr = "e3" else e3_time_delay_val; e3 : stx_scale_cntr port map (clk => inclk_e3, reset => areset_ena_sig, cout => e3_clk, initial => cntr_e3_initial, high => e3_high_val, low => e3_low_val, mode => e3_mode_val, time_delay => cntr_e3_delay, ph_tap => e3_ph_val); inclk_l0_dly1 <= inclk_l0; inclk_l0_dly2 <= inclk_l0_dly1; inclk_l0_dly3 <= inclk_l0_dly2; inclk_l0_dly4 <= inclk_l0_dly3; inclk_l0_dly5 <= inclk_l0_dly4; inclk_l0_dly6 <= inclk_l0_dly5; inclk_l1_dly1 <= inclk_l1; inclk_l1_dly2 <= inclk_l1_dly1; inclk_l1_dly3 <= inclk_l1_dly2; inclk_l1_dly4 <= inclk_l1_dly3; inclk_l1_dly5 <= inclk_l1_dly4; inclk_l1_dly6 <= inclk_l1_dly5; process(inclk_l0_dly6, inclk_l1_dly6, areset_ipd, ena_ipd, sig_stop_vco) variable l0_got_first_rising_edge : boolean := false; variable l0_count : integer := 1; variable l0_tmp, l1_tmp : std_logic := '0'; variable l1_got_first_rising_edge : boolean := false; variable l1_count : integer := 1; begin if (areset_ipd = '1' or ena_ipd = '0' or sig_stop_vco = '1') then l0_count := 1; l1_count := 1; l0_got_first_rising_edge := false; l1_got_first_rising_edge := false; else if (nce_l0 = '0') then if (not l0_got_first_rising_edge) then if (inclk_l0_dly6'event and inclk_l0_dly6 = '1') then l0_got_first_rising_edge := true; end if; elsif (inclk_l0_dly6'event) then l0_count := l0_count + 1; if (l0_count = (l0_high_val + l0_low_val) * 2) then l0_count := 1; end if; end if; end if; if (inclk_l0_dly6'event and inclk_l0_dly6 = '0') then if (l0_count = 1) then l0_tmp := '1'; l0_got_first_rising_edge := false; else l0_tmp := '0'; end if; end if; if (nce_l1 = '0') then if (not l1_got_first_rising_edge) then if (inclk_l1_dly6'event and inclk_l1_dly6 = '1') then l1_got_first_rising_edge := true; end if; elsif (inclk_l1_dly6'event) then l1_count := l1_count + 1; if (l1_count = (l1_high_val + l1_low_val) * 2) then l1_count := 1; end if; end if; end if; if (inclk_l1_dly6'event and inclk_l1_dly6 = '0') then if (l1_count = 1) then l1_tmp := '1'; l1_got_first_rising_edge := false; else l1_tmp := '0'; end if; end if; end if; if (enable0_counter = "l0") then enable0_tmp <= l0_tmp; elsif (enable0_counter = "l1") then enable0_tmp <= l1_tmp; else enable0_tmp <= '0'; end if; if (enable1_counter = "l0") then enable1_tmp <= l0_tmp; elsif (enable1_counter = "l1") then enable1_tmp <= l1_tmp; else enable1_tmp <= '0'; end if; end process; glocked_cntr : process(clkin, ena_ipd, areset_ipd) variable count : integer := 0; variable output : std_logic := '0'; begin if (areset_ipd = '1') then count := 0; output := '0'; elsif (clkin'event and clkin = '1') then if (ena_ipd = '1') then count := count + 1; if (count = gate_lock_counter) then output := '1'; end if; end if; end if; gate_locked <= output; end process; locked <= gate_locked and lock when gate_lock_signal = "yes" else lock; process (transfer) variable init : boolean := true; variable low, high : std_logic_vector(8 downto 0); variable delay_chain : std_logic_vector(3 downto 0); variable mn_delay_chain : std_logic_vector(0 to 3); variable mode : string(1 to 6) := "bypass"; variable delay_val : integer := 0; variable is_error : boolean := false; -- user to advanced variables variable i_m_initial : natural; variable i_m : integer := 1; variable i_n : natural := 1; variable i_m2 : natural; variable i_n2 : natural; variable i_ss : natural; variable i_l0_high : natural; variable i_l1_high : natural; variable i_g0_high : natural; variable i_g1_high : natural; variable i_g2_high : natural; variable i_g3_high : natural; variable i_e0_high : natural; variable i_e1_high : natural; variable i_e2_high : natural; variable i_e3_high : natural; variable i_l0_low : natural; variable i_l1_low : natural; variable i_g0_low : natural; variable i_g1_low : natural; variable i_g2_low : natural; variable i_g3_low : natural; variable i_e0_low : natural; variable i_e1_low : natural; variable i_e2_low : natural; variable i_e3_low : natural; variable i_l0_initial : natural; variable i_l1_initial : natural; variable i_g0_initial : natural; variable i_g1_initial : natural; variable i_g2_initial : natural; variable i_g3_initial : natural; variable i_e0_initial : natural; variable i_e1_initial : natural; variable i_e2_initial : natural; variable i_e3_initial : natural; variable i_l0_mode : string(1 to 6); variable i_l1_mode : string(1 to 6); variable i_g0_mode : string(1 to 6); variable i_g1_mode : string(1 to 6); variable i_g2_mode : string(1 to 6); variable i_g3_mode : string(1 to 6); variable i_e0_mode : string(1 to 6); variable i_e1_mode : string(1 to 6); variable i_e2_mode : string(1 to 6); variable i_e3_mode : string(1 to 6); variable max_neg_abs : integer := 0; variable i_l0_time_delay : natural; variable i_l1_time_delay : natural; variable i_g0_time_delay : natural; variable i_g1_time_delay : natural; variable i_g2_time_delay : natural; variable i_g3_time_delay : natural; variable i_e0_time_delay : natural; variable i_e1_time_delay : natural; variable i_e2_time_delay : natural; variable i_e3_time_delay : natural; variable i_m_time_delay : natural; variable i_n_time_delay : natural; variable i_l0_ph : natural; variable i_l1_ph : natural; variable i_g0_ph : natural; variable i_g1_ph : natural; variable i_g2_ph : natural; variable i_g3_ph : natural; variable i_e0_ph : natural; variable i_e1_ph : natural; variable i_e2_ph : natural; variable i_e3_ph : natural; variable i_m_ph : natural; variable output_count : natural; variable new_divisor : natural; begin if (init) then if (m = 0) then -- convert user parameters to advanced i_n := 1; if (pll_type = "lvds") then i_m := clk0_multiply_by; else i_m := lcm (clk0_multiply_by, clk1_multiply_by, clk2_multiply_by, clk3_multiply_by, clk4_multiply_by, clk5_multiply_by, extclk0_multiply_by, extclk1_multiply_by, extclk2_multiply_by, extclk3_multiply_by, inclk0_input_frequency); end if; i_m_time_delay := maxnegabs(str2int(clk0_time_delay), str2int(clk1_time_delay), str2int(clk2_time_delay), str2int(clk3_time_delay), str2int(clk4_time_delay), str2int(clk5_time_delay), str2int(extclk0_time_delay), str2int(extclk1_time_delay), str2int(extclk2_time_delay), str2int(extclk3_time_delay)); i_n_time_delay := mintimedelay(str2int(clk0_time_delay), str2int(clk1_time_delay), str2int(clk2_time_delay), str2int(clk3_time_delay), str2int(clk4_time_delay), str2int(clk5_time_delay), str2int(extclk0_time_delay), str2int(extclk1_time_delay), str2int(extclk2_time_delay), str2int(extclk3_time_delay)); if (pll_type = "lvds") then i_g0_time_delay := counter_time_delay(str2int(clk2_time_delay), i_m_time_delay, i_n_time_delay); else i_g0_time_delay := counter_time_delay(str2int(clk0_time_delay), i_m_time_delay,i_n_time_delay); end if; i_g1_time_delay := counter_time_delay(str2int(clk1_time_delay), i_m_time_delay, i_n_time_delay); i_g2_time_delay := counter_time_delay(str2int(clk2_time_delay), i_m_time_delay, i_n_time_delay); i_g3_time_delay := counter_time_delay(str2int(clk3_time_delay), i_m_time_delay, i_n_time_delay); if (pll_type = "lvds") then i_l0_time_delay := i_g0_time_delay; i_l1_time_delay := i_g0_time_delay; else i_l0_time_delay := counter_time_delay(str2int(clk4_time_delay), i_m_time_delay, i_n_time_delay); i_l1_time_delay := counter_time_delay(str2int(clk5_time_delay), i_m_time_delay, i_n_time_delay); end if; i_e0_time_delay := counter_time_delay(str2int(extclk0_time_delay), i_m_time_delay, i_n_time_delay); i_e1_time_delay := counter_time_delay(str2int(extclk1_time_delay), i_m_time_delay, i_n_time_delay); i_e2_time_delay := counter_time_delay(str2int(extclk2_time_delay), i_m_time_delay, i_n_time_delay); i_e3_time_delay := counter_time_delay(str2int(extclk3_time_delay), i_m_time_delay, i_n_time_delay); max_neg_abs := maxnegabs(str2int(clk0_phase_shift), str2int(clk1_phase_shift), str2int(clk2_phase_shift), str2int(clk3_phase_shift), str2int(clk4_phase_shift), str2int(clk5_phase_shift), str2int(extclk0_phase_shift), str2int(extclk1_phase_shift), str2int(extclk2_phase_shift), str2int(extclk3_phase_shift)); i_m_ph := counter_ph(get_phase_degree(max_neg_abs,inclk0_input_frequency), i_m, i_n); if (pll_type = "lvds") then i_g0_ph := counter_ph(get_phase_degree(ph_adjust(str2int(clk2_phase_shift),max_neg_abs),inclk0_input_frequency), i_m, i_n); else i_g0_ph := counter_ph(get_phase_degree(ph_adjust(str2int(clk0_phase_shift),max_neg_abs),inclk0_input_frequency), i_m, i_n); end if; i_g1_ph := counter_ph(get_phase_degree(ph_adjust(str2int(clk1_phase_shift),max_neg_abs),inclk0_input_frequency), i_m, i_n); i_g2_ph := counter_ph(get_phase_degree(ph_adjust(str2int(clk2_phase_shift),max_neg_abs),inclk0_input_frequency), i_m, i_n); i_g3_ph := counter_ph(get_phase_degree(ph_adjust(str2int(clk3_phase_shift),max_neg_abs),inclk0_input_frequency), i_m, i_n); if (pll_type = "lvds") then i_l0_ph := i_g0_ph; i_l1_ph := i_g0_ph; else i_l0_ph := counter_ph(get_phase_degree(ph_adjust(str2int(clk4_phase_shift),max_neg_abs),inclk0_input_frequency), i_m, i_n); i_l1_ph := counter_ph(get_phase_degree(ph_adjust(str2int(clk5_phase_shift),max_neg_abs),inclk0_input_frequency), i_m, i_n); end if; i_e0_ph := counter_ph(get_phase_degree(ph_adjust(str2int(extclk0_phase_shift),max_neg_abs),inclk0_input_frequency), i_m, i_n); i_e1_ph := counter_ph(get_phase_degree(ph_adjust(str2int(extclk1_phase_shift),max_neg_abs),inclk0_input_frequency), i_m, i_n); i_e2_ph := counter_ph(get_phase_degree(ph_adjust(str2int(extclk2_phase_shift),max_neg_abs),inclk0_input_frequency), i_m, i_n); i_e3_ph := counter_ph(get_phase_degree(ph_adjust(str2int(extclk3_phase_shift),max_neg_abs),inclk0_input_frequency), i_m, i_n); if (pll_type = "lvds") then i_g0_high := counter_high(output_counter_value(clk2_divide_by, clk2_multiply_by, i_m, i_n), clk2_duty_cycle); else i_g0_high := counter_high(output_counter_value(clk0_divide_by, clk0_multiply_by, i_m, i_n), clk0_duty_cycle); end if; i_g1_high := counter_high(output_counter_value(clk1_divide_by, clk1_multiply_by, i_m, i_n), clk1_duty_cycle); i_g2_high := counter_high(output_counter_value(clk2_divide_by, clk2_multiply_by, i_m, i_n), clk2_duty_cycle); i_g3_high := counter_high(output_counter_value(clk3_divide_by, clk3_multiply_by, i_m, i_n), clk3_duty_cycle); if (pll_type = "lvds") then i_l0_high := i_g0_high; i_l1_high := i_g0_high; else i_l0_high := counter_high(output_counter_value(clk4_divide_by, clk4_multiply_by, i_m, i_n), clk4_duty_cycle); i_l1_high := counter_high(output_counter_value(clk5_divide_by, clk5_multiply_by, i_m, i_n), clk5_duty_cycle); end if; i_e0_high := counter_high(output_counter_value(extclk0_divide_by, extclk0_multiply_by, i_m, i_n), extclk0_duty_cycle); i_e1_high := counter_high(output_counter_value(extclk1_divide_by, extclk1_multiply_by, i_m, i_n), extclk1_duty_cycle); i_e2_high := counter_high(output_counter_value(extclk2_divide_by, extclk2_multiply_by, i_m, i_n), extclk2_duty_cycle); i_e3_high := counter_high(output_counter_value(extclk3_divide_by, extclk3_multiply_by, i_m, i_n), extclk3_duty_cycle); if (pll_type = "lvds") then i_g0_low := counter_low(output_counter_value(clk2_divide_by, clk2_multiply_by, i_m, i_n), clk2_duty_cycle); else i_g0_low := counter_low(output_counter_value(clk0_divide_by, clk0_multiply_by, i_m, i_n), clk0_duty_cycle); end if; i_g1_low := counter_low(output_counter_value(clk1_divide_by, clk1_multiply_by, i_m, i_n), clk1_duty_cycle); i_g2_low := counter_low(output_counter_value(clk2_divide_by, clk2_multiply_by, i_m, i_n), clk2_duty_cycle); i_g3_low := counter_low(output_counter_value(clk3_divide_by, clk3_multiply_by, i_m, i_n), clk3_duty_cycle); if (pll_type = "lvds") then i_l0_low := i_g0_low; i_l1_low := i_g0_low; else i_l0_low := counter_low(output_counter_value(clk4_divide_by, clk4_multiply_by, i_m, i_n), clk4_duty_cycle); i_l1_low := counter_low(output_counter_value(clk5_divide_by, clk5_multiply_by, i_m, i_n), clk5_duty_cycle); end if; i_e0_low := counter_low(output_counter_value(extclk0_divide_by, extclk0_multiply_by, i_m, i_n), extclk0_duty_cycle); i_e1_low := counter_low(output_counter_value(extclk1_divide_by, extclk1_multiply_by, i_m, i_n), extclk1_duty_cycle); i_e2_low := counter_low(output_counter_value(extclk2_divide_by, extclk2_multiply_by, i_m, i_n), extclk2_duty_cycle); i_e3_low := counter_low(output_counter_value(extclk3_divide_by, extclk3_multiply_by, i_m, i_n), extclk3_duty_cycle); i_m_initial := counter_initial(get_phase_degree(max_neg_abs, inclk0_input_frequency), i_m,i_n); if (pll_type = "lvds") then i_g0_initial := counter_initial(get_phase_degree(ph_adjust(str2int(clk2_phase_shift), max_neg_abs), inclk0_input_frequency), i_m, i_n); else i_g0_initial := counter_initial(get_phase_degree(ph_adjust(str2int(clk0_phase_shift), max_neg_abs), inclk0_input_frequency), i_m, i_n); end if; i_g1_initial := counter_initial(get_phase_degree(ph_adjust(str2int(clk1_phase_shift), max_neg_abs), inclk0_input_frequency), i_m, i_n); i_g2_initial := counter_initial(get_phase_degree(ph_adjust(str2int(clk2_phase_shift), max_neg_abs), inclk0_input_frequency), i_m, i_n); i_g3_initial := counter_initial(get_phase_degree(ph_adjust(str2int(clk3_phase_shift), max_neg_abs), inclk0_input_frequency), i_m, i_n); if (pll_type = "lvds") then i_l0_initial := i_g0_initial; i_l1_initial := i_g0_initial; else i_l0_initial := counter_initial(get_phase_degree(ph_adjust(str2int(clk4_phase_shift), max_neg_abs), inclk0_input_frequency), i_m, i_n); i_l1_initial := counter_initial(get_phase_degree(ph_adjust(str2int(clk5_phase_shift), max_neg_abs), inclk0_input_frequency), i_m, i_n); end if; i_e0_initial := counter_initial(get_phase_degree(ph_adjust(str2int(extclk0_phase_shift), max_neg_abs), inclk0_input_frequency), i_m, i_n); i_e1_initial := counter_initial(get_phase_degree(ph_adjust(str2int(extclk1_phase_shift), max_neg_abs), inclk0_input_frequency), i_m, i_n); i_e2_initial := counter_initial(get_phase_degree(ph_adjust(str2int(extclk2_phase_shift), max_neg_abs), inclk0_input_frequency), i_m, i_n); i_e3_initial := counter_initial(get_phase_degree(ph_adjust(str2int(extclk3_phase_shift), max_neg_abs), inclk0_input_frequency), i_m, i_n); if (pll_type = "lvds") then i_g0_mode := counter_mode(clk2_duty_cycle, output_counter_value(clk2_divide_by, clk2_multiply_by, i_m, i_n)); else i_g0_mode := counter_mode(clk0_duty_cycle, output_counter_value(clk0_divide_by, clk0_multiply_by, i_m, i_n)); end if; i_g1_mode := counter_mode(clk1_duty_cycle, output_counter_value(clk1_divide_by, clk1_multiply_by, i_m, i_n)); i_g2_mode := counter_mode(clk2_duty_cycle, output_counter_value(clk2_divide_by, clk2_multiply_by, i_m, i_n)); i_g3_mode := counter_mode(clk3_duty_cycle, output_counter_value(clk3_divide_by, clk3_multiply_by, i_m, i_n)); if (pll_type = "lvds") then i_l0_mode := "bypass"; i_l1_mode := "bypass"; else i_l0_mode := counter_mode(clk4_duty_cycle, output_counter_value(clk4_divide_by, clk4_multiply_by, i_m, i_n)); i_l1_mode := counter_mode(clk5_duty_cycle, output_counter_value(clk5_divide_by, clk5_multiply_by, i_m, i_n)); end if; i_e0_mode := counter_mode(extclk0_duty_cycle, output_counter_value(extclk0_divide_by, extclk0_multiply_by, i_m, i_n)); i_e1_mode := counter_mode(extclk1_duty_cycle, output_counter_value(extclk1_divide_by, extclk1_multiply_by, i_m, i_n)); i_e2_mode := counter_mode(extclk2_duty_cycle, output_counter_value(extclk2_divide_by, extclk2_multiply_by, i_m, i_n)); i_e3_mode := counter_mode(extclk3_duty_cycle, output_counter_value(extclk3_divide_by, extclk3_multiply_by, i_m, i_n)); -- in external feedback mode, need to adjust M value to take -- into consideration the external feedback counter value if(operation_mode = "external_feedback") then -- if there is a negative phase shift, m_initial can -- only be 1 if (max_neg_abs > 0) then i_m_initial := 1; end if; -- calculate the feedback counter multiplier if (feedback_source = "extclk0") then if (i_e0_mode = "bypass") then output_count := 1; else output_count := i_e0_high + i_e0_low; end if; elsif (feedback_source = "extclk1") then if (i_e1_mode = "bypass") then output_count := 1; else output_count := i_e1_high + i_e1_low; end if; elsif (feedback_source = "extclk2") then if (i_e2_mode = "bypass") then output_count := 1; else output_count := i_e2_high + i_e2_low; end if; elsif (feedback_source = "extclk3") then if (i_e3_mode = "bypass") then output_count := 1; else output_count := i_e3_high + i_e3_low; end if; else -- default to e0 if (i_e0_mode = "bypass") then output_count := 1; else output_count := i_e0_high + i_e0_low; end if; end if; if (i_m > output_count) then i_m := i_m / output_count; else new_divisor := gcd(i_m, output_count); i_m := i_m / new_divisor; i_n := output_count / new_divisor; end if; end if; else -- m /= 0 i_n := n; i_m := m; i_m_initial := m_initial; i_m_time_delay := m_time_delay; i_n_time_delay := n_time_delay; i_l0_time_delay := l0_time_delay; i_l1_time_delay := l1_time_delay; i_g0_time_delay := g0_time_delay; i_g1_time_delay := g1_time_delay; i_g2_time_delay := g2_time_delay; i_g3_time_delay := g3_time_delay; i_e0_time_delay := e0_time_delay; i_e1_time_delay := e1_time_delay; i_e2_time_delay := e2_time_delay; i_e3_time_delay := e3_time_delay; i_m_ph := m_ph; i_l0_ph := l0_ph; i_l1_ph := l1_ph; i_g0_ph := g0_ph; i_g1_ph := g1_ph; i_g2_ph := g2_ph; i_g3_ph := g3_ph; i_e0_ph := e0_ph; i_e1_ph := e1_ph; i_e2_ph := e2_ph; i_e3_ph := e3_ph; i_l0_high := l0_high; i_l1_high := l1_high; i_g0_high := g0_high; i_g1_high := g1_high; i_g2_high := g2_high; i_g3_high := g3_high; i_e0_high := e0_high; i_e1_high := e1_high; i_e2_high := e2_high; i_e3_high := e3_high; i_l0_low := l0_low; i_l1_low := l1_low; i_g0_low := g0_low; i_g1_low := g1_low; i_g2_low := g2_low; i_g3_low := g3_low; i_e0_low := e0_low; i_e1_low := e1_low; i_e2_low := e2_low; i_e3_low := e3_low; i_l0_initial := l0_initial; i_l1_initial := l1_initial; i_g0_initial := g0_initial; i_g1_initial := g1_initial; i_g2_initial := g2_initial; i_g3_initial := g3_initial; i_e0_initial := e0_initial; i_e1_initial := e1_initial; i_e2_initial := e2_initial; i_e3_initial := e3_initial; i_l0_mode := translate_string(l0_mode); i_l1_mode := translate_string(l1_mode); i_g0_mode := translate_string(g0_mode); i_g1_mode := translate_string(g1_mode); i_g2_mode := translate_string(g2_mode); i_g3_mode := translate_string(g3_mode); i_e0_mode := translate_string(e0_mode); i_e1_mode := translate_string(e1_mode); i_e2_mode := translate_string(e2_mode); i_e3_mode := translate_string(e3_mode); end if; -- user to advanced conversion. m_initial_val <= i_m_initial; n_val <= i_n; m_val <= i_m; if (i_m = 1) then m_mode_val <= "bypass"; end if; if (i_n = 1) then n_mode_val <= "bypass"; end if; -- NOTE: m_time_delay (vco time delay) not supported for external -- feedback mode -- in feedback mode, m_time_delay = delay of feedback loop tap m_time_delay_val <= i_m_time_delay; n_time_delay_val <= i_n_time_delay; m_ph_val <= i_m_ph; m2_val <= m2; n2_val <= n2; if (m2 = 1) then m2_mode_val <= "bypass"; end if; if (n2 = 1) then n2_mode_val <= "bypass"; end if; if (skip_vco = "on") then m_val <= 1; m_initial_val <= 1; m_time_delay_val <= 0; m_ph_val <= 0; end if; l0_ph_val <= i_l0_ph; l1_ph_val <= i_l1_ph; g0_ph_val <= i_g0_ph; g1_ph_val <= i_g1_ph; g2_ph_val <= i_g2_ph; g3_ph_val <= i_g3_ph; e0_ph_val <= i_e0_ph; e1_ph_val <= i_e1_ph; e2_ph_val <= i_e2_ph; e3_ph_val <= i_e3_ph; l0_initial_val <= i_l0_initial; l0_high_val <= i_l0_high; l0_low_val <= i_l0_low; l0_mode_val <= i_l0_mode; l0_time_delay_val <= i_l0_time_delay; l1_initial_val <= i_l1_initial; l1_high_val <= i_l1_high; l1_low_val <= i_l1_low; l1_mode_val <= i_l1_mode; l1_time_delay_val <= i_l1_time_delay; g0_initial_val <= i_g0_initial; g0_high_val <= i_g0_high; g0_low_val <= i_g0_low; g0_mode_val <= i_g0_mode; g0_time_delay_val <= i_g0_time_delay; g1_initial_val <= i_g1_initial; g1_high_val <= i_g1_high; g1_low_val <= i_g1_low; g1_mode_val <= i_g1_mode; g1_time_delay_val <= i_g1_time_delay; g2_initial_val <= i_g2_initial; g2_high_val <= i_g2_high; g2_low_val <= i_g2_low; g2_mode_val <= i_g2_mode; g2_time_delay_val <= i_g2_time_delay; g3_initial_val <= i_g3_initial; g3_high_val <= i_g3_high; g3_low_val <= i_g3_low; g3_mode_val <= i_g3_mode; g3_time_delay_val <= i_g3_time_delay; if (scan_chain = "long") then e0_initial_val <= i_e0_initial; e0_high_val <= i_e0_high; e0_low_val <= i_e0_low; e0_mode_val <= i_e0_mode; e0_time_delay_val <= i_e0_time_delay; e1_initial_val <= i_e1_initial; e1_high_val <= i_e1_high; e1_low_val <= i_e1_low; e1_mode_val <= i_e1_mode; e1_time_delay_val <= i_e1_time_delay; e2_initial_val <= i_e2_initial; e2_high_val <= i_e2_high; e2_low_val <= i_e2_low; e2_mode_val <= i_e2_mode; e2_time_delay_val <= i_e2_time_delay; e3_initial_val <= i_e3_initial; e3_high_val <= i_e3_high; e3_low_val <= i_e3_low; e3_mode_val <= i_e3_mode; e3_time_delay_val <= i_e3_time_delay; scan_chain_length <= EGPP_SCAN_CHAIN; end if; init := false; elsif (transfer'event and transfer = '1') then reconfig_err <= false; ASSERT false REPORT "Reconfiguring PLL" severity note; if (scan_chain = "long") then -- cntr e3 delay_chain := scan_data(287 downto 284); if (scan_data(273) = '1') then e3_mode_val <= "bypass"; if (scan_data(283) = '1') then e3_mode_val <= " off"; ASSERT false REPORT "The specified bit settings will turn OFF the E3 counter. It cannot be turned on unless the part is re-initialized." severity warning; end if; elsif (scan_data(283) = '1') then e3_mode_val <= " odd"; else e3_mode_val <= " even"; end if; high := scan_data(272 downto 264); low := scan_data(282 downto 274); e3_low_val <= alt_conv_integer(low); e3_high_val <= alt_conv_integer(high); -- count value of 0 is actually 512 if (alt_conv_integer(high) = 0) then e3_high_val <= 512; end if; if (alt_conv_integer(low) = 0) then e3_low_val <= 512; end if; delay_val := alt_conv_integer(delay_chain); delay_val := delay_val * 250; if (delay_val > 3000) then delay_val := 3000; end if; e3_time_delay_val <= delay_val; -- cntr e2 delay_chain := scan_data(263 downto 260); if (scan_data(249) = '1') then e2_mode_val <= "bypass"; if (scan_data(259) = '1') then e2_mode_val <= " off"; ASSERT false REPORT "The specified bit settings will turn OFF the E2 counter. It cannot be turned on unless the part is re-initialized." severity warning; end if; elsif (scan_data(259) = '1') then e2_mode_val <= " odd"; else e2_mode_val <= " even"; end if; high := scan_data(248 downto 240); low := scan_data(258 downto 250); e2_low_val <= alt_conv_integer(low); e2_high_val <= alt_conv_integer(high); if (alt_conv_integer(high) = 0) then e2_high_val <= 512; end if; if (alt_conv_integer(low) = 0) then e2_low_val <= 512; end if; delay_val := alt_conv_integer(delay_chain); delay_val := delay_val * 250; if (delay_val > 3000) then delay_val := 3000; end if; e2_time_delay_val <= delay_val; -- cntr e1 delay_chain := scan_data(239 downto 236); if (scan_data(225) = '1') then e1_mode_val <= "bypass"; if (scan_data(235) = '1') then e1_mode_val <= " off"; ASSERT false REPORT "The specified bit settings will turn OFF the E1 counter. It cannot be turned on unless the part is re-initialized." severity warning; end if; elsif (scan_data(235) = '1') then e1_mode_val <= " odd"; else e1_mode_val <= " even"; end if; high := scan_data(224 downto 216); low := scan_data(234 downto 226); e1_low_val <= alt_conv_integer(low); e1_high_val <= alt_conv_integer(high); if (alt_conv_integer(high) = 0) then e1_high_val <= 512; end if; if (alt_conv_integer(low) = 0) then e1_low_val <= 512; end if; delay_val := alt_conv_integer(delay_chain); delay_val := delay_val * 250; if (delay_val > 3000) then delay_val := 3000; end if; e1_time_delay_val <= delay_val; -- cntr e0 delay_chain := scan_data(215 downto 212); if (scan_data(201) = '1') then e0_mode_val <= "bypass"; if (scan_data(211) = '1') then e0_mode_val <= " off"; ASSERT false REPORT "The specified bit settings will turn OFF the E0 counter. It cannot be turned on unless the part is re-initialized." severity warning; end if; elsif (scan_data(211) = '1') then e0_mode_val <= " odd"; else e0_mode_val <= " even"; end if; high := scan_data(200 downto 192); low := scan_data(210 downto 202); e0_low_val <= alt_conv_integer(low); e0_high_val <= alt_conv_integer(high); if (alt_conv_integer(high) = 0) then e0_high_val <= 512; end if; if (alt_conv_integer(low) = 0) then e0_low_val <= 512; end if; delay_val := alt_conv_integer(delay_chain); delay_val := delay_val * 250; if (delay_val > 3000) then delay_val := 3000; end if; e0_time_delay_val <= delay_val; end if; -- cntr l1 delay_chain := scan_data(191 downto 188); if (scan_data(177) = '1') then l1_mode_val <= "bypass"; if (scan_data(187) = '1') then l1_mode_val <= " off"; ASSERT false REPORT "The specified bit settings will turn OFF the L1 counter. It cannot be turned on unless the part is re-initialized." severity warning; end if; elsif (scan_data(187) = '1') then l1_mode_val <= " odd"; else l1_mode_val <= " even"; end if; high := scan_data(176 downto 168); low := scan_data(186 downto 178); l1_low_val <= alt_conv_integer(low); l1_high_val <= alt_conv_integer(high); if (alt_conv_integer(high) = 0) then l1_high_val <= 512; end if; if (alt_conv_integer(low) = 0) then l1_low_val <= 512; end if; delay_val := alt_conv_integer(delay_chain); delay_val := delay_val * 250; if (delay_val > 3000) then delay_val := 3000; end if; l1_time_delay_val <= delay_val; -- cntr l0 delay_chain := scan_data(167 downto 164); if (scan_data(153) = '1') then l0_mode_val <= "bypass"; if (scan_data(163) = '1') then l0_mode_val <= " off"; ASSERT false REPORT "The specified bit settings will turn OFF the L0 counter. It cannot be turned on unless the part is re-initialized." severity warning; end if; elsif (scan_data(163) = '1') then l0_mode_val <= " odd"; else l0_mode_val <= " even"; end if; high := scan_data(152 downto 144); low := scan_data(162 downto 154); l0_low_val <= alt_conv_integer(low); l0_high_val <= alt_conv_integer(high); if (alt_conv_integer(high) = 0) then l0_high_val <= 512; end if; if (alt_conv_integer(low) = 0) then l0_low_val <= 512; end if; delay_val := alt_conv_integer(delay_chain); delay_val := delay_val * 250; if (delay_val > 3000) then delay_val := 3000; end if; l0_time_delay_val <= delay_val; -- cntr g3 delay_chain := scan_data(143 downto 140); if (scan_data(129) = '1') then g3_mode_val <= "bypass"; if (scan_data(139) = '1') then g3_mode_val <= " off"; ASSERT false REPORT "The specified bit settings will turn OFF the G3 counter. It cannot be turned on unless the part is re-initialized." severity warning; end if; elsif (scan_data(139) = '1') then g3_mode_val <= " odd"; else g3_mode_val <= " even"; end if; high := scan_data(128 downto 120); low := scan_data(138 downto 130); g3_low_val <= alt_conv_integer(low); g3_high_val <= alt_conv_integer(high); if (alt_conv_integer(high) = 0) then g3_high_val <= 512; end if; if (alt_conv_integer(low) = 0) then g3_low_val <= 512; end if; delay_val := alt_conv_integer(delay_chain); delay_val := delay_val * 250; if (delay_val > 3000) then delay_val := 3000; end if; g3_time_delay_val <= delay_val; -- cntr g2 delay_chain := scan_data(119 downto 116); if (scan_data(105) = '1') then g2_mode_val <= "bypass"; if (scan_data(115) = '1') then g2_mode_val <= " off"; ASSERT false REPORT "The specified bit settings will turn OFF the G2 counter. It cannot be turned on unless the part is re-initialized." severity warning; end if; elsif (scan_data(115) = '1') then g2_mode_val <= " odd"; else g2_mode_val <= " even"; end if; high := scan_data(104 downto 96); low := scan_data(114 downto 106); g2_low_val <= alt_conv_integer(low); g2_high_val <= alt_conv_integer(high); if (alt_conv_integer(high) = 0) then g2_high_val <= 512; end if; if (alt_conv_integer(low) = 0) then g2_low_val <= 512; end if; delay_val := alt_conv_integer(delay_chain); delay_val := delay_val * 250; if (delay_val > 3000) then delay_val := 3000; end if; g2_time_delay_val <= delay_val; -- cntr g1 delay_chain := scan_data(95 downto 92); if (scan_data(81) = '1') then g1_mode_val <= "bypass"; if (scan_data(91) = '1') then g1_mode_val <= " off"; ASSERT false REPORT "The specified bit settings will turn OFF the G1 counter. It cannot be turned on unless the part is re-initialized." severity warning; end if; elsif (scan_data(91) = '1') then g1_mode_val <= " odd"; else g1_mode_val <= " even"; end if; high := scan_data(80 downto 72); low := scan_data(90 downto 82); g1_low_val <= alt_conv_integer(low); g1_high_val <= alt_conv_integer(high); if (alt_conv_integer(high) = 0) then g1_high_val <= 512; end if; if (alt_conv_integer(low) = 0) then g1_low_val <= 512; end if; delay_val := alt_conv_integer(delay_chain); delay_val := delay_val * 250; if (delay_val > 3000) then delay_val := 3000; end if; g1_time_delay_val <= delay_val; -- cntr g0 delay_chain := scan_data(71 downto 68); if (scan_data(57) = '1') then g0_mode_val <= "bypass"; if (scan_data(67) = '1') then g0_mode_val <= " off"; ASSERT false REPORT "The specified bit settings will turn OFF the G0 counter. It cannot be turned on unless the part is re-initialized." severity warning; end if; elsif (scan_data(67) = '1') then g0_mode_val <= " odd"; else g0_mode_val <= " even"; end if; high := scan_data(56 downto 48); low := scan_data(66 downto 58); g0_low_val <= alt_conv_integer(low); g0_high_val <= alt_conv_integer(high); if (alt_conv_integer(high) = 0) then g0_high_val <= 512; end if; if (alt_conv_integer(low) = 0) then g0_low_val <= 512; end if; delay_val := alt_conv_integer(delay_chain); delay_val := delay_val * 250; if (delay_val > 3000) then delay_val := 3000; end if; g0_time_delay_val <= delay_val; -- cntr M is_error := false; -- 'low' contains modulus for m_cntr(spread_spectrum disabled) low := scan_data(32 downto 24); m_val <= alt_conv_integer(low); if (scan_data(33) /= '1') then if (alt_conv_integer(low) = 1) then is_error := true; reconfig_err <= true; ASSERT false REPORT "Illegal 1 value for M counter. Instead, M counter should be BYPASSED. Reconfiguration may not work." severity warning; elsif (alt_conv_integer(low) = 0) then m_val <= 512; end if; if (not is_error) then if (m_mode_val = "bypass") then ASSERT false REPORT "M counter switched from BYPASS mode to enabled (M modulus = " &int2str(alt_conv_integer(low))& "). PLL may lose lock." severity warning; else ASSERT FALSE REPORT "M modulus = " &int2str(alt_conv_integer(low))& " "severity note; end if; m_mode_val <= " "; end if; elsif (scan_data(33) = '1') then if (scan_data(24) /= '0') then is_error := true; reconfig_err <= true; ASSERT false REPORT "Illegal value for M counter in BYPASS mode. The LSB of the counter should be set to 0 in order to operate the counter in BYPASS mode. Reconfiguration may not work." severity warning; else if (m_mode_val /= "bypass") then ASSERT false REPORT "M counter switched from enabled to BYPASS mode. PLL may lose lock." severity warning; end if; ASSERT FALSE REPORT "M modulus = " &int2str(1)& " "severity note; m_val <= 1; m_mode_val <= "bypass"; end if; end if; if (skip_vco = "on") then m_val <= 1; ASSERT FALSE REPORT "VCO is bypassed, setting M modulus = 1, M time delay = 0" severity note; end if; -- cntr M2 if (ss > 0) then is_error := false; low := scan_data(42 downto 34); m2_val <= alt_conv_integer(low); if (scan_data(43) /= '1') then if (alt_conv_integer(low) = 1) then is_error := true; reconfig_err <= true; ASSERT false REPORT "Illegal 1 value for M2 counter. Instead, M counter should be BYPASSED. Reconfiguration may not work." severity warning; elsif (alt_conv_integer(low) = 0) then m2_val <= 512; end if; if (not is_error) then if (m2_mode_val = "bypass") then ASSERT false REPORT "M2 counter switched from BYPASS mode to enabled (M2 modulus = " &int2str(alt_conv_integer(low))& "). PLL may lose lock." severity warning; else ASSERT FALSE REPORT "M2 modulus = " &int2str(alt_conv_integer(low))& " "severity note; end if; m2_mode_val <= " "; end if; elsif (scan_data(43) = '1') then if (scan_data(34) /= '0') then is_error := true; reconfig_err <= true; ASSERT false REPORT "Illegal value for M2 counter in BYPASS mode. The LSB of the counter should be set to 0 in order to operate the counter in BYPASS mode. Reconfiguration may not work." severity warning; else if (m2_mode_val /= "bypass") then ASSERT false REPORT "M2 counter switched from enabled to BYPASS mode. PLL may lose lock." severity warning; end if; ASSERT FALSE REPORT "M2 modulus = " &int2str(1)& " "severity note; m2_val <= 1; m2_mode_val <= "bypass"; end if; end if; if (m_mode_val /= m2_mode_val) then is_error := true; reconfig_err <= true; ASSERT false REPORT "Incompatible modes for M1/M2 counters. Either both should be BYPASSED or both NON-BYPASSED. Reconfiguration may not work." severity warning; end if; end if; delay_chain := scan_data(47 downto 44); delay_val := alt_conv_integer(delay_chain); delay_val := delay_val * 250; if (delay_val > 3000) then delay_val := 3000; end if; m_time_delay_val <= delay_val; if (skip_vco = "on") then m_time_delay_val <= 0; delay_val := 0; end if; ASSERT FALSE REPORT " M time delay = " &int2str(delay_val)& " "severity note; -- cntr N is_error := false; -- 'low' contains modulus for n_cntr(spread_spectrum disabled) low := scan_data(8 downto 0); n_val <= alt_conv_integer(low); if (scan_data(9) /= '1') then if (alt_conv_integer(low) = 1) then is_error := true; reconfig_err <= true; ASSERT false REPORT "Illegal 1 value for N counter. Instead, N counter should be BYPASSED. Reconfiguration may not work." severity warning; elsif (alt_conv_integer(low) = 0) then n_val <= 512; ASSERT FALSE REPORT "N modulus = " &int2str(512)& " "severity note; else ASSERT FALSE REPORT "N modulus = " &int2str(alt_conv_integer(low))& " "severity note; end if; if (not is_error) then if (n_mode_val = "bypass") then ASSERT false REPORT "N Counter switched from BYPASS mode to enabled (N modulus = " &int2str(alt_conv_integer(low))& "). PLL may lose lock." severity warning; else ASSERT FALSE REPORT "N modulus = " &int2str(alt_conv_integer(low))& " "severity note; end if; n_mode_val <= " "; end if; elsif (scan_data(9) = '1') then if (scan_data(0) /= '0') then is_error := true; reconfig_err <= true; ASSERT false REPORT "Illegal value for N counter in BYPASS mode. The LSB of the counter should be set to 0 in order to operate the counter in BYPASS mode. Reconfiguration may not work." severity warning; else if (n_mode_val /= "bypass") then ASSERT false REPORT "N counter switched from enabled to BYPASS mode. PLL may lose lock." severity warning; end if; ASSERT FALSE REPORT "N modulus = " &int2str(1)& " "severity note; n_val <= 1; n_mode_val <= "bypass"; end if; end if; -- cntr N2 if (ss > 0) then is_error := false; low := scan_data(18 downto 10); n2_val <= alt_conv_integer(low); if (scan_data(19) /= '1') then if (alt_conv_integer(low) = 1) then is_error := true; reconfig_err <= true; ASSERT false REPORT "Illegal 1 value for N2 counter. Instead, N counter should be BYPASSED. Reconfiguration may not work." severity warning; elsif (alt_conv_integer(low) = 0) then n2_val <= 512; end if; if (not is_error) then if (n2_mode_val = "bypass") then ASSERT false REPORT "N2 counter switched from BYPASS mode to enabled (N2 modulus = " &int2str(alt_conv_integer(low))& "). PLL may lose lock." severity warning; else ASSERT FALSE REPORT "N2 modulus = " &int2str(alt_conv_integer(low))& " "severity note; end if; n2_mode_val <= " "; end if; elsif (scan_data(19) = '1') then if (scan_data(10) /= '0') then is_error := true; reconfig_err <= true; ASSERT false REPORT "Illegal value for N2 counter in BYPASS mode. The LSB of the counter should be set to 0 in order to operate the counter in BYPASS mode. Reconfiguration may not work." severity warning; else if (n2_mode_val /= "bypass") then ASSERT false REPORT "N2 counter switched from enabled to BYPASS mode. PLL may lose lock." severity warning; end if; ASSERT FALSE REPORT "N2 modulus = " &int2str(1)& " "severity note; n2_val <= 1; n2_mode_val <= "bypass"; end if; end if; if (n_mode_val /= n2_mode_val) then is_error := true; reconfig_err <= true; ASSERT false REPORT "Incompatible modes for N1/N2 counters. Either both should be BYPASSED or both NON-BYPASSED. Reconfiguration may not work." severity warning; end if; end if; delay_chain := scan_data(23 downto 20); delay_val := alt_conv_integer(delay_chain); delay_val := delay_val * 250; if (delay_val > 3000) then delay_val := 3000; end if; n_time_delay_val <= delay_val; ASSERT FALSE REPORT " N time delay = " &int2str(delay_val)& " "severity note; else if (scan_chain = "long") then ASSERT false REPORT "E3 high = "& int2str(e3_high_val) & ", E3 low = "& int2str(e3_low_val) & ", E3 mode = "& e3_mode_val & ", E3 time delay = "& int2str(e3_time_delay_val) & " "severity note; ASSERT false REPORT "E2 high = "& int2str(e2_high_val) & ", E2 low = "& int2str(e2_low_val) & ", E2 mode = "& e2_mode_val & ", E2 time delay = "& int2str(e2_time_delay_val) & " "severity note; ASSERT false REPORT "E1 high = "& int2str(e1_high_val) & ", E1 low = "& int2str(e1_low_val) & ", E1 mode = "& e1_mode_val & ", E1 time delay = "& int2str(e1_time_delay_val) & " "severity note; ASSERT false REPORT "E0 high = "& int2str(e0_high_val) & ", E0 low = "& int2str(e0_low_val) & ", E0 mode = "& e0_mode_val & ", E0 time delay = "& int2str(e0_time_delay_val) & " "severity note; end if; ASSERT false REPORT "L1 high = "& int2str(l1_high_val) & ", L1 low = "& int2str(l1_low_val) & ", l1 mode = "& l1_mode_val & ", l1 time delay = "& int2str(l1_time_delay_val) & " "severity note; ASSERT false REPORT "L0 high = "& int2str(l0_high_val) & ", L0 low = "& int2str(l0_low_val) & ", l0 mode = "& l0_mode_val & ", l0 time delay = "& int2str(l0_time_delay_val) & " "severity note; ASSERT false REPORT "G3 high = "& int2str(g3_high_val) & ", G3 low = "& int2str(g3_low_val) & ", G3 mode = "& g3_mode_val & ", G3 time delay = "& int2str(g3_time_delay_val) & " "severity note; ASSERT false REPORT "G2 high = "& int2str(g2_high_val) & ", G2 low = "& int2str(g2_low_val) & ", G2 mode = "& g2_mode_val & ", G2 time delay = "& int2str(g2_time_delay_val) & " "severity note; ASSERT false REPORT "G1 high = "& int2str(g1_high_val) & ", G1 low = "& int2str(g1_low_val) & ", G1 mode = "& g1_mode_val & ", G1 time delay = "& int2str(g1_time_delay_val) & " "severity note; ASSERT false REPORT "G0 high = "& int2str(g0_high_val) & ", G0 low = "& int2str(g0_low_val) & ", G0 mode = "& g0_mode_val & ", G0 time delay = "& int2str(g0_time_delay_val) & " "severity note; end if; end process; process (schedule_vco, areset_ipd, ena_ipd, pfdena_ipd, refclk, fbclk) variable sched_time : time := 0 ps; TYPE time_array is ARRAY (0 to 7) of time; variable init : boolean := true; variable refclk_period : time; variable primary_clock_frequency : time; variable m_times_vco_period : time; variable new_m_times_vco_period : time; variable phase_shift : time_array := (OTHERS => 0 ps); variable last_phase_shift : time_array := (OTHERS => 0 ps); variable l_index : integer := 1; variable cycle_to_adjust : integer := 0; variable stop_vco : boolean := false; variable locked_tmp : std_logic := '0'; variable pll_is_locked : boolean := false; variable pll_about_to_lock : boolean := false; variable cycles_to_lock : integer := 0; variable cycles_to_unlock : integer := 0; variable got_first_refclk : boolean := false; variable got_second_refclk : boolean := false; variable got_first_fbclk : boolean := false; variable refclk_time : time := 0 ps; variable fbclk_time : time := 0 ps; variable first_fbclk_time : time := 0 ps; variable fbclk_period : time := 0 ps; variable first_schedule : boolean := true; variable schedule_offset : boolean := true; variable vco_val : std_logic := '0'; variable vco_period_was_phase_adjusted : boolean := false; variable phase_adjust_was_scheduled : boolean := false; variable loop_xplier : integer; variable loop_initial : integer := 0; variable loop_ph : integer := 0; variable loop_time_delay : integer := 0; variable initial_delay : time := 0 ps; variable vco_per : time; variable tmp_rem : integer; variable my_rem : integer; variable fbk_phase : integer := 0; variable pull_back_ext_fbk_cntr : integer := 0; variable pull_back_M : integer := 0; variable total_pull_back : integer := 0; variable fbk_delay : integer := 0; variable offset : time := 0 ps; variable tmp_vco_per : integer := 0; variable high_time : time; variable low_time : time; variable got_refclk_posedge : boolean := false; variable got_fbclk_posedge : boolean := false; variable inclk_out_of_range : boolean := false; variable no_warn : boolean := false; variable init_clks : boolean := true; variable ext_fbk_cntr_modulus : integer := 1; begin if (init) then if (pll_type = "fast") then locked_tmp := '1'; end if; -- jump-start the VCO -- add 1 ps delay to ensure all signals are updated to initial -- values schedule_vco <= transport not schedule_vco after 1 ps; init := false; end if; if (schedule_vco'event) then if (init_clks) then if (primary_clock = "inclk0") then refclk_period := inclk0_input_frequency * n_val * 1 ps; primary_clock_frequency := inclk0_input_frequency * 1 ps; elsif (primary_clock = "inclk1") then refclk_period := inclk1_input_frequency * n_val * 1 ps; primary_clock_frequency := inclk1_input_frequency * 1 ps; end if; m_times_vco_period := refclk_period; new_m_times_vco_period := refclk_period; init_clks := false; end if; sched_time := 0 ps; for i in 0 to 7 loop last_phase_shift(i) := phase_shift(i); end loop; cycle_to_adjust := 0; l_index := 1; m_times_vco_period := new_m_times_vco_period; end if; -- areset was asserted if (areset_ipd'event and areset_ipd = '1') then assert false report "Stratix PLL was reset" severity note; end if; -- ena was deasserted if (ena_ipd'event and ena_ipd = '0') then assert false report "Stratix PLL was disabled" severity note; end if; if (schedule_vco'event and (areset_ipd = '1' or ena_ipd = '0' or stop_vco)) then -- drop VCO taps to 0 for i in 0 to 7 loop vco_out(i) <= transport '0' after last_phase_shift(i); phase_shift(i) := 0 ps; last_phase_shift(i) := 0 ps; end loop; -- reset lock parameters locked_tmp := '0'; if (pll_type = "fast") then locked_tmp := '1'; end if; pll_is_locked := false; pll_about_to_lock := false; cycles_to_lock := 0; cycles_to_unlock := 0; got_first_refclk := false; got_second_refclk := false; refclk_time := 0 ps; got_first_fbclk := false; fbclk_time := 0 ps; first_fbclk_time := 0 ps; fbclk_period := 0 ps; first_schedule := true; schedule_offset := true; vco_val := '0'; vco_period_was_phase_adjusted := false; phase_adjust_was_scheduled := false; elsif ((schedule_vco'event or ena_ipd'event or areset_ipd'event) and areset_ipd = '0' and ena_ipd = '1' and (not stop_vco) and (now > 0 ps)) then -- note areset deassert time -- note it as refclk_time to prevent false triggering -- of stop_vco after areset if (areset_ipd'event and areset_ipd = '0') then refclk_time := now; end if; -- calculate loop_xplier : this will be different from m_val -- in external_feedback_mode loop_xplier := m_val; loop_initial := m_initial_val - 1; loop_ph := m_ph_val; loop_time_delay := m_time_delay_val; if (operation_mode = "external_feedback") then if (ext_fbk_cntr_mode = "bypass") then ext_fbk_cntr_modulus := 1; else ext_fbk_cntr_modulus := ext_fbk_cntr_high + ext_fbk_cntr_low; end if; loop_xplier := m_val * (ext_fbk_cntr_modulus); loop_ph := ext_fbk_cntr_ph; loop_initial := ext_fbk_cntr_initial - 1 + ((m_initial_val - 1) * (ext_fbk_cntr_modulus)); loop_time_delay := m_time_delay_val + ext_fbk_cntr_delay; end if; -- convert initial value to delay initial_delay := (loop_initial * m_times_vco_period)/loop_xplier; -- convert loop ph_tap to delay my_rem := (m_times_vco_period/1 ps) rem loop_xplier; tmp_vco_per := (m_times_vco_period/1 ps) / loop_xplier; if (my_rem /= 0) then tmp_vco_per := tmp_vco_per + 1; end if; fbk_phase := (loop_ph * tmp_vco_per)/8; if (operation_mode = "external_feedback") then pull_back_ext_fbk_cntr := ext_fbk_cntr_delay + (ext_fbk_cntr_initial - 1) * (m_times_vco_period/loop_xplier)/1 ps + fbk_phase; while (pull_back_ext_fbk_cntr > refclk_period/1 ps) loop pull_back_ext_fbk_cntr := pull_back_ext_fbk_cntr - refclk_period/ 1 ps; end loop; pull_back_M := m_time_delay_val + (m_initial_val - 1) * (ext_fbk_cntr_modulus) * ((refclk_period/loop_xplier)/1 ps); while (pull_back_M > refclk_period/1 ps) loop pull_back_M := pull_back_M - refclk_period/ 1 ps; end loop; else pull_back_ext_fbk_cntr := 0; pull_back_M := initial_delay/1 ps + m_time_delay_val + fbk_phase; end if; total_pull_back := pull_back_M + pull_back_ext_fbk_cntr; if (simulation_type = "timing") then total_pull_back := total_pull_back + pll_compensation_delay; end if; while (total_pull_back > refclk_period/1 ps) loop total_pull_back := total_pull_back - refclk_period/1 ps; end loop; if (total_pull_back > 0) then offset := refclk_period - (total_pull_back * 1 ps); end if; if (operation_mode = "external_feedback") then fbk_delay := pull_back_M; if (simulation_type = "timing") then fbk_delay := fbk_delay + pll_compensation_delay; end if; ext_fbk_delay <= transport (pull_back_ext_fbk_cntr - fbk_phase) after 1 ps; else fbk_delay := total_pull_back - fbk_phase; if (fbk_delay < 0) then offset := offset - (fbk_phase * 1 ps); fbk_delay := total_pull_back; end if; end if; -- assign m_delay m_delay <= transport fbk_delay after 1 ps; my_rem := (m_times_vco_period/1 ps) rem loop_xplier; for i in 1 to loop_xplier loop -- adjust cycles tmp_vco_per := (m_times_vco_period/1 ps)/loop_xplier; if (my_rem /= 0 and l_index <= my_rem) then tmp_rem := (loop_xplier * l_index) rem my_rem; cycle_to_adjust := (loop_xplier * l_index) / my_rem; if (tmp_rem /= 0) then cycle_to_adjust := cycle_to_adjust + 1; end if; end if; if (cycle_to_adjust = i) then tmp_vco_per := tmp_vco_per + 1; l_index := l_index + 1; end if; -- calculate high and low periods vco_per := tmp_vco_per * 1 ps; high_time := (tmp_vco_per/2) * 1 ps; if (tmp_vco_per rem 2 /= 0) then high_time := high_time + 1 ps; end if; low_time := vco_per - high_time; -- schedule the rising and falling edges for j in 1 to 2 loop vco_val := not vco_val; if (vco_val = '0') then sched_time := sched_time + high_time; elsif (vco_val = '1') then sched_time := sched_time + low_time; end if; -- add offset if (schedule_offset) then sched_time := sched_time + offset; schedule_offset := false; end if; -- schedule the phase taps for k in 0 to 7 loop phase_shift(k) := (k * vco_per)/8; if (first_schedule) then vco_out(k) <= transport vco_val after (sched_time + phase_shift(k)); else vco_out(k) <= transport vco_val after (sched_time + last_phase_shift(k)); end if; end loop; end loop; end loop; -- schedule once more if (first_schedule) then vco_val := not vco_val; if (vco_val = '0') then sched_time := sched_time + high_time; elsif (vco_val = '1') then sched_time := sched_time + low_time; end if; -- schedule the phase taps for k in 0 to 7 loop phase_shift(k) := (k * vco_per)/8; vco_out(k) <= transport vco_val after (sched_time + phase_shift(k)); end loop; first_schedule := false; end if; schedule_vco <= transport not schedule_vco after sched_time; if (vco_period_was_phase_adjusted) then m_times_vco_period := refclk_period; new_m_times_vco_period := refclk_period; vco_period_was_phase_adjusted := false; phase_adjust_was_scheduled := true; vco_per := m_times_vco_period/loop_xplier; for k in 0 to 7 loop phase_shift(k) := (k * vco_per)/8; end loop; end if; end if; if (refclk'event and refclk = '1' and areset_ipd = '0') then got_refclk_posedge := true; if (not got_first_refclk) then got_first_refclk := true; else got_second_refclk := true; refclk_period := now - refclk_time; -- check if incoming freq. will cause VCO range to be -- exceeded if ( (vco_max /= 0 and vco_min /= 0 and skip_vco = "off" and pfdena_ipd = '1') and (((refclk_period/1 ps)/loop_xplier > vco_max) or ((refclk_period/1 ps)/loop_xplier < vco_min)) ) then if (pll_is_locked) then assert false report " Input clock freq. is not within VCO range : PLL may lose lock" severity warning; else assert false report " Input clock freq. is not within VCO range : PLL may not lock. Please use the correct frequency." severity warning; end if; inclk_out_of_range := true; elsif (vco_min = 0 and vco_max = 0 and pll_type = "cdr") then if (refclk_period /= primary_clock_frequency) then if (not no_warn) then assert false report "Incoming clock period " & int2str(refclk_period/1 ps) & " ps for PLL does not match the specified inclock period " & int2str(primary_clock_frequency/1 ps) & " ps. ALTGXB simulation may not function correctly. " severity warning; no_warn := true; end if; end if; else inclk_out_of_range := false; end if; end if; if (stop_vco) then stop_vco := false; schedule_vco <= not schedule_vco; end if; refclk_time := now; else got_refclk_posedge := false; end if; if (fbclk'event and fbclk = '1') then got_fbclk_posedge := true; if (not got_first_fbclk) then got_first_fbclk := true; else fbclk_period := now - fbclk_time; end if; -- need refclk_period here, so initialized to proper value above if ( (now - refclk_time > 1.5 * refclk_period) and pfdena_ipd = '1') then stop_vco := true; -- reset got_first_refclk := false; got_first_fbclk := false; got_second_refclk := false; if (pll_is_locked) then pll_is_locked := false; locked_tmp := '0'; if (pll_type = "fast") then locked_tmp := '1'; end if; assert false report "Stratix PLL lost lock due to loss of input clock" severity note; end if; pll_about_to_lock := false; cycles_to_lock := 0; cycles_to_unlock := 0; first_schedule := true; end if; fbclk_time := now; else got_fbclk_posedge := false; end if; if ((got_refclk_posedge or got_fbclk_posedge) and got_second_refclk and pfdena_ipd = '1' and (not inclk_out_of_range)) then -- now we know actual incoming period if ( abs(fbclk_time - refclk_time) <= 5 ps or (got_first_fbclk and abs(refclk_period - abs(fbclk_time - refclk_time)) <= 5 ps)) then -- considered in phase if (cycles_to_lock = valid_lock_multiplier - 1) then pll_about_to_lock := true; end if; if (cycles_to_lock = valid_lock_multiplier) then if (not pll_is_locked) then assert (quiet_period_violation) report "Stratix PLL locked to incoming clock" severity note; end if; pll_is_locked := true; locked_tmp := '1'; if (pll_type = "fast") then locked_tmp := '0'; end if; end if; -- increment lock counter only if second part of above -- time check is NOT true if (not(abs(refclk_period - abs(fbclk_time - refclk_time)) <= 5 ps)) then cycles_to_lock := cycles_to_lock + 1; end if; -- adjust m_times_vco_period new_m_times_vco_period := refclk_period; else -- if locked, begin unlock if (pll_is_locked) then cycles_to_unlock := cycles_to_unlock + 1; if (cycles_to_unlock = invalid_lock_multiplier) then pll_is_locked := false; locked_tmp := '0'; if (pll_type = "fast") then locked_tmp := '1'; end if; pll_about_to_lock := false; cycles_to_lock := 0; assert (quiet_period_violation) report "Stratix PLL lost lock" severity note; first_schedule := true; schedule_offset := true; vco_period_was_phase_adjusted := false; phase_adjust_was_scheduled := false; end if; end if; if ( abs(refclk_period - fbclk_period) <= 2 ps ) then -- frequency is still good if (now = fbclk_time and (not phase_adjust_was_scheduled)) then if ( abs(fbclk_time - refclk_time) > refclk_period/2) then new_m_times_vco_period := m_times_vco_period + (refclk_period - abs(fbclk_time - refclk_time)); vco_period_was_phase_adjusted := true; else new_m_times_vco_period := m_times_vco_period - abs(fbclk_time - refclk_time); vco_period_was_phase_adjusted := true; end if; end if; else phase_adjust_was_scheduled := false; new_m_times_vco_period := refclk_period; end if; end if; end if; if (pfdena_ipd = '0') then locked_tmp := 'X'; pll_is_locked := false; cycles_to_lock := 0; end if; -- give message only at time of deassertion if (pfdena_ipd'event and pfdena_ipd = '0') then assert false report "PFDENA deasserted." severity note; elsif (pfdena_ipd'event and pfdena_ipd = '1') then got_first_refclk := false; got_second_refclk := false; refclk_time := now; end if; if (quiet_period_violation or reconfig_err or scanclr_violation or scanclr_clk_violation) then lock <= '0'; if (pll_type = "fast") then lock <= '1'; end if; else lock <= locked_tmp; end if; about_to_lock <= pll_about_to_lock after 1 ps; -- signal to calculate quiet_time sig_refclk_period <= refclk_period; -- signals for debugging sig_offset <= offset; sig_refclk_time <= refclk_time; sig_fbclk_period <= fbclk_period; sig_vco_period_was_phase_adjusted <= vco_period_was_phase_adjusted; sig_phase_adjust_was_scheduled <= phase_adjust_was_scheduled; if (stop_vco = true) then sig_stop_vco <= '1'; else sig_stop_vco <= '0'; end if; sig_m_times_vco_period <= m_times_vco_period; sig_new_m_times_vco_period <= new_m_times_vco_period; sig_got_refclk_posedge <= got_refclk_posedge; sig_got_fbclk_posedge <= got_fbclk_posedge; sig_got_second_refclk <= got_second_refclk; end process; process (scanclk_ipd, scanaclr_ipd, scan_data, transfer) variable j : integer := 0; variable pll_in_quiet_period : boolean := false; variable start_quiet_time : time := 0 ps; variable quiet_time : time := 0 ps; variable scanclr_rising_time : time := 0 ps; variable scanclr_falling_time : time := 0 ps; variable got_first_scanclk_after_scanclr_inactive_edge : boolean := false; variable scan_chain_being_reset : boolean := false; function slowest_clk(L0 : integer; L1 : integer; G0 : integer; G1 : integer; G2 : integer; G3 : integer; E0 : integer; E1 : integer; E2 : integer; E3 : integer; scan_chain : string; refclk : time; m_mod : integer) return time is variable max_modulus : integer := 0; variable q_period : time := 0 ps; variable refclk_int : integer := 0; begin if (L0 > L1) then max_modulus := L0; else max_modulus := L1; end if; if (G0 > max_modulus) then max_modulus := G0; end if; if (G1 > max_modulus) then max_modulus := G1; end if; if (G2 > max_modulus) then max_modulus := G2; end if; if (G3 > max_modulus) then max_modulus := G3; end if; if (scan_chain = "long") then if (E0 > max_modulus) then max_modulus := E0; end if; if (E1 > max_modulus) then max_modulus := E1; end if; if (E2 > max_modulus) then max_modulus := E2; end if; if (E3 > max_modulus) then max_modulus := E3; end if; end if; refclk_int := refclk / 1 ps; if (m_mod /= 0) then q_period := ((refclk_int/m_mod) * max_modulus) * 1 ps; end if; return (2*q_period); end slowest_clk; begin if (transfer'event) then if (transfer = '0') then -- clear the chain for i in scan_data'range loop scan_data(i) <= '0'; end loop; end if; elsif (scanaclr_ipd'event and scanaclr_ipd = '1') then -- scanaclr rising scanclr_rising_time := now; scan_chain_being_reset := true; elsif (scanaclr_ipd'event and scanaclr_ipd = '0' and (now > 0 ps)) then -- scanaclr falling scanclr_falling_time := now; if (scan_chain_being_reset and (now - scanclr_rising_time < TRST)) then scanclr_violation <= true; ASSERT false REPORT "Detected SCANACLR ACTIVE pulse width violation. Required is 5000 ps, actual is "& int2str((now - scanclr_rising_time) / 1 ps) &". The PLL may not function correctly." severity warning; else scanclr_violation <= false; for i in scan_data'range loop scan_data(i) <= '0'; end loop; end if; scan_chain_being_reset := false; got_first_scanclk_after_scanclr_inactive_edge := false; elsif (scanclk_ipd'event and scanclk_ipd = '1' and not got_first_scanclk_after_scanclr_inactive_edge and (now - scanclr_falling_time < TRSTCLK)) then scanclr_clk_violation <= true; got_first_scanclk_after_scanclr_inactive_edge := true; ASSERT false REPORT "Detected SCANACLR INACTIVE time violation before rising edge of SCANCLK. Required is 5000 ps, actual is "& int2str((now - scanclr_falling_time) / 1 ps) &". Reconfiguration may not work." severity warning; elsif (scanclk_ipd'event and scanclk_ipd = '1' and scanaclr_ipd = '0') then if (pll_in_quiet_period and (now - start_quiet_time < quiet_time)) then ASSERT false REPORT "Detected transition on SCANCLK during quiet period. The PLL may not function correctly." severity warning; quiet_period_violation <= true; else pll_in_quiet_period := false; for j in scan_chain_length-1 downto 1 loop scan_data(j) <= scan_data(j-1); end loop; scan_data(0) <= scandata_ipd; end if; if (not got_first_scanclk_after_scanclr_inactive_edge) then got_first_scanclk_after_scanclr_inactive_edge := true; scanclr_clk_violation <= false; end if; elsif (scanclk_ipd'event and scanclk_ipd = '0' and scanaclr_ipd = '0') then if (pll_in_quiet_period and (now - start_quiet_time < quiet_time)) then ASSERT false REPORT "Detected transition on SCANCLK during quiet period. The PLL may not function correctly." severity warning; quiet_period_violation <= true; elsif (scan_data(scan_chain_length-1) = '1') then -- reset violation flag only after another reconfig seq. quiet_period_violation <= false; -- initiate transfer transfer <= '1'; transfer <= transport '0' after 1 ps; scandataout_tmp <= '1'; pll_in_quiet_period := true; start_quiet_time := now; quiet_time := slowest_clk(l0_high_val+l0_low_val, l1_high_val+l1_low_val, g0_high_val+g0_low_val, g1_high_val+g1_low_val, g2_high_val+g2_low_val, g3_high_val+g3_low_val, e0_high_val+e0_low_val, e1_high_val+e1_low_val, e2_high_val+e2_low_val, e3_high_val+e3_low_val, scan_chain, sig_refclk_period, m_val); scandataout_tmp <= transport '0' after quiet_time; end if; end if; end process; clk0_tmp <= l0_clk when i_clk0_counter = "l0" else l1_clk when i_clk0_counter = "l1" else g0_clk when i_clk0_counter = "g0" else g1_clk when i_clk0_counter = "g1" else g2_clk when i_clk0_counter = "g2" else g3_clk when i_clk0_counter = "g3" else '0'; not_clk0_tmp <= not clk0_tmp; ena0_reg : dffp port map (D => clkena(0), CLRN => vcc, PRN => vcc, ENA => vcc, CLK => not_clk0_tmp, Q => ena0 ); clk(0) <= ena0 and clk0_tmp when (areset_ipd = '1' or ena_ipd = '0') or (about_to_lock and (not quiet_period_violation) and (not reconfig_err) and (not scanclr_violation) and (not scanclr_clk_violation)) else ena0 and 'X'; clk1_tmp <= l0_clk when i_clk1_counter = "l0" else l1_clk when i_clk1_counter = "l1" else g0_clk when i_clk1_counter = "g0" else g1_clk when i_clk1_counter = "g1" else g2_clk when i_clk1_counter = "g2" else g3_clk when i_clk1_counter = "g3" else '0'; not_clk1_tmp <= not clk1_tmp; ena1_reg : dffp port map (D => clkena(1), CLRN => vcc, PRN => vcc, ENA => vcc, CLK => not_clk1_tmp, Q => ena1 ); clk(1) <= ena1 and clk1_tmp when (areset_ipd = '1' or ena_ipd = '0') or (about_to_lock and (not quiet_period_violation) and (not reconfig_err) and (not scanclr_violation) and (not scanclr_clk_violation)) else ena1 and 'X'; clk2_tmp <= l0_clk when i_clk2_counter = "l0" else l1_clk when i_clk2_counter = "l1" else g0_clk when i_clk2_counter = "g0" else g1_clk when i_clk2_counter = "g1" else g2_clk when i_clk2_counter = "g2" else g3_clk when i_clk2_counter = "g3" else '0'; not_clk2_tmp <= not clk2_tmp; ena2_reg : dffp port map (D => clkena(2), CLRN => vcc, PRN => vcc, ENA => vcc, CLK => not_clk2_tmp, Q => ena2 ); clk(2) <= ena2 and clk2_tmp when (areset_ipd = '1' or ena_ipd = '0') or (about_to_lock and (not quiet_period_violation) and (not reconfig_err) and (not scanclr_violation) and (not scanclr_clk_violation)) else ena2 and 'X'; clk3_tmp <= l0_clk when i_clk3_counter = "l0" else l1_clk when i_clk3_counter = "l1" else g0_clk when i_clk3_counter = "g0" else g1_clk when i_clk3_counter = "g1" else g2_clk when i_clk3_counter = "g2" else g3_clk when i_clk3_counter = "g3" else '0'; not_clk3_tmp <= not clk3_tmp; ena3_reg : dffp port map (D => clkena(3), CLRN => vcc, PRN => vcc, ENA => vcc, CLK => not_clk3_tmp, Q => ena3 ); clk(3) <= ena3 and clk3_tmp when (areset_ipd = '1' or ena_ipd = '0') or (about_to_lock and (not quiet_period_violation) and (not reconfig_err) and (not scanclr_violation) and (not scanclr_clk_violation)) else ena3 and 'X'; clk4_tmp <= l0_clk when i_clk4_counter = "l0" else l1_clk when i_clk4_counter = "l1" else g0_clk when i_clk4_counter = "g0" else g1_clk when i_clk4_counter = "g1" else g2_clk when i_clk4_counter = "g2" else g3_clk when i_clk4_counter = "g3" else '0'; not_clk4_tmp <= not clk4_tmp; ena4_reg : dffp port map (D => clkena(4), CLRN => vcc, PRN => vcc, ENA => vcc, CLK => not_clk4_tmp, Q => ena4 ); clk(4) <= ena4 and clk4_tmp when (areset_ipd = '1' or ena_ipd = '0') or (about_to_lock and (not quiet_period_violation) and (not reconfig_err) and (not scanclr_violation) and (not scanclr_clk_violation)) else ena4 and 'X'; clk5_tmp <= l0_clk when i_clk5_counter = "l0" else l1_clk when i_clk5_counter = "l1" else g0_clk when i_clk5_counter = "g0" else g1_clk when i_clk5_counter = "g1" else g2_clk when i_clk5_counter = "g2" else g3_clk when i_clk5_counter = "g3" else '0'; not_clk5_tmp <= not clk5_tmp; ena5_reg : dffp port map (D => clkena(5), CLRN => vcc, PRN => vcc, ENA => vcc, CLK => not_clk5_tmp, Q => ena5 ); clk(5) <= ena5 and clk5_tmp when (areset_ipd = '1' or ena_ipd = '0') or (about_to_lock and (not quiet_period_violation) and (not reconfig_err) and (not scanclr_violation) and (not scanclr_clk_violation)) else ena5 and 'X'; extclk0_tmp <= e0_clk when i_extclk0_counter = "e0" else e1_clk when i_extclk0_counter = "e1" else e2_clk when i_extclk0_counter = "e2" else e3_clk when i_extclk0_counter = "e3" else '0'; not_extclk0_tmp <= not extclk0_tmp; extena0_reg : dffp port map (D => extclkena(0), CLRN => vcc, PRN => vcc, ENA => vcc, CLK => not_extclk0_tmp, Q => extena0 ); extclk(0) <= extena0 and extclk0_tmp when (areset_ipd = '1' or ena_ipd = '0') or (about_to_lock and (not quiet_period_violation) and (not reconfig_err) and (not scanclr_violation) and (not scanclr_clk_violation)) else extena0 and 'X'; extclk1_tmp <= e0_clk when i_extclk1_counter = "e0" else e1_clk when i_extclk1_counter = "e1" else e2_clk when i_extclk1_counter = "e2" else e3_clk when i_extclk1_counter = "e3" else '0'; not_extclk1_tmp <= not extclk1_tmp; extena1_reg : dffp port map (D => extclkena(1), CLRN => vcc, PRN => vcc, ENA => vcc, CLK => not_extclk1_tmp, Q => extena1 ); extclk(1) <= extena1 and extclk1_tmp when (areset_ipd = '1' or ena_ipd = '0') or (about_to_lock and (not quiet_period_violation) and (not reconfig_err) and (not scanclr_violation) and (not scanclr_clk_violation)) else extena1 and 'X'; extclk2_tmp <= e0_clk when i_extclk2_counter = "e0" else e1_clk when i_extclk2_counter = "e1" else e2_clk when i_extclk2_counter = "e2" else e3_clk when i_extclk2_counter = "e3" else '0'; not_extclk2_tmp <= not extclk2_tmp; extena2_reg : dffp port map (D => extclkena(2), CLRN => vcc, PRN => vcc, ENA => vcc, CLK => not_extclk2_tmp, Q => extena2 ); extclk(2) <= extena2 and extclk2_tmp when (areset_ipd = '1' or ena_ipd = '0') or (about_to_lock and (not quiet_period_violation) and (not reconfig_err) and (not scanclr_violation) and (not scanclr_clk_violation)) else extena2 and 'X'; extclk3_tmp <= e0_clk when i_extclk3_counter = "e0" else e1_clk when i_extclk3_counter = "e1" else e2_clk when i_extclk3_counter = "e2" else e3_clk when i_extclk3_counter = "e3" else '0'; not_extclk3_tmp <= not extclk3_tmp; extena3_reg : dffp port map (D => extclkena(3), CLRN => vcc, PRN => vcc, ENA => vcc, CLK => not_extclk3_tmp, Q => extena3 ); extclk(3) <= extena3 and extclk3_tmp when (areset_ipd = '1' or ena_ipd = '0') or (about_to_lock and (not quiet_period_violation) and (not reconfig_err) and (not scanclr_violation) and (not scanclr_clk_violation)) else extena3 and 'X'; enable0 <= enable0_tmp when (areset_ipd = '1' or ena_ipd = '0') or (about_to_lock and (not quiet_period_violation) and (not reconfig_err) and (not scanclr_violation) and (not scanclr_clk_violation)) else 'X'; enable1 <= enable1_tmp when (areset_ipd = '1' or ena_ipd = '0') or (about_to_lock and (not quiet_period_violation) and (not reconfig_err) and (not scanclr_violation) and (not scanclr_clk_violation)) else 'X'; scandataout <= scandataout_tmp; end vital_pll; -- END ARCHITECTURE VITAL_PLL --/////////////////////////////////////////////////////////////////////////// -- -- Entity Name : MF_stratixii_pll -- -- Description : Simulation model for the Stratix II PLL. -- In the functional mode, it is also the model for the altpll -- megafunction. -- -- Limitations : Does not support Spread Spectrum and Bandwidth. -- -- Outputs : Up to 6 output clocks, each defined by its own set of -- parameters. Locked output (active high) indicates when the -- PLL locks. clkbad, clkloss and activeclock are used for -- clock switchover to inidicate which input clock has gone -- bad, when the clock switchover initiates and which input -- clock is being used as the reference, respectively. -- scandataout is the data output of the serial scan chain. -- --/////////////////////////////////////////////////////////////////////////// library ieee, std, altera_mf; use IEEE.std_logic_1164.all; use STD.textio.all; use work.pllpack.all; use altera_mf.altera_mf_components.all; ENTITY MF_stratixii_pll is GENERIC ( operation_mode : string := "normal"; pll_type : string := "auto"; -- EGPP/FAST/AUTO compensate_clock : string := "clk0"; feedback_source : string := "clk0"; qualify_conf_done : string := "off"; test_input_comp_delay : integer := 0; test_feedback_comp_delay : integer := 0; inclk0_input_frequency : integer := 10000; inclk1_input_frequency : integer := 10000; gate_lock_signal : string := "no"; gate_lock_counter : integer := 1; valid_lock_multiplier : integer := 1; invalid_lock_multiplier : integer := 5; switch_over_type : string := "auto"; switch_over_on_lossclk : string := "off"; switch_over_on_gated_lock : string := "off"; switch_over_counter : integer := 1; enable_switch_over_counter : string := "on"; bandwidth : integer := 0; bandwidth_type : string := "auto"; down_spread : string := "0.0"; spread_frequency : integer := 0; clk0_output_frequency : integer := 0; clk0_multiply_by : integer := 1; clk0_divide_by : integer := 1; clk0_phase_shift : string := "0"; clk0_duty_cycle : integer := 50; clk1_output_frequency : integer := 0; clk1_multiply_by : integer := 1; clk1_divide_by : integer := 1; clk1_phase_shift : string := "0"; clk1_duty_cycle : integer := 50; clk2_output_frequency : integer := 0; clk2_multiply_by : integer := 1; clk2_divide_by : integer := 1; clk2_phase_shift : string := "0"; clk2_duty_cycle : integer := 50; clk3_output_frequency : integer := 0; clk3_multiply_by : integer := 1; clk3_divide_by : integer := 1; clk3_phase_shift : string := "0"; clk3_duty_cycle : integer := 50; clk4_output_frequency : integer := 0; clk4_multiply_by : integer := 1; clk4_divide_by : integer := 1; clk4_phase_shift : string := "0"; clk4_duty_cycle : integer := 50; clk5_output_frequency : integer := 0; clk5_multiply_by : integer := 1; clk5_divide_by : integer := 1; clk5_phase_shift : string := "0"; clk5_duty_cycle : integer := 50; pfd_min : integer := 0; pfd_max : integer := 0; vco_min : integer := 0; vco_max : integer := 0; vco_center : integer := 0; -- ADVANCED USER PARAMETERS m_initial : integer := 1; m : integer := 1; n : integer := 1; m2 : integer := 1; n2 : integer := 1; ss : integer := 0; c0_high : integer := 1; c0_low : integer := 1; c0_initial : integer := 1; c0_mode : string := "bypass"; c0_ph : integer := 0; c1_high : integer := 1; c1_low : integer := 1; c1_initial : integer := 1; c1_mode : string := "bypass"; c1_ph : integer := 0; c2_high : integer := 1; c2_low : integer := 1; c2_initial : integer := 1; c2_mode : string := "bypass"; c2_ph : integer := 0; c3_high : integer := 1; c3_low : integer := 1; c3_initial : integer := 1; c3_mode : string := "bypass"; c3_ph : integer := 0; c4_high : integer := 1; c4_low : integer := 1; c4_initial : integer := 1; c4_mode : string := "bypass"; c4_ph : integer := 0; c5_high : integer := 1; c5_low : integer := 1; c5_initial : integer := 1; c5_mode : string := "bypass"; c5_ph : integer := 0; m_ph : integer := 0; clk0_counter : string := "c0"; clk1_counter : string := "c1"; clk2_counter : string := "c2"; clk3_counter : string := "c3"; clk4_counter : string := "c4"; clk5_counter : string := "c5"; c1_use_casc_in : string := "off"; c2_use_casc_in : string := "off"; c3_use_casc_in : string := "off"; c4_use_casc_in : string := "off"; c5_use_casc_in : string := "off"; m_test_source : integer := 5; c0_test_source : integer := 5; c1_test_source : integer := 5; c2_test_source : integer := 5; c3_test_source : integer := 5; c4_test_source : integer := 5; c5_test_source : integer := 5; -- LVDS mode parameters enable0_counter : string := "c0"; enable1_counter : string := "c1"; sclkout0_phase_shift : string := "0"; sclkout1_phase_shift : string := "0"; charge_pump_current : integer := 0; loop_filter_r : string := "1.0"; loop_filter_c : integer := 1; common_rx_tx : string := "off"; rx_outclock_resource : string := "auto"; use_vco_bypass : string := "false"; use_dc_coupling : string := "false"; pll_compensation_delay : integer := 0; simulation_type : string := "functional"; vco_multiply_by : integer := 0; vco_divide_by : integer := 0 ); PORT ( inclk : in std_logic_vector(1 downto 0); fbin : in std_logic; ena : in std_logic := '1'; clkswitch : in std_logic; areset : in std_logic; pfdena : in std_logic; scanread : in std_logic; scanwrite : in std_logic; scandata : in std_logic; scanclk : in std_logic; clk : out std_logic_vector(5 downto 0); clkbad : out std_logic_vector(1 downto 0); activeclock : out std_logic; locked : out std_logic; clkloss : out std_logic; scandataout : out std_logic; scandone : out std_logic; testupout : out std_logic; testdownout : out std_logic; -- lvds specific ports enable0 : out std_logic; enable1 : out std_logic; sclkout : out std_logic_vector(1 downto 0) ); END MF_stratixii_pll; ARCHITECTURE vital_pll of MF_stratixii_pll is TYPE int_array is ARRAY(NATURAL RANGE <>) of integer; TYPE str_array is ARRAY(NATURAL RANGE <>) of string(1 to 6); -- internal advanced parameter signals signal i_vco_min : integer; signal i_vco_max : integer; signal i_vco_center : integer; signal i_pfd_min : integer; signal i_pfd_max : integer; signal c_ph_val : int_array(0 to 5) := (OTHERS => 0); signal c_high_val : int_array(0 to 5) := (OTHERS => 1); signal c_low_val : int_array(0 to 5) := (OTHERS => 1); signal c_initial_val : int_array(0 to 5) := (OTHERS => 1); signal c_mode_val : str_array(0 to 5); -- old values signal c_high_val_old : int_array(0 to 5) := (OTHERS => 1); signal c_low_val_old : int_array(0 to 5) := (OTHERS => 1); signal c_ph_val_old : int_array(0 to 5) := (OTHERS => 0); signal c_mode_val_old : str_array(0 to 5); -- hold registers signal c_high_val_hold : int_array(0 to 5) := (OTHERS => 1); signal c_low_val_hold : int_array(0 to 5) := (OTHERS => 1); signal c_ph_val_hold : int_array(0 to 5) := (OTHERS => 0); signal c_mode_val_hold : str_array(0 to 5); -- temp registers signal sig_c_ph_val_tmp : int_array(0 to 5) := (OTHERS => 0); signal sig_c_low_val_tmp : int_array(0 to 5) := (OTHERS => 1); signal c_ph_val_orig : int_array(0 to 5) := (OTHERS => 0); signal i_clk5_counter : string(1 to 2) := "c5"; signal i_clk4_counter : string(1 to 2) := "c4"; signal i_clk3_counter : string(1 to 2) := "c3"; signal i_clk2_counter : string(1 to 2) := "c2"; signal i_clk1_counter : string(1 to 2) := "c1"; signal i_clk0_counter : string(1 to 2) := "c0"; signal i_charge_pump_current : integer; signal i_loop_filter_r : integer; -- end internal advanced parameter signals -- CONSTANTS CONSTANT SCAN_CHAIN : integer := 174; CONSTANT cntrs : str_array(5 downto 0) := (" C5", " C4", " C3", " C2", " C1", " C0"); CONSTANT ss_cntrs : str_array(0 to 3) := (" M", " M2", " N", " N2"); -- signals signal vcc : std_logic := '1'; signal fbclk : std_logic; signal refclk : std_logic; signal c0_clk : std_logic; signal c1_clk : std_logic; signal c2_clk : std_logic; signal c3_clk : std_logic; signal c4_clk : std_logic; signal c5_clk : std_logic; signal vco_out : std_logic_vector(7 downto 0) := (OTHERS => '0'); -- signals to assign values to counter params signal m_val : int_array(0 to 1) := (OTHERS => 1); signal n_val : int_array(0 to 1) := (OTHERS => 1); signal m_ph_val : integer := 0; signal m_initial_val : integer := m_initial; signal m_mode_val : str_array(0 to 1) := (OTHERS => " "); signal n_mode_val : str_array(0 to 1) := (OTHERS => " "); -- old values signal m_val_old : int_array(0 to 1) := (OTHERS => 1); --signal m_val_tmp : int_array(0 to 1) := (OTHERS => 1); signal n_val_old : int_array(0 to 1) := (OTHERS => 1); signal m_mode_val_old : str_array(0 to 1) := (OTHERS => " "); signal n_mode_val_old : str_array(0 to 1) := (OTHERS => " "); signal m_ph_val_old : integer := 0; signal scan_data : std_logic_vector(173 downto 0) := (OTHERS => '0'); signal clk0_tmp : std_logic; signal clk1_tmp : std_logic; signal clk2_tmp : std_logic; signal clk3_tmp : std_logic; signal clk4_tmp : std_logic; signal clk5_tmp : std_logic; signal sclkout0_tmp : std_logic; signal sclkout1_tmp : std_logic; signal clkin : std_logic := '0'; signal gate_locked : std_logic := '0'; signal lock : std_logic := '0'; signal about_to_lock : boolean := false; signal reconfig_err : boolean := false; signal inclk_c0 : std_logic; signal inclk_c1 : std_logic; signal inclk_c2 : std_logic; signal inclk_c3 : std_logic; signal inclk_c4 : std_logic; signal inclk_c5 : std_logic; signal inclk_m : std_logic; signal devpor : std_logic; signal devclrn : std_logic; signal inclk0_ipd : std_logic; signal inclk1_ipd : std_logic; signal ena_ipd : std_logic; signal pfdena_ipd : std_logic; signal areset_ipd : std_logic; signal fbin_ipd : std_logic; signal scanclk_ipd : std_logic; signal scanread_ipd : std_logic; signal scanwrite_ipd : std_logic; signal scandata_ipd : std_logic; signal clkswitch_ipd : std_logic; -- registered signals signal scanread_reg : std_logic := '0'; signal scanwrite_reg : std_logic := '0'; signal inclk_c0_dly1 : std_logic := '0'; signal inclk_c0_dly2 : std_logic := '0'; signal inclk_c0_dly3 : std_logic := '0'; signal inclk_c0_dly4 : std_logic := '0'; signal inclk_c0_dly5 : std_logic := '0'; signal inclk_c0_dly6 : std_logic := '0'; signal inclk_c1_dly1 : std_logic := '0'; signal inclk_c1_dly2 : std_logic := '0'; signal inclk_c1_dly3 : std_logic := '0'; signal inclk_c1_dly4 : std_logic := '0'; signal inclk_c1_dly5 : std_logic := '0'; signal inclk_c1_dly6 : std_logic := '0'; signal sig_offset : time := 0 ps; signal sig_refclk_time : time := 0 ps; signal sig_fbclk_period : time := 0 ps; signal sig_vco_period_was_phase_adjusted : boolean := false; signal sig_phase_adjust_was_scheduled : boolean := false; signal sig_stop_vco : std_logic := '0'; signal sig_m_times_vco_period : time := 0 ps; signal sig_new_m_times_vco_period : time := 0 ps; signal sig_got_refclk_posedge : boolean := false; signal sig_got_fbclk_posedge : boolean := false; signal sig_got_second_refclk : boolean := false; signal m_delay : integer := 0; signal n_delay : integer := 0; signal sig_curr_clock : string(1 to 6) := "inclk0"; signal inclk1_tmp : std_logic := '0'; signal scan_chain_length : integer := SCAN_CHAIN; signal ext_fbk_cntr_high : integer := 0; signal ext_fbk_cntr_low : integer := 0; signal ext_fbk_cntr_ph : integer := 0; signal ext_fbk_cntr_initial : integer := 1; signal ext_fbk_cntr : string(1 to 2) := "c0"; signal ext_fbk_cntr_mode : string(1 to 6) := "bypass"; signal ext_fbk_cntr_index : integer := 0; signal enable0_tmp : std_logic := '0'; signal enable1_tmp : std_logic := '0'; signal reset_low : std_logic := '0'; signal scandataout_tmp : std_logic := '0'; signal scandone_tmp : std_logic := '0'; signal sig_refclk_period : time := (inclk0_input_frequency * 1 ps) * n; signal schedule_vco : std_logic := '0'; signal areset_ena_sig : std_logic := '0'; signal inclk_c0_from_vco : std_logic; signal inclk_c1_from_vco : std_logic; signal inclk_c2_from_vco : std_logic; signal inclk_c3_from_vco : std_logic; signal inclk_c4_from_vco : std_logic; signal inclk_c5_from_vco : std_logic; signal inclk_m_from_vco : std_logic; signal inclk_sclkout0_from_vco : std_logic; signal inclk_sclkout1_from_vco : std_logic; COMPONENT MF_mn_cntr PORT ( clk : IN std_logic; reset : IN std_logic := '0'; cout : OUT std_logic; initial_value : IN integer := 1; modulus : IN integer := 1; time_delay : IN integer := 0 ); END COMPONENT; COMPONENT arm_scale_cntr PORT ( clk : IN std_logic; reset : IN std_logic := '0'; cout : OUT std_logic; initial : IN integer := 1; high : IN integer := 1; low : IN integer := 1; mode : IN string := "bypass"; ph_tap : IN integer := 0 ); END COMPONENT; COMPONENT DFFP PORT( Q : out STD_LOGIC := '0'; D : in STD_LOGIC := '1'; CLRN : in STD_LOGIC := '1'; PRN : in STD_LOGIC := '1'; CLK : in STD_LOGIC := '0'; ENA : in STD_LOGIC := '1'); END COMPONENT; COMPONENT MF_PLL_REG PORT( Q : out STD_LOGIC := '0'; D : in STD_LOGIC := '1'; CLRN : in STD_LOGIC := '1'; PRN : in STD_LOGIC := '1'; CLK : in STD_LOGIC := '0'; ENA : in STD_LOGIC := '1'); END COMPONENT; begin ---------------------- -- INPUT PATH DELAYs ---------------------- WireDelay : block begin inclk0_ipd <= inclk(0); inclk1_ipd <= inclk(1); areset_ipd <= areset; ena_ipd <= ena; fbin_ipd <= fbin; pfdena_ipd <= pfdena; scanclk_ipd <= scanclk; scanread_ipd <= scanread; scandata_ipd <= scandata; scanwrite_ipd <= scanwrite; clkswitch_ipd <= clkswitch; end block; inclk_m <= clkin when m_test_source = 0 else clk0_tmp when operation_mode = "external_feedback" and feedback_source = "clk0" else clk1_tmp when operation_mode = "external_feedback" and feedback_source = "clk1" else clk2_tmp when operation_mode = "external_feedback" and feedback_source = "clk2" else clk3_tmp when operation_mode = "external_feedback" and feedback_source = "clk3" else clk4_tmp when operation_mode = "external_feedback" and feedback_source = "clk4" else clk5_tmp when operation_mode = "external_feedback" and feedback_source = "clk5" else inclk_m_from_vco; ext_fbk_cntr_high <= c_high_val(ext_fbk_cntr_index); ext_fbk_cntr_low <= c_low_val(ext_fbk_cntr_index); ext_fbk_cntr_ph <= c_ph_val(ext_fbk_cntr_index); ext_fbk_cntr_initial <= c_initial_val(ext_fbk_cntr_index); ext_fbk_cntr_mode <= c_mode_val(ext_fbk_cntr_index); areset_ena_sig <= areset_ipd or (not ena_ipd) or sig_stop_vco; m1 : MF_mn_cntr port map (clk => inclk_m, reset => areset_ena_sig, cout => fbclk, initial_value => m_initial_val, modulus => m_val(0), time_delay => m_delay ); -- add delta delay to inclk1 to ensure inclk0 and inclk1 are processed -- in different simulation deltas. inclk1_tmp <= inclk1_ipd; process (inclk0_ipd, inclk1_tmp, clkswitch_ipd) variable input_value : std_logic := '0'; variable current_clock : string(1 to 6) := "inclk0"; variable clk0_count, clk1_count : integer := 0; variable clk0_is_bad, clk1_is_bad : std_logic := '0'; variable primary_clk_is_bad : boolean := false; variable current_clk_is_bad : boolean := false; variable got_curr_clk_falling_edge_after_clkswitch : boolean := false; variable switch_over_count : integer := 0; variable active_clock : std_logic := '0'; variable external_switch : boolean := false; begin if (now = 0 ps) then if (switch_over_type = "manual" and clkswitch_ipd = '1') then current_clock := "inclk1"; active_clock := '1'; end if; end if; if (clkswitch_ipd'event and clkswitch_ipd = '1' and switch_over_type = "auto") then external_switch := true; elsif (switch_over_type = "manual") then if (clkswitch_ipd'event and clkswitch_ipd = '1') then current_clock := "inclk1"; active_clock := '1'; elsif (clkswitch_ipd'event and clkswitch_ipd = '0') then current_clock := "inclk0"; active_clock := '0'; end if; end if; -- save the current inclk event value if (inclk0_ipd'event) then input_value := inclk0_ipd; elsif (inclk1_tmp'event) then input_value := inclk1_tmp; end if; -- check if either input clk is bad if (inclk0_ipd'event and inclk0_ipd = '1') then clk0_count := clk0_count + 1; clk0_is_bad := '0'; clk1_count := 0; if (clk0_count > 2) then -- no event on other clk for 2 cycles clk1_is_bad := '1'; if (current_clock = "inclk1") then current_clk_is_bad := true; end if; end if; end if; if (inclk1_tmp'event and inclk1_tmp = '1') then clk1_count := clk1_count + 1; clk1_is_bad := '0'; clk0_count := 0; if (clk1_count > 2) then -- no event on other clk for 2 cycles clk0_is_bad := '1'; if (current_clock = "inclk0") then current_clk_is_bad := true; end if; end if; end if; -- check if the bad clk is the primary clock if (clk0_is_bad = '1') then primary_clk_is_bad := true; else primary_clk_is_bad := false; end if; -- actual switching if (inclk0_ipd'event and current_clock = "inclk0") then if (external_switch) then if (not got_curr_clk_falling_edge_after_clkswitch) then if (inclk0_ipd = '0') then got_curr_clk_falling_edge_after_clkswitch := true; end if; clkin <= transport inclk0_ipd; end if; else clkin <= transport inclk0_ipd; end if; elsif (inclk1_tmp'event and current_clock = "inclk1") then if (external_switch) then if (not got_curr_clk_falling_edge_after_clkswitch) then if (inclk1_tmp = '0') then got_curr_clk_falling_edge_after_clkswitch := true; end if; clkin <= transport inclk1_tmp; end if; else clkin <= transport inclk1_tmp; end if; else if (input_value = '1' and switch_over_on_lossclk = "on" and enable_switch_over_counter = "on" and primary_clk_is_bad) then switch_over_count := switch_over_count + 1; end if; if (input_value = '0') then if (external_switch and (got_curr_clk_falling_edge_after_clkswitch or current_clk_is_bad)) or (switch_over_on_lossclk = "on" and primary_clk_is_bad and (enable_switch_over_counter = "off" or switch_over_count = switch_over_counter)) then got_curr_clk_falling_edge_after_clkswitch := false; if (current_clock = "inclk0") then current_clock := "inclk1"; else current_clock := "inclk0"; end if; active_clock := not active_clock; switch_over_count := 0; external_switch := false; current_clk_is_bad := false; end if; end if; end if; -- schedule outputs clkbad(0) <= clk0_is_bad; clkbad(1) <= clk1_is_bad; if (switch_over_on_lossclk = "on" and clkswitch_ipd /= '1') then if (primary_clk_is_bad) then -- assert clkloss clkloss <= '1'; else clkloss <= '0'; end if; else clkloss <= clkswitch_ipd; end if; activeclock <= active_clock; -- for debugging only -- sig_curr_clock <= current_clock; end process; process (inclk_sclkout0_from_vco) begin sclkout0_tmp <= inclk_sclkout0_from_vco; end process; process (inclk_sclkout1_from_vco) begin sclkout1_tmp <= inclk_sclkout1_from_vco; end process; n1 : MF_mn_cntr port map (clk => clkin, reset => areset_ipd, cout => refclk, initial_value => n_val(0), modulus => n_val(0)); inclk_c0 <= clkin when c0_test_source = 0 else refclk when c0_test_source = 1 else inclk_c0_from_vco; c0 : arm_scale_cntr port map (clk => inclk_c0, reset => areset_ena_sig, cout => c0_clk, initial => c_initial_val(0), high => c_high_val(0), low => c_low_val(0), mode => c_mode_val(0), ph_tap => c_ph_val(0)); inclk_c1 <= clkin when c1_test_source = 0 else fbclk when c1_test_source = 2 else c0_clk when c1_use_casc_in = "on" else inclk_c1_from_vco; c1 : arm_scale_cntr port map (clk => inclk_c1, reset => areset_ena_sig, cout => c1_clk, initial => c_initial_val(1), high => c_high_val(1), low => c_low_val(1), mode => c_mode_val(1), ph_tap => c_ph_val(1)); inclk_c2 <= clkin when c2_test_source = 0 else c1_clk when c2_use_casc_in = "on" else inclk_c2_from_vco; c2 : arm_scale_cntr port map (clk => inclk_c2, reset => areset_ena_sig, cout => c2_clk, initial => c_initial_val(2), high => c_high_val(2), low => c_low_val(2), mode => c_mode_val(2), ph_tap => c_ph_val(2)); inclk_c3 <= clkin when c3_test_source = 0 else c2_clk when c3_use_casc_in = "on" else inclk_c3_from_vco; c3 : arm_scale_cntr port map (clk => inclk_c3, reset => areset_ena_sig, cout => c3_clk, initial => c_initial_val(3), high => c_high_val(3), low => c_low_val(3), mode => c_mode_val(3), ph_tap => c_ph_val(3)); inclk_c4 <= clkin when c4_test_source = 0 else c3_clk when c4_use_casc_in = "on" else inclk_c4_from_vco; c4 : arm_scale_cntr port map (clk => inclk_c4, reset => areset_ena_sig, cout => c4_clk, initial => c_initial_val(4), high => c_high_val(4), low => c_low_val(4), mode => c_mode_val(4), ph_tap => c_ph_val(4)); inclk_c5 <= clkin when c5_test_source = 0 else c4_clk when c5_use_casc_in = "on" else inclk_c5_from_vco; c5 : arm_scale_cntr port map (clk => inclk_c5, reset => areset_ena_sig, cout => c5_clk, initial => c_initial_val(5), high => c_high_val(5), low => c_low_val(5), mode => c_mode_val(5), ph_tap => c_ph_val(5)); inclk_c0_dly1 <= inclk_c0; inclk_c0_dly2 <= inclk_c0_dly1; inclk_c0_dly3 <= inclk_c0_dly2; inclk_c0_dly4 <= inclk_c0_dly3; inclk_c0_dly5 <= inclk_c0_dly4; inclk_c0_dly6 <= inclk_c0_dly5; inclk_c1_dly1 <= inclk_c1; inclk_c1_dly2 <= inclk_c1_dly1; inclk_c1_dly3 <= inclk_c1_dly2; inclk_c1_dly4 <= inclk_c1_dly3; inclk_c1_dly5 <= inclk_c1_dly4; inclk_c1_dly6 <= inclk_c1_dly5; process(inclk_c0_dly6, inclk_c1_dly6, areset_ipd, ena_ipd, sig_stop_vco) variable c0_got_first_rising_edge : boolean := false; variable c0_count : integer := 2; variable c0_tmp, c1_tmp : std_logic := '0'; variable c1_got_first_rising_edge : boolean := false; variable c1_count : integer := 2; begin if (areset_ipd = '1' or ena_ipd = '0' or sig_stop_vco = '1') then c0_count := 2; c1_count := 2; c0_got_first_rising_edge := false; c1_got_first_rising_edge := false; else if (not c0_got_first_rising_edge) then if (inclk_c0_dly6'event and inclk_c0_dly6 = '1') then c0_got_first_rising_edge := true; end if; elsif (inclk_c0_dly6'event) then c0_count := c0_count + 1; if (c0_count = (c_high_val(0) + c_low_val(0)) * 2) then c0_count := 1; end if; end if; if (inclk_c0_dly6'event and inclk_c0_dly6 = '0') then if (c0_count = 1) then c0_tmp := '1'; c0_got_first_rising_edge := false; else c0_tmp := '0'; end if; end if; if (not c1_got_first_rising_edge) then if (inclk_c1_dly6'event and inclk_c1_dly6 = '1') then c1_got_first_rising_edge := true; end if; elsif (inclk_c1_dly6'event) then c1_count := c1_count + 1; if (c1_count = (c_high_val(1) + c_low_val(1)) * 2) then c1_count := 1; end if; end if; if (inclk_c1_dly6'event and inclk_c1_dly6 = '0') then if (c1_count = 1) then c1_tmp := '1'; c1_got_first_rising_edge := false; else c1_tmp := '0'; end if; end if; end if; if (enable0_counter = "c0") then enable0_tmp <= c0_tmp; elsif (enable0_counter = "c1") then enable0_tmp <= c1_tmp; else enable0_tmp <= '0'; end if; if (enable1_counter = "c0") then enable1_tmp <= c0_tmp; elsif (enable1_counter = "c1") then enable1_tmp <= c1_tmp; else enable1_tmp <= '0'; end if; end process; glocked_cntr : process(clkin, ena_ipd, areset_ipd) variable count : integer := 0; variable output : std_logic := '0'; begin if (areset_ipd = '1') then count := 0; output := '0'; elsif (clkin'event and clkin = '1') then if (ena_ipd = '1') then count := count + 1; if (count = gate_lock_counter) then output := '1'; end if; end if; end if; gate_locked <= output; end process; locked <= gate_locked and lock when gate_lock_signal = "yes" else lock; process (scandone_tmp) variable buf : line; begin if (scandone_tmp'event and scandone_tmp = '0') then if (reconfig_err = false) then ASSERT false REPORT "PLL Reprogramming completed with the following values (Values in parantheses indicate values before reprogramming) :" severity note; ASSERT false REPORT "N modulus = " &int2str(n_val(0))& " (" &int2str(n_val_old(0))& ") "severity note; ASSERT false REPORT "M modulus = " &int2str(m_val(0))& " (" &int2str(m_val_old(0))& ") "severity note; ASSERT false REPORT "M ph_tap = " &int2str(m_ph_val)& " (" &int2str(m_ph_val_old)& ") "severity note; if (ss > 0) then ASSERT false REPORT "M2 modulus = " &int2str(m_val(1))& " (" &int2str(m_val_old(1))& ") "severity note; ASSERT false REPORT "N2 modulus = " &int2str(n_val(1))& " (" &int2str(n_val_old(1))& ") "severity note; end if; for i in 0 to 5 loop write (buf, cntrs(i)); write (buf, string'(" : high = ")); write (buf, c_high_val(i)); write (buf, string'(" (")); write (buf, c_high_val_old(i)); write (buf, string'(") ")); write (buf, string'(" , low = ")); write (buf, sig_c_low_val_tmp(i)); write (buf, string'(" (")); write (buf, c_low_val_old(i)); write (buf, string'(") ")); write (buf, string'(" , mode = ")); write (buf, c_mode_val(i)); write (buf, string'(" (")); write (buf, c_mode_val_old(i)); write (buf, string'(") ")); write (buf, string'(" , phase tap = ")); write (buf, c_ph_val(i)); write (buf, string'(" (")); write (buf, c_ph_val_old(i)); write (buf, string'(") ")); writeline(output, buf); end loop; else ASSERT false REPORT "Errors were encountered during PLL reprogramming. Please refer to error/warning messages above." severity warning; end if; end if; end process; process (scanwrite_reg, c0_clk, c1_clk, c2_clk, c3_clk, c4_clk, c5_clk, vco_out, fbclk) variable init : boolean := true; variable low, high : std_logic_vector(7 downto 0); variable mode : string(1 to 6) := "bypass"; variable is_error : boolean := false; variable m_tmp, n_tmp : std_logic_vector(8 downto 0); variable c_high_val_tmp : int_array(0 to 5) := (OTHERS => 1); variable c_low_val_tmp : int_array(0 to 5) := (OTHERS => 1); variable c_ph_val_tmp : int_array(0 to 5) := (OTHERS => 0); variable c_mode_val_tmp : str_array(0 to 5); variable m_ph_val_tmp : integer := 0; variable m_val_tmp : int_array(0 to 1) := (OTHERS => 1); variable c0_rising_edge_transfer_done : boolean := false; variable c1_rising_edge_transfer_done : boolean := false; variable c2_rising_edge_transfer_done : boolean := false; variable c3_rising_edge_transfer_done : boolean := false; variable c4_rising_edge_transfer_done : boolean := false; variable c5_rising_edge_transfer_done : boolean := false; -- user to advanced variables variable max_neg_abs : integer := 0; variable i_m_initial : integer; variable i_m : integer := 1; variable i_n : integer := 1; variable i_m2 : integer; variable i_n2 : integer; variable i_ss : integer; variable i_c_high : int_array(0 to 5); variable i_c_low : int_array(0 to 5); variable i_c_initial : int_array(0 to 5); variable i_c_ph : int_array(0 to 5); variable i_c_mode : str_array(0 to 5); variable i_m_ph : integer; variable output_count : integer; variable new_divisor : integer; variable clk0_cntr : string(1 to 2) := "c0"; variable clk1_cntr : string(1 to 2) := "c1"; variable clk2_cntr : string(1 to 2) := "c2"; variable clk3_cntr : string(1 to 2) := "c3"; variable clk4_cntr : string(1 to 2) := "c4"; variable clk5_cntr : string(1 to 2) := "c5"; variable fbk_cntr : string(1 to 2); variable fbk_cntr_index : integer; variable start_bit : integer; variable quiet_time : time := 0 ps; variable tmp_scan_data : std_logic_vector(173 downto 0) := (OTHERS => '0'); function slowest_clk(C0 : integer; C1 : integer; C2 : integer; C3 : integer; C4 : integer; C5 : integer; refclk : time; m_mod : integer) return time is variable max_modulus : integer := 0; variable q_period : time := 0 ps; variable refclk_int : integer := 0; begin if (C0 > C1) then max_modulus := C0; else max_modulus := C1; end if; if (C2 > max_modulus) then max_modulus := C2; end if; if (C3 > max_modulus) then max_modulus := C3; end if; if (C4 > max_modulus) then max_modulus := C4; end if; if (C5 > max_modulus) then max_modulus := C5; end if; refclk_int := refclk / 1 ps; if (m_mod /= 0) then q_period := (refclk_int * max_modulus / m_mod) * 1 ps; end if; return (2*q_period); end slowest_clk; begin if (init) then if (m = 0) then clk5_cntr := "c5"; clk4_cntr := "c4"; clk3_cntr := "c3"; clk2_cntr := "c2"; clk1_cntr := "c1"; clk0_cntr := "c0"; else clk5_cntr := clk5_counter; clk4_cntr := clk4_counter; clk3_cntr := clk3_counter; clk2_cntr := clk2_counter; clk1_cntr := clk1_counter; clk0_cntr := clk0_counter; end if; if (operation_mode = "external_feedback") then if (feedback_source = "clk0") then fbk_cntr := clk0_cntr; elsif (feedback_source = "clk1") then fbk_cntr := clk1_cntr; elsif (feedback_source = "clk2") then fbk_cntr := clk2_cntr; elsif (feedback_source = "clk3") then fbk_cntr := clk3_cntr; elsif (feedback_source = "clk4") then fbk_cntr := clk4_cntr; elsif (feedback_source = "clk5") then fbk_cntr := clk5_cntr; else fbk_cntr := "c0"; end if; if (fbk_cntr = "c0") then fbk_cntr_index := 0; elsif (fbk_cntr = "c1") then fbk_cntr_index := 1; elsif (fbk_cntr = "c2") then fbk_cntr_index := 2; elsif (fbk_cntr = "c3") then fbk_cntr_index := 3; elsif (fbk_cntr = "c4") then fbk_cntr_index := 4; elsif (fbk_cntr = "c5") then fbk_cntr_index := 5; end if; ext_fbk_cntr <= fbk_cntr; ext_fbk_cntr_index <= fbk_cntr_index; end if; i_clk0_counter <= clk0_cntr; i_clk1_counter <= clk1_cntr; i_clk2_counter <= clk2_cntr; i_clk3_counter <= clk3_cntr; i_clk4_counter <= clk4_cntr; i_clk5_counter <= clk5_cntr; if (m = 0) then -- convert user parameters to advanced if (((pll_type = "fast") or (pll_type = "lvds")) and ((vco_multiply_by /= 0) and (vco_divide_by /= 0))) then i_n := vco_divide_by; i_m := vco_multiply_by; else i_n := 1; i_m := lcm (clk0_multiply_by, clk1_multiply_by, clk2_multiply_by, clk3_multiply_by, clk4_multiply_by, clk5_multiply_by, 1, 1, 1, 1, inclk0_input_frequency); end if; max_neg_abs := maxnegabs(str2int(clk0_phase_shift), str2int(clk1_phase_shift), str2int(clk2_phase_shift), str2int(clk3_phase_shift), str2int(clk4_phase_shift), str2int(clk5_phase_shift), 0, 0, 0, 0); i_m_ph := counter_ph(get_phase_degree(max_neg_abs,inclk0_input_frequency), i_m, i_n); i_c_ph(0) := counter_ph(get_phase_degree(ph_adjust(str2int(clk0_phase_shift),max_neg_abs),inclk0_input_frequency), i_m, i_n); i_c_ph(1) := counter_ph(get_phase_degree(ph_adjust(str2int(clk1_phase_shift),max_neg_abs),inclk0_input_frequency), i_m, i_n); i_c_ph(2) := counter_ph(get_phase_degree(ph_adjust(str2int(clk2_phase_shift),max_neg_abs),inclk0_input_frequency), i_m, i_n); i_c_ph(3) := counter_ph(get_phase_degree(ph_adjust(str2int(clk3_phase_shift),max_neg_abs),inclk0_input_frequency), i_m, i_n); i_c_ph(4) := counter_ph(get_phase_degree(ph_adjust(str2int(clk4_phase_shift),max_neg_abs),inclk0_input_frequency), i_m, i_n); i_c_ph(5) := counter_ph(get_phase_degree(ph_adjust(str2int(clk5_phase_shift),max_neg_abs),inclk0_input_frequency), i_m, i_n); i_c_high(0) := counter_high(output_counter_value(clk0_divide_by, clk0_multiply_by, i_m, i_n), clk0_duty_cycle); i_c_high(1) := counter_high(output_counter_value(clk1_divide_by, clk1_multiply_by, i_m, i_n), clk1_duty_cycle); i_c_high(2) := counter_high(output_counter_value(clk2_divide_by, clk2_multiply_by, i_m, i_n), clk2_duty_cycle); i_c_high(3) := counter_high(output_counter_value(clk3_divide_by, clk3_multiply_by, i_m, i_n), clk3_duty_cycle); i_c_high(4) := counter_high(output_counter_value(clk4_divide_by, clk4_multiply_by, i_m, i_n), clk4_duty_cycle); i_c_high(5) := counter_high(output_counter_value(clk5_divide_by, clk5_multiply_by, i_m, i_n), clk5_duty_cycle); i_c_low(0) := counter_low(output_counter_value(clk0_divide_by, clk0_multiply_by, i_m, i_n), clk0_duty_cycle); i_c_low(1) := counter_low(output_counter_value(clk1_divide_by, clk1_multiply_by, i_m, i_n), clk1_duty_cycle); i_c_low(2) := counter_low(output_counter_value(clk2_divide_by, clk2_multiply_by, i_m, i_n), clk2_duty_cycle); i_c_low(3) := counter_low(output_counter_value(clk3_divide_by, clk3_multiply_by, i_m, i_n), clk3_duty_cycle); i_c_low(4) := counter_low(output_counter_value(clk4_divide_by, clk4_multiply_by, i_m, i_n), clk4_duty_cycle); i_c_low(5) := counter_low(output_counter_value(clk5_divide_by, clk5_multiply_by, i_m, i_n), clk5_duty_cycle); i_m_initial := counter_initial(get_phase_degree(max_neg_abs, inclk0_input_frequency), i_m,i_n); i_c_initial(0) := counter_initial(get_phase_degree(ph_adjust(str2int(clk0_phase_shift), max_neg_abs), inclk0_input_frequency), i_m, i_n); i_c_initial(1) := counter_initial(get_phase_degree(ph_adjust(str2int(clk1_phase_shift), max_neg_abs), inclk0_input_frequency), i_m, i_n); i_c_initial(2) := counter_initial(get_phase_degree(ph_adjust(str2int(clk2_phase_shift), max_neg_abs), inclk0_input_frequency), i_m, i_n); i_c_initial(3) := counter_initial(get_phase_degree(ph_adjust(str2int(clk3_phase_shift), max_neg_abs), inclk0_input_frequency), i_m, i_n); i_c_initial(4) := counter_initial(get_phase_degree(ph_adjust(str2int(clk4_phase_shift), max_neg_abs), inclk0_input_frequency), i_m, i_n); i_c_initial(5) := counter_initial(get_phase_degree(ph_adjust(str2int(clk5_phase_shift), max_neg_abs), inclk0_input_frequency), i_m, i_n); i_c_mode(0) := counter_mode(clk0_duty_cycle, output_counter_value(clk0_divide_by, clk0_multiply_by, i_m, i_n)); i_c_mode(1) := counter_mode(clk1_duty_cycle, output_counter_value(clk1_divide_by, clk1_multiply_by, i_m, i_n)); i_c_mode(2) := counter_mode(clk2_duty_cycle, output_counter_value(clk2_divide_by, clk2_multiply_by, i_m, i_n)); i_c_mode(3) := counter_mode(clk3_duty_cycle, output_counter_value(clk3_divide_by, clk3_multiply_by, i_m, i_n)); i_c_mode(4) := counter_mode(clk4_duty_cycle, output_counter_value(clk4_divide_by, clk4_multiply_by, i_m, i_n)); i_c_mode(5) := counter_mode(clk5_duty_cycle, output_counter_value(clk5_divide_by, clk5_multiply_by, i_m, i_n)); -- in external feedback mode, need to adjust M value to take -- into consideration the external feedback counter value if(operation_mode = "external_feedback") then -- if there is a negative phase shift, m_initial can -- only be 1 if (max_neg_abs > 0) then i_m_initial := 1; end if; -- calculate the feedback counter multiplier if (i_c_mode(fbk_cntr_index) = "bypass") then output_count := 1; else output_count := i_c_high(fbk_cntr_index) + i_c_low(fbk_cntr_index); end if; if (i_m > output_count) then i_m := i_m / output_count; else new_divisor := gcd(i_m, output_count); i_m := i_m / new_divisor; i_n := output_count / new_divisor; end if; end if; else -- m /= 0 i_n := n; i_m := m; i_m_initial := m_initial; i_m_ph := m_ph; i_c_ph(0) := c0_ph; i_c_ph(1) := c1_ph; i_c_ph(2) := c2_ph; i_c_ph(3) := c3_ph; i_c_ph(4) := c4_ph; i_c_ph(5) := c5_ph; i_c_high(0) := c0_high; i_c_high(1) := c1_high; i_c_high(2) := c2_high; i_c_high(3) := c3_high; i_c_high(4) := c4_high; i_c_high(5) := c5_high; i_c_low(0) := c0_low; i_c_low(1) := c1_low; i_c_low(2) := c2_low; i_c_low(3) := c3_low; i_c_low(4) := c4_low; i_c_low(5) := c5_low; i_c_initial(0) := c0_initial; i_c_initial(1) := c1_initial; i_c_initial(2) := c2_initial; i_c_initial(3) := c3_initial; i_c_initial(4) := c4_initial; i_c_initial(5) := c5_initial; i_c_mode(0) := translate_string(c0_mode); i_c_mode(1) := translate_string(c1_mode); i_c_mode(2) := translate_string(c2_mode); i_c_mode(3) := translate_string(c3_mode); i_c_mode(4) := translate_string(c4_mode); i_c_mode(5) := translate_string(c5_mode); end if; -- user to advanced conversion. m_initial_val <= i_m_initial; n_val(0) <= i_n; m_val(0) <= i_m; m_val(1) <= m2; n_val(1) <= n2; if (i_m = 1) then m_mode_val(0) <= "bypass"; else m_mode_val(0) <= " "; end if; if (m2 = 1) then m_mode_val(1) <= "bypass"; end if; if (i_n = 1) then n_mode_val(0) <= "bypass"; end if; if (n2 = 1) then n_mode_val(1) <= "bypass"; end if; m_ph_val <= i_m_ph; m_ph_val_tmp := i_m_ph; m_val_tmp := m_val; for i in 0 to 5 loop c_ph_val(i) <= i_c_ph(i); c_initial_val(i) <= i_c_initial(i); c_high_val(i) <= i_c_high(i); c_low_val(i) <= i_c_low(i); c_mode_val(i) <= i_c_mode(i); c_high_val_tmp(i) := i_c_high(i); c_low_val_tmp(i) := i_c_low(i); c_mode_val_tmp(i) := i_c_mode(i); c_ph_val_tmp(i) := i_c_ph(i); c_ph_val_orig(i) <= i_c_ph(i); c_high_val_hold(i) <= i_c_high(i); c_low_val_hold(i) <= i_c_low(i); c_mode_val_hold(i) <= i_c_mode(i); end loop; init := false; elsif (scanwrite_reg'event and scanwrite_reg = '1') then ASSERT false REPORT "PLL Reprogramming Initiated" severity note; reconfig_err <= false; scandone_tmp <= transport '1'; quiet_time := slowest_clk(c_high_val(0)+c_low_val(0), c_high_val(1)+c_low_val(1), c_high_val(2)+c_low_val(2), c_high_val(3)+c_low_val(3), c_high_val(4)+c_low_val(4), c_high_val(5)+c_low_val(5), sig_refclk_period, m_val(0)); scandone_tmp <= transport '0' after quiet_time; -- LF -- CP -- cntrs c0-c5 -- make temporary copy of scan_data for processing tmp_scan_data := scan_data; -- save old values for display info. m_val_old <= m_val; n_val_old <= n_val; m_mode_val_old <= m_mode_val; n_mode_val_old <= n_mode_val; m_ph_val_old <= m_ph_val; c_high_val_old <= c_high_val; c_low_val_old <= c_low_val; c_ph_val_old <= c_ph_val; c_mode_val_old <= c_mode_val; for i in 0 to 5 loop start_bit := 42 + (i*20); if (tmp_scan_data(start_bit + 8) = '1') then c_mode_val_tmp(i) := "bypass"; if (tmp_scan_data(start_bit + 17) = '1') then c_mode_val_tmp(i) := " off"; ASSERT false REPORT "The specified bit settings will turn OFF the " &cntrs(i)& "counter. It cannot be turned on unless the part is re-initialized." severity warning; end if; elsif (tmp_scan_data(start_bit + 17) = '1') then c_mode_val_tmp(i) := " odd"; else c_mode_val_tmp(i) := " even"; end if; if (tmp_scan_data(start_bit + 18) = '0') then -- do nothing elsif (tmp_scan_data(start_bit + 18) = '1') then if (tmp_scan_data(start_bit + 19) = '1') then c_ph_val_tmp(i) := c_ph_val(i) + 1; if (c_ph_val_tmp(i) > 7) then c_ph_val_tmp(i) := 0; end if; elsif (tmp_scan_data(start_bit + 19) = '0') then c_ph_val_tmp(i) := c_ph_val_tmp(i) - 1; if (c_ph_val_tmp(i) < 0) then c_ph_val_tmp(i) := 7; end if; end if; end if; high := tmp_scan_data(start_bit + 7 downto start_bit); low := tmp_scan_data(start_bit+16 downto start_bit+9); if (tmp_scan_data(start_bit+7 downto start_bit) = "00000000") then c_high_val_tmp(i) := 512; else c_high_val_tmp(i) := alt_conv_integer(high); end if; if (tmp_scan_data(start_bit+16 downto start_bit+9) = "00000000") then c_low_val_tmp(i) := 512; else c_low_val_tmp(i) := alt_conv_integer(low); end if; end loop; sig_c_ph_val_tmp <= c_ph_val_tmp; sig_c_low_val_tmp <= c_low_val_tmp; -- cntrs M/M2 for i in 0 to 1 loop start_bit := 20 + (i*10); if ( i = 0 or (i = 1 and ss > 0) ) then is_error := false; m_tmp := tmp_scan_data(start_bit+8 downto start_bit); m_val_tmp(i) := alt_conv_integer(m_tmp); if (tmp_scan_data(start_bit+9) /= '1') then if (m_mode_val(i) = "bypass") then is_error := true; reconfig_err <= true; ASSERT false REPORT "Illegal mode for " &ss_cntrs(i)& " counter. Cannot switch between BYPASS/NON-BYPASS modes. Reconfiguration may not work." severity warning; -- Mode is illegal : give warning elsif (tmp_scan_data(start_bit+8 downto start_bit) = "000000001") then is_error := true; reconfig_err <= true; -- cntr value is illegal : give warning ASSERT false REPORT "Illegal 1 value for " &ss_cntrs(i)& "counter. Instead " &ss_cntrs(i)& "should be BYPASSED. Reconfiguration may not work." severity warning; elsif (tmp_scan_data(start_bit+8 downto start_bit) = "000000000") then m_val_tmp(i) := 512; end if; m_mode_val(i) <= " "; elsif (tmp_scan_data(start_bit+9) = '1') then if (m_mode_val(i) /= "bypass") then is_error := true; reconfig_err <= true; ASSERT false REPORT "Illegal mode for the " &ss_cntrs(i)& "counter. Cannot switch between BYPASS/NON-BYPASS modes. Reconfiguration may not work." severity warning; elsif (tmp_scan_data(start_bit) /= '0') then is_error := true; reconfig_err <= true; ASSERT false report "Illegal value for counter " &ss_cntrs(i)& "in BYPASS mode. The LSB of the counter should be set to 0 in order to operate the counter in BYPASS mode. Reconfiguration may not work." severity warning; else m_val_tmp(i) := 1; end if; m_mode_val(i) <= "bypass"; end if; end if; end loop; if (ss > 0) then if (m_mode_val(0) /= m_mode_val(1)) then reconfig_err <= true; is_error := true; ASSERT false REPORT "Incompatible modes for M/M2 counters. Either both should be BYPASSED or both NON-BYPASSED. Reconfiguration may not work." severity warning; end if; end if; if (scan_data(40) = '0') then -- do nothing elsif (scan_data(40) = '1' and scan_data(41) = '1') then m_ph_val_tmp := m_ph_val_tmp + 1; if (m_ph_val_tmp > 7) then m_ph_val_tmp := 0; end if; elsif (scan_data(40) = '1' and scan_data(41) = '0') then m_ph_val_tmp := m_ph_val_tmp - 1; if (m_ph_val_tmp < 0) then m_ph_val_tmp := 7; end if; else reconfig_err <= true; ASSERT false REPORT "Illegal values for M counter phase tap. Reconfiguration may not work." severity warning; end if; -- cntrs N/N2 for i in 0 to 1 loop start_bit := i*10; if ( i = 0 or (i = 1 and ss > 0) ) then is_error := false; n_tmp := tmp_scan_data(start_bit+8 downto start_bit); n_val(i) <= alt_conv_integer(n_tmp); if (tmp_scan_data(start_bit+9) /= '1') then if (n_mode_val(i) = "bypass") then is_error := true; reconfig_err <= true; ASSERT false REPORT "Illegal mode for " &ss_cntrs(2+i)& " counter. Cannot switch between BYPASS/NON-BYPASS modes. Reconfiguration may not work." severity warning; elsif (tmp_scan_data(start_bit+8 downto start_bit) = "000000001") then is_error := true; reconfig_err <= true; -- cntr value is illegal : give warning ASSERT false REPORT "Illegal 1 value for " &ss_cntrs(2+i)& "counter. Instead " &ss_cntrs(2+i)& "should be BYPASSED. Reconfiguration may not work." severity warning; elsif (tmp_scan_data(start_bit+8 downto start_bit) = "000000000") then n_val(i) <= 512; end if; n_mode_val(i) <= " "; elsif (tmp_scan_data(start_bit+9) = '1') then if (n_mode_val(i) /= "bypass") then is_error := true; reconfig_err <= true; ASSERT false REPORT "Illegal mode for the " &ss_cntrs(2+i)& "counter. Cannot switch between BYPASS/NON-BYPASS modes. Reconfiguration may not work." severity warning; elsif (tmp_scan_data(start_bit) /= '0') then is_error := true; reconfig_err <= true; ASSERT false report "Illegal value for counter " &ss_cntrs(2+i)& "in BYPASS mode. The LSB of the counter should be set to 0 in order to operate the counter in BYPASS mode. Reconfiguration may not work." severity warning; else n_val(i) <= 1; end if; n_mode_val(i) <= "bypass"; end if; end if; end loop; if (ss > 0) then if (n_mode_val(0) /= n_mode_val(1)) then reconfig_err <= true; is_error := true; ASSERT false REPORT "Incompatible modes for N/N2 counters. Either both should be BYPASSED or both NON-BYPASSED. Reconfiguration may not work." severity warning; end if; end if; end if; if (scandone_tmp = '1') then if (fbclk'event and fbclk = '1') then m_val <= m_val_tmp; end if; if (c0_clk'event and c0_clk = '1') then c_high_val_hold(0) <= c_high_val_tmp(0); c_mode_val_hold(0) <= c_mode_val_tmp(0); c0_rising_edge_transfer_done := true; c_high_val(0) <= c_high_val_hold(0); c_mode_val(0) <= c_mode_val_hold(0); end if; if (c1_clk'event and c1_clk = '1') then c_high_val_hold(1) <= c_high_val_tmp(1); c_mode_val_hold(1) <= c_mode_val_tmp(1); c1_rising_edge_transfer_done := true; c_high_val(1) <= c_high_val_hold(1); c_mode_val(1) <= c_mode_val_hold(1); end if; if (c2_clk'event and c2_clk = '1') then c_high_val_hold(2) <= c_high_val_tmp(2); c_mode_val_hold(2) <= c_mode_val_tmp(2); c2_rising_edge_transfer_done := true; c_high_val(2) <= c_high_val_hold(2); c_mode_val(2) <= c_mode_val_hold(2); end if; if (c3_clk'event and c3_clk = '1') then c_high_val_hold(3) <= c_high_val_tmp(3); c_mode_val_hold(3) <= c_mode_val_tmp(3); c_high_val(3) <= c_high_val_hold(3); c_mode_val(3) <= c_mode_val_hold(3); c3_rising_edge_transfer_done := true; end if; if (c4_clk'event and c4_clk = '1') then c_high_val_hold(4) <= c_high_val_tmp(4); c_mode_val_hold(4) <= c_mode_val_tmp(4); c_high_val(4) <= c_high_val_hold(4); c_mode_val(4) <= c_mode_val_hold(4); c4_rising_edge_transfer_done := true; end if; if (c5_clk'event and c5_clk = '1') then c_high_val_hold(5) <= c_high_val_tmp(5); c_mode_val_hold(5) <= c_mode_val_tmp(5); c_high_val(5) <= c_high_val_hold(5); c_mode_val(5) <= c_mode_val_hold(5); c5_rising_edge_transfer_done := true; end if; end if; if (c0_clk'event and c0_clk = '0' and c0_rising_edge_transfer_done) then c_low_val_hold(0) <= c_low_val_tmp(0); c_low_val(0) <= c_low_val_hold(0); end if; if (c1_clk'event and c1_clk = '0' and c1_rising_edge_transfer_done) then c_low_val_hold(1) <= c_low_val_tmp(1); c_low_val(1) <= c_low_val_hold(1); end if; if (c2_clk'event and c2_clk = '0' and c2_rising_edge_transfer_done) then c_low_val_hold(2) <= c_low_val_tmp(2); c_low_val(2) <= c_low_val_hold(2); end if; if (c3_clk'event and c3_clk = '0' and c3_rising_edge_transfer_done) then c_low_val_hold(3) <= c_low_val_tmp(3); c_low_val(3) <= c_low_val_hold(3); end if; if (c4_clk'event and c4_clk = '0' and c4_rising_edge_transfer_done) then c_low_val_hold(4) <= c_low_val_tmp(4); c_low_val(4) <= c_low_val_hold(4); end if; if (c5_clk'event and c5_clk = '0' and c5_rising_edge_transfer_done) then c_low_val_hold(5) <= c_low_val_tmp(5); c_low_val(5) <= c_low_val_hold(5); end if; if (scandone_tmp = '1') then if (vco_out(0)'event and vco_out(0) = '0') then for i in 0 to 5 loop if (c_ph_val(i) = 0) then c_ph_val(i) <= c_ph_val_tmp(i); end if; end loop; if (m_ph_val = 0) then m_ph_val <= m_ph_val_tmp; end if; end if; if (vco_out(1)'event and vco_out(1) = '0') then for i in 0 to 5 loop if (c_ph_val(i) = 1) then c_ph_val(i) <= c_ph_val_tmp(i); end if; end loop; if (m_ph_val = 1) then m_ph_val <= m_ph_val_tmp; end if; end if; if (vco_out(2)'event and vco_out(2) = '0') then for i in 0 to 5 loop if (c_ph_val(i) = 2) then c_ph_val(i) <= c_ph_val_tmp(i); end if; end loop; if (m_ph_val = 2) then m_ph_val <= m_ph_val_tmp; end if; end if; if (vco_out(3)'event and vco_out(3) = '0') then for i in 0 to 5 loop if (c_ph_val(i) = 3) then c_ph_val(i) <= c_ph_val_tmp(i); end if; end loop; if (m_ph_val = 3) then m_ph_val <= m_ph_val_tmp; end if; end if; if (vco_out(4)'event and vco_out(4) = '0') then for i in 0 to 5 loop if (c_ph_val(i) = 4) then c_ph_val(i) <= c_ph_val_tmp(i); end if; end loop; if (m_ph_val = 4) then m_ph_val <= m_ph_val_tmp; end if; end if; if (vco_out(5)'event and vco_out(5) = '0') then for i in 0 to 5 loop if (c_ph_val(i) = 5) then c_ph_val(i) <= c_ph_val_tmp(i); end if; end loop; if (m_ph_val = 5) then m_ph_val <= m_ph_val_tmp; end if; end if; if (vco_out(6)'event and vco_out(6) = '0') then for i in 0 to 5 loop if (c_ph_val(i) = 6) then c_ph_val(i) <= c_ph_val_tmp(i); end if; end loop; if (m_ph_val = 6) then m_ph_val <= m_ph_val_tmp; end if; end if; if (vco_out(7)'event and vco_out(7) = '0') then for i in 0 to 5 loop if (c_ph_val(i) = 7) then c_ph_val(i) <= c_ph_val_tmp(i); end if; end loop; if (m_ph_val = 7) then m_ph_val <= m_ph_val_tmp; end if; end if; end if; if (vco_out'event) then inclk_c0_from_vco <= vco_out(c_ph_val(0)); inclk_c1_from_vco <= vco_out(c_ph_val(1)); inclk_c2_from_vco <= vco_out(c_ph_val(2)); inclk_c3_from_vco <= vco_out(c_ph_val(3)); inclk_c4_from_vco <= vco_out(c_ph_val(4)); inclk_c5_from_vco <= vco_out(c_ph_val(5)); if (enable0_counter = "c0") then inclk_sclkout0_from_vco <= vco_out(c_ph_val(0)); elsif (enable0_counter = "c1") then inclk_sclkout0_from_vco <= vco_out(c_ph_val(1)); end if; if (enable1_counter = "c0") then inclk_sclkout1_from_vco <= vco_out(c_ph_val(0)); elsif (enable1_counter = "c1") then inclk_sclkout1_from_vco <= vco_out(c_ph_val(1)); end if; inclk_m_from_vco <= vco_out(m_ph_val); end if; end process; process (schedule_vco, areset_ipd, ena_ipd, pfdena_ipd, refclk, fbclk) variable sched_time : time := 0 ps; TYPE time_array is ARRAY (0 to 7) of time; variable init : boolean := true; variable refclk_period : time; variable m_times_vco_period : time; variable new_m_times_vco_period : time; variable phase_shift : time_array := (OTHERS => 0 ps); variable last_phase_shift : time_array := (OTHERS => 0 ps); variable l_index : integer := 1; variable cycle_to_adjust : integer := 0; variable stop_vco : boolean := false; variable locked_tmp : std_logic := '0'; variable pll_is_locked : boolean := false; variable pll_about_to_lock : boolean := false; variable cycles_to_lock : integer := 0; variable cycles_to_unlock : integer := 0; variable got_first_refclk : boolean := false; variable got_second_refclk : boolean := false; variable got_first_fbclk : boolean := false; variable refclk_time : time := 0 ps; variable fbclk_time : time := 0 ps; variable first_fbclk_time : time := 0 ps; variable fbclk_period : time := 0 ps; variable first_schedule : boolean := true; variable vco_val : std_logic := '0'; variable vco_period_was_phase_adjusted : boolean := false; variable phase_adjust_was_scheduled : boolean := false; variable loop_xplier : integer; variable loop_initial : integer := 0; variable loop_ph : integer := 0; variable loop_time_delay : integer := 0; variable initial_delay : time := 0 ps; variable vco_per : time; variable tmp_rem : integer; variable my_rem : integer; variable fbk_phase : integer := 0; variable pull_back_M : integer := 0; variable total_pull_back : integer := 0; variable fbk_delay : integer := 0; variable offset : time := 0 ps; variable tmp_vco_per : integer := 0; variable high_time : time; variable low_time : time; variable got_refclk_posedge : boolean := false; variable got_fbclk_posedge : boolean := false; variable inclk_out_of_range : boolean := false; variable ext_fbk_cntr_modulus : integer := 1; variable init_clks : boolean := true; begin if (init) then -- jump-start the VCO -- add 1 ps delay to ensure all signals are updated to initial -- values schedule_vco <= transport not schedule_vco after 1 ps; init := false; end if; if (schedule_vco'event) then if (init_clks) then refclk_period := inclk0_input_frequency * n_val(0) * 1 ps; m_times_vco_period := refclk_period; new_m_times_vco_period := refclk_period; init_clks := false; end if; sched_time := 0 ps; for i in 0 to 7 loop last_phase_shift(i) := phase_shift(i); end loop; cycle_to_adjust := 0; l_index := 1; m_times_vco_period := new_m_times_vco_period; end if; -- areset was asserted if (areset_ipd'event and areset_ipd = '1') then assert false report "PLL was reset" severity note; end if; -- ena was deasserted if (ena_ipd'event and ena_ipd = '0') then assert false report "PLL was disabled" severity note; end if; if (schedule_vco'event and (areset_ipd = '1' or ena_ipd = '0' or stop_vco)) then -- drop VCO taps to 0 for i in 0 to 7 loop vco_out(i) <= transport '0' after last_phase_shift(i); phase_shift(i) := 0 ps; last_phase_shift(i) := 0 ps; end loop; -- reset lock parameters locked_tmp := '0'; pll_is_locked := false; pll_about_to_lock := false; cycles_to_lock := 0; cycles_to_unlock := 0; got_first_refclk := false; got_second_refclk := false; refclk_time := 0 ps; got_first_fbclk := false; fbclk_time := 0 ps; first_fbclk_time := 0 ps; fbclk_period := 0 ps; first_schedule := true; vco_val := '0'; vco_period_was_phase_adjusted := false; phase_adjust_was_scheduled := false; elsif ((schedule_vco'event or ena_ipd'event or areset_ipd'event) and areset_ipd = '0' and ena_ipd = '1' and (not stop_vco) and now > 0 ps) then -- note areset deassert time -- note it as refclk_time to prevent false triggering -- of stop_vco after areset if (areset_ipd'event and areset_ipd = '0') then refclk_time := now; end if; -- calculate loop_xplier : this will be different from m_val -- in external_feedback_mode loop_xplier := m_val(0); loop_initial := m_initial_val - 1; loop_ph := m_ph_val; if (operation_mode = "external_feedback") then if (ext_fbk_cntr_mode = "bypass") then ext_fbk_cntr_modulus := 1; else ext_fbk_cntr_modulus := ext_fbk_cntr_high + ext_fbk_cntr_low; end if; loop_xplier := m_val(0) * (ext_fbk_cntr_modulus); loop_ph := ext_fbk_cntr_ph; loop_initial := ext_fbk_cntr_initial - 1 + ((m_initial_val - 1) * ext_fbk_cntr_modulus); end if; -- convert initial value to delay initial_delay := (loop_initial * m_times_vco_period)/loop_xplier; -- convert loop ph_tap to delay my_rem := (m_times_vco_period/1 ps) rem loop_xplier; tmp_vco_per := (m_times_vco_period/1 ps) / loop_xplier; if (my_rem /= 0) then tmp_vco_per := tmp_vco_per + 1; end if; fbk_phase := (loop_ph * tmp_vco_per)/8; if (operation_mode = "external_feedback") then pull_back_M := (m_initial_val - 1) * ext_fbk_cntr_modulus * ((refclk_period/loop_xplier)/1 ps); while (pull_back_M > refclk_period/1 ps) loop pull_back_M := pull_back_M - refclk_period/ 1 ps; end loop; else pull_back_M := initial_delay/1 ps + fbk_phase; end if; total_pull_back := pull_back_M; if (simulation_type = "timing") then total_pull_back := total_pull_back + pll_compensation_delay; end if; while (total_pull_back > refclk_period/1 ps) loop total_pull_back := total_pull_back - refclk_period/1 ps; end loop; if (total_pull_back > 0) then offset := refclk_period - (total_pull_back * 1 ps); end if; if (operation_mode = "external_feedback") then fbk_delay := pull_back_M; if (simulation_type = "timing") then fbk_delay := fbk_delay + pll_compensation_delay; end if; else fbk_delay := total_pull_back - fbk_phase; if (fbk_delay < 0) then offset := offset - (fbk_phase * 1 ps); fbk_delay := total_pull_back; end if; end if; -- assign m_delay m_delay <= transport fbk_delay after 1 ps; my_rem := (m_times_vco_period/1 ps) rem loop_xplier; for i in 1 to loop_xplier loop -- adjust cycles tmp_vco_per := (m_times_vco_period/1 ps)/loop_xplier; if (my_rem /= 0 and l_index <= my_rem) then tmp_rem := (loop_xplier * l_index) rem my_rem; cycle_to_adjust := (loop_xplier * l_index) / my_rem; if (tmp_rem /= 0) then cycle_to_adjust := cycle_to_adjust + 1; end if; end if; if (cycle_to_adjust = i) then tmp_vco_per := tmp_vco_per + 1; l_index := l_index + 1; end if; -- calculate high and low periods vco_per := tmp_vco_per * 1 ps; high_time := (tmp_vco_per/2) * 1 ps; if (tmp_vco_per rem 2 /= 0) then high_time := high_time + 1 ps; end if; low_time := vco_per - high_time; -- schedule the rising and falling edges for j in 1 to 2 loop vco_val := not vco_val; if (vco_val = '0') then sched_time := sched_time + high_time; elsif (vco_val = '1') then sched_time := sched_time + low_time; end if; -- schedule the phase taps for k in 0 to 7 loop phase_shift(k) := (k * vco_per)/8; if (first_schedule) then vco_out(k) <= transport vco_val after (sched_time + phase_shift(k)); else vco_out(k) <= transport vco_val after (sched_time + last_phase_shift(k)); end if; end loop; end loop; end loop; -- schedule once more if (first_schedule) then vco_val := not vco_val; if (vco_val = '0') then sched_time := sched_time + high_time; elsif (vco_val = '1') then sched_time := sched_time + low_time; end if; -- schedule the phase taps for k in 0 to 7 loop phase_shift(k) := (k * vco_per)/8; vco_out(k) <= transport vco_val after (sched_time + phase_shift(k)); end loop; first_schedule := false; end if; schedule_vco <= transport not schedule_vco after sched_time; if (vco_period_was_phase_adjusted) then m_times_vco_period := refclk_period; new_m_times_vco_period := refclk_period; vco_period_was_phase_adjusted := false; phase_adjust_was_scheduled := true; vco_per := m_times_vco_period/loop_xplier; for k in 0 to 7 loop phase_shift(k) := (k * vco_per)/8; end loop; end if; end if; if (refclk'event and refclk = '1' and areset_ipd = '0') then got_refclk_posedge := true; if (not got_first_refclk) then got_first_refclk := true; else got_second_refclk := true; refclk_period := now - refclk_time; -- check if incoming freq. will cause VCO range to be -- exceeded if ( (vco_max /= 0 and vco_min /= 0 and pfdena_ipd = '1') and (((refclk_period/1 ps)/loop_xplier > vco_max) or ((refclk_period/1 ps)/loop_xplier < vco_min)) ) then if (pll_is_locked) then assert false report " Input clock freq. is not within VCO range : PLL may lose lock" severity warning; if (inclk_out_of_range) then pll_is_locked := false; locked_tmp := '0'; pll_about_to_lock := false; cycles_to_lock := 0; vco_period_was_phase_adjusted := false; phase_adjust_was_scheduled := false; assert false report "PLL lost lock." severity note; end if; else assert false report " Input clock freq. is not within VCO range : PLL may not lock. Please use the correct frequency." severity warning; end if; inclk_out_of_range := true; else inclk_out_of_range := false; end if; end if; if (stop_vco) then stop_vco := false; schedule_vco <= not schedule_vco; end if; refclk_time := now; else got_refclk_posedge := false; end if; if (fbclk'event and fbclk = '1') then got_fbclk_posedge := true; if (not got_first_fbclk) then got_first_fbclk := true; else fbclk_period := now - fbclk_time; end if; -- need refclk_period here, so initialized to proper value above if ( (now - refclk_time > 1.5 * refclk_period) and pfdena_ipd = '1') then stop_vco := true; -- reset got_first_refclk := false; got_first_fbclk := false; got_second_refclk := false; if (pll_is_locked) then pll_is_locked := false; locked_tmp := '0'; assert false report "PLL lost lock due to loss of input clock" severity note; end if; pll_about_to_lock := false; cycles_to_lock := 0; cycles_to_unlock := 0; first_schedule := true; end if; fbclk_time := now; else got_fbclk_posedge := false; end if; if ((got_refclk_posedge or got_fbclk_posedge) and got_second_refclk and pfdena_ipd = '1' and (not inclk_out_of_range)) then -- now we know actual incoming period if ( abs(fbclk_time - refclk_time) <= 5 ps or (got_first_fbclk and abs(refclk_period - abs(fbclk_time - refclk_time)) <= 5 ps)) then -- considered in phase if (cycles_to_lock = valid_lock_multiplier - 1) then pll_about_to_lock := true; end if; if (cycles_to_lock = valid_lock_multiplier) then if (not pll_is_locked) then assert false report "Stratix II PLL locked to incoming clock" severity note; end if; pll_is_locked := true; locked_tmp := '1'; cycles_to_unlock := 0; end if; -- increment lock counter only if second part of above -- time check is NOT true if (not(abs(refclk_period - abs(fbclk_time - refclk_time)) <= 5 ps)) then cycles_to_lock := cycles_to_lock + 1; end if; -- adjust m_times_vco_period new_m_times_vco_period := refclk_period; else -- if locked, begin unlock if (pll_is_locked) then cycles_to_unlock := cycles_to_unlock + 1; if (cycles_to_unlock = invalid_lock_multiplier) then pll_is_locked := false; locked_tmp := '0'; pll_about_to_lock := false; cycles_to_lock := 0; vco_period_was_phase_adjusted := false; phase_adjust_was_scheduled := false; assert false report "PLL lost lock." severity note; end if; end if; if ( abs(refclk_period - fbclk_period) <= 2 ps ) then -- frequency is still good if (now = fbclk_time and (not phase_adjust_was_scheduled)) then if ( abs(fbclk_time - refclk_time) > refclk_period/2) then new_m_times_vco_period := m_times_vco_period + (refclk_period - abs(fbclk_time - refclk_time)); vco_period_was_phase_adjusted := true; else new_m_times_vco_period := m_times_vco_period - abs(fbclk_time - refclk_time); vco_period_was_phase_adjusted := true; end if; end if; else phase_adjust_was_scheduled := false; new_m_times_vco_period := refclk_period; end if; end if; end if; if (pfdena_ipd = '0') then if (pll_is_locked) then locked_tmp := 'X'; end if; pll_is_locked := false; cycles_to_lock := 0; end if; -- give message only at time of deassertion if (pfdena_ipd'event and pfdena_ipd = '0') then assert false report "PFDENA deasserted." severity note; elsif (pfdena_ipd'event and pfdena_ipd = '1') then got_first_refclk := false; got_second_refclk := false; refclk_time := now; end if; if (reconfig_err) then lock <= '0'; else lock <= locked_tmp; end if; about_to_lock <= pll_about_to_lock after 1 ps; -- signal to calculate quiet_time sig_refclk_period <= refclk_period; -- signals for debugging sig_offset <= offset; sig_refclk_time <= refclk_time; sig_fbclk_period <= fbclk_period; sig_vco_period_was_phase_adjusted <= vco_period_was_phase_adjusted; sig_phase_adjust_was_scheduled <= phase_adjust_was_scheduled; if (stop_vco = true) then sig_stop_vco <= '1'; else sig_stop_vco <= '0'; end if; sig_m_times_vco_period <= m_times_vco_period; sig_new_m_times_vco_period <= new_m_times_vco_period; sig_got_refclk_posedge <= got_refclk_posedge; sig_got_fbclk_posedge <= got_fbclk_posedge; sig_got_second_refclk <= got_second_refclk; end process; process (scanclk_ipd) variable j : integer := 0; variable scanread_active_edge : time := 0 ps; variable got_first_scanclk : boolean := false; variable scanclk_last_rising_edge : time := 0 ps; variable scanclk_period : time := 0 ps; begin if (scanclk_ipd'event and scanclk_ipd = '1') then -- register scanread scanread_reg <= scanread_ipd; if (scanread_ipd = '1' and scanread_reg = '0') then scanread_active_edge := now; end if; -- register scanwrite scanwrite_reg <= scanwrite_ipd; if (got_first_scanclk) then scanclk_period := now - scanclk_last_rising_edge; else got_first_scanclk := true; end if; if (scanclk_period > 0 ps and scanread_reg = '1' and scanwrite_reg = '0') then if (now - scanread_active_edge >= scanclk_period) then for j in scan_chain_length - 1 downto 1 loop scan_data(j) <= scan_data(j-1); end loop; scan_data(0) <= scandata_ipd; else ASSERT FALSE REPORT "SCANREAD must go high at least one cycle before SCANDATA is read in." severity warning; end if; end if; scanclk_last_rising_edge := now; end if; end process; clk0_tmp <= c0_clk when i_clk0_counter = "c0" else c1_clk when i_clk0_counter = "c1" else c2_clk when i_clk0_counter = "c2" else c3_clk when i_clk0_counter = "c3" else c4_clk when i_clk0_counter = "c4" else c5_clk when i_clk0_counter = "c5" else '0'; clk(0) <= clk0_tmp when (areset_ipd = '1' or ena_ipd = '0') or (about_to_lock and (not reconfig_err)) else 'X'; clk1_tmp <= c0_clk when i_clk1_counter = "c0" else c1_clk when i_clk1_counter = "c1" else c2_clk when i_clk1_counter = "c2" else c3_clk when i_clk1_counter = "c3" else c4_clk when i_clk1_counter = "c4" else c5_clk when i_clk1_counter = "c5" else '0'; clk(1) <= clk1_tmp when (areset_ipd = '1' or ena_ipd = '0') or (about_to_lock and (not reconfig_err)) else 'X'; clk2_tmp <= c0_clk when i_clk2_counter = "c0" else c1_clk when i_clk2_counter = "c1" else c2_clk when i_clk2_counter = "c2" else c3_clk when i_clk2_counter = "c3" else c4_clk when i_clk2_counter = "c4" else c5_clk when i_clk2_counter = "c5" else '0'; clk(2) <= clk2_tmp when (areset_ipd = '1' or ena_ipd = '0') or (about_to_lock and (not reconfig_err)) else 'X'; clk3_tmp <= c0_clk when i_clk3_counter = "c0" else c1_clk when i_clk3_counter = "c1" else c2_clk when i_clk3_counter = "c2" else c3_clk when i_clk3_counter = "c3" else c4_clk when i_clk3_counter = "c4" else c5_clk when i_clk3_counter = "c5" else '0'; clk(3) <= clk3_tmp when (areset_ipd = '1' or ena_ipd = '0') or (about_to_lock and (not reconfig_err)) else 'X'; clk4_tmp <= c0_clk when i_clk4_counter = "c0" else c1_clk when i_clk4_counter = "c1" else c2_clk when i_clk4_counter = "c2" else c3_clk when i_clk4_counter = "c3" else c4_clk when i_clk4_counter = "c4" else c5_clk when i_clk4_counter = "c5" else '0'; clk(4) <= clk4_tmp when (areset_ipd = '1' or ena_ipd = '0') or (about_to_lock and (not reconfig_err)) else 'X'; clk5_tmp <= c0_clk when i_clk5_counter = "c0" else c1_clk when i_clk5_counter = "c1" else c2_clk when i_clk5_counter = "c2" else c3_clk when i_clk5_counter = "c3" else c4_clk when i_clk5_counter = "c4" else c5_clk when i_clk5_counter = "c5" else '0'; clk(5) <= clk5_tmp when (areset_ipd = '1' or ena_ipd = '0') or (about_to_lock and (not reconfig_err)) else 'X'; sclkout(0) <= sclkout0_tmp when (areset_ipd = '1' or ena_ipd = '0') or (about_to_lock and (not reconfig_err)) else 'X'; sclkout(1) <= sclkout1_tmp when (areset_ipd = '1' or ena_ipd = '0') or (about_to_lock and (not reconfig_err)) else 'X'; enable0 <= enable0_tmp when (areset_ipd = '1' or ena_ipd = '0') or (about_to_lock and (not reconfig_err)) else 'X'; enable1 <= enable1_tmp when (areset_ipd = '1' or ena_ipd = '0') or (about_to_lock and (not reconfig_err)) else 'X'; scandataout <= scandataout_tmp; scandone <= scandone_tmp; end vital_pll; -- END ARCHITECTURE VITAL_PLL -- START ENTITY HEADER --------------------------------------------------------- -- -- Entity Name : ALTPLL -- -- Description : Phase-Locked Loop (PLL) behavioral model. Model supports -- basic PLL features such as clock division and -- multiplication, programmable duty cycle and phase shifts, -- various feedback modes and clock delays. Also supports -- real-time reconfiguration of PLL "parameters" and clock -- switchover between the 2 input reference clocks. -- Up to 10 clock outputs may be used. -- -- Limitations : Applicable to Stratix, Stratix-GX and Stratix II device -- families only. There is no support in the model for -- spread-spectrum feature. -- -- Expected results : Up to 10 different output clocks, each defined by its own -- parameters. Locked output (active high) indicates when -- the PLL locks. clkbad, clkloss and activeclock highlights -- which clock has gone bad, when clock switchover initiates, -- and which input clock (0 or 1) is the reference clock, -- respectively. scandataout is the data output of the serial -- scan chain. -- -- END ENTITY HEADER ----------------------------------------------------------- library ieee, altera_mf; use ieee.std_logic_1164.all; use work.ALTERA_DEVICE_FAMILIES.all; use altera_mf.altera_mf_components.all; -- ENTITY DECLARATION entity altpll is generic ( intended_device_family : string := "Stratix" ; operation_mode : string := "NORMAL" ; pll_type : string := "AUTO" ; qualify_conf_done : string := "OFF" ; compensate_clock : string := "CLK0" ; scan_chain : string := "LONG"; primary_clock : string := "inclk0" ; inclk0_input_frequency : positive; -- required parameter inclk1_input_frequency : natural := 0; gate_lock_signal : string := "NO"; gate_lock_counter : integer := 0; lock_high : natural := 1; lock_low : natural := 5; valid_lock_multiplier : natural := 1; invalid_lock_multiplier : natural := 5; switch_over_type : string := "AUTO" ; switch_over_on_lossclk : string := "OFF" ; switch_over_on_gated_lock : string := "OFF" ; enable_switch_over_counter : string := "OFF"; switch_over_counter : natural := 0; feedback_source : string := "EXTCLK0" ; bandwidth : natural := 0; bandwidth_type : string := "UNUSED"; spread_frequency : natural := 0; down_spread : string := "0.0"; -- simulation-only parameters simulation_type : string := "functional"; source_is_pll : string := "off"; skip_vco : string := "off"; -- internal clock (i.e. clock that feeds the core) specifications clk5_multiply_by : positive := 1; clk4_multiply_by : positive := 1; clk3_multiply_by : positive := 1; clk2_multiply_by : positive := 1; clk1_multiply_by : positive := 1; clk0_multiply_by : positive := 1; clk5_divide_by : positive := 1; clk4_divide_by : positive := 1; clk3_divide_by : positive := 1; clk2_divide_by : positive := 1; clk1_divide_by : positive := 1; clk0_divide_by : positive := 1; clk5_phase_shift : string := "0"; clk4_phase_shift : string := "0"; clk3_phase_shift : string := "0"; clk2_phase_shift : string := "0"; clk1_phase_shift : string := "0"; clk0_phase_shift : string := "0"; clk5_time_delay : string := "0"; clk4_time_delay : string := "0"; clk3_time_delay : string := "0"; clk2_time_delay : string := "0"; clk1_time_delay : string := "0"; clk0_time_delay : string := "0"; clk5_duty_cycle : natural := 50; clk4_duty_cycle : natural := 50; clk3_duty_cycle : natural := 50; clk2_duty_cycle : natural := 50; clk1_duty_cycle : natural := 50; clk0_duty_cycle : natural := 50; -- external clock (i.e. clock that feeds pins) specifications extclk3_multiply_by : positive := 1; extclk2_multiply_by : positive := 1; extclk1_multiply_by : positive := 1; extclk0_multiply_by : positive := 1; extclk3_divide_by : positive := 1; extclk2_divide_by : positive := 1; extclk1_divide_by : positive := 1; extclk0_divide_by : positive := 1; extclk3_phase_shift : string := "0"; extclk2_phase_shift : string := "0"; extclk1_phase_shift : string := "0"; extclk0_phase_shift : string := "0"; extclk3_time_delay : string := "0"; extclk2_time_delay : string := "0"; extclk1_time_delay : string := "0"; extclk0_time_delay : string := "0"; extclk3_duty_cycle : natural := 50; extclk2_duty_cycle : natural := 50; extclk1_duty_cycle : natural := 50; extclk0_duty_cycle : natural := 50; -- The following 4 parameters are for Stratix II pll in lvds mode only vco_multiply_by : integer := 1; vco_divide_by : integer := 1; sclkout0_phase_shift : string := "0"; sclkout1_phase_shift : string := "0"; -- advanced user parameters vco_min : natural := 0; vco_max : natural := 0; vco_center : natural := 0; pfd_min : natural := 0; pfd_max : natural := 0; m_initial : natural := 1; m : natural := 0; -- m must default to 0 to force altpll to calculate the internal parameters for itself n : natural := 1; m2 : natural := 1; n2 : natural := 1; ss : natural := 0; c0_high : natural := 1; c1_high : natural := 1; c2_high : natural := 1; c3_high : natural := 1; c4_high : natural := 1; c5_high : natural := 1; l0_high : natural := 1; l1_high : natural := 1; g0_high : natural := 1; g1_high : natural := 1; g2_high : natural := 1; g3_high : natural := 1; e0_high : natural := 1; e1_high : natural := 1; e2_high : natural := 1; e3_high : natural := 1; c0_low : natural := 1; c1_low : natural := 1; c2_low : natural := 1; c3_low : natural := 1; c4_low : natural := 1; c5_low : natural := 1; l0_low : natural := 1; l1_low : natural := 1; g0_low : natural := 1; g1_low : natural := 1; g2_low : natural := 1; g3_low : natural := 1; e0_low : natural := 1; e1_low : natural := 1; e2_low : natural := 1; e3_low : natural := 1; c0_initial : natural := 1; c1_initial : natural := 1; c2_initial : natural := 1; c3_initial : natural := 1; c4_initial : natural := 1; c5_initial : natural := 1; l0_initial : natural := 1; l1_initial : natural := 1; g0_initial : natural := 1; g1_initial : natural := 1; g2_initial : natural := 1; g3_initial : natural := 1; e0_initial : natural := 1; e1_initial : natural := 1; e2_initial : natural := 1; e3_initial : natural := 1; c0_mode : string := "bypass" ; c1_mode : string := "bypass" ; c2_mode : string := "bypass" ; c3_mode : string := "bypass" ; c4_mode : string := "bypass" ; c5_mode : string := "bypass" ; l0_mode : string := "bypass" ; l1_mode : string := "bypass" ; g0_mode : string := "bypass" ; g1_mode : string := "bypass" ; g2_mode : string := "bypass" ; g3_mode : string := "bypass" ; e0_mode : string := "bypass" ; e1_mode : string := "bypass" ; e2_mode : string := "bypass" ; e3_mode : string := "bypass" ; c0_ph : natural := 0; c1_ph : natural := 0; c2_ph : natural := 0; c3_ph : natural := 0; c4_ph : natural := 0; c5_ph : natural := 0; l0_ph : natural := 0; l1_ph : natural := 0; g0_ph : natural := 0; g1_ph : natural := 0; g2_ph : natural := 0; g3_ph : natural := 0; e0_ph : natural := 0; e1_ph : natural := 0; e2_ph : natural := 0; e3_ph : natural := 0; m_ph : natural := 0; l0_time_delay : natural := 0; l1_time_delay : natural := 0; g0_time_delay : natural := 0; g1_time_delay : natural := 0; g2_time_delay : natural := 0; g3_time_delay : natural := 0; e0_time_delay : natural := 0; e1_time_delay : natural := 0; e2_time_delay : natural := 0; e3_time_delay : natural := 0; m_time_delay : natural := 0; n_time_delay : natural := 0; c1_use_casc_in : string := "off"; c2_use_casc_in : string := "off"; c3_use_casc_in : string := "off"; c4_use_casc_in : string := "off"; c5_use_casc_in : string := "off"; extclk3_counter : string := "e3" ; extclk2_counter : string := "e2" ; extclk1_counter : string := "e1" ; extclk0_counter : string := "e0" ; clk5_counter : string := "l1" ; clk4_counter : string := "l0" ; clk3_counter : string := "g3" ; clk2_counter : string := "g2" ; clk1_counter : string := "g1" ; clk0_counter : string := "g0" ; enable0_counter : string := "l0"; enable1_counter : string := "l0"; charge_pump_current : natural := 2; loop_filter_r : string := "1.0"; loop_filter_c : natural := 5; vco_post_scale : natural := 0; lpm_type : string := "altpll" ); port ( inclk : in std_logic_vector(1 downto 0) := (others => '0'); -- input clocks, up to 2 can be used fbin : in std_logic := '1'; -- external feedback port pllena : in std_logic := '1'; -- PLL enable signal clkswitch : in std_logic := '0'; -- switch between inclk0 and inclk1 areset : in std_logic := '0'; -- asynchronous reset pfdena : in std_logic := '1'; -- enable Phase Frequency Detector (PFD) clkena : in std_logic_vector(5 downto 0) := (others => '1'); -- enable clk0-clk5 outputs extclkena : in std_logic_vector(3 downto 0) := (others => '1'); -- enable extclk0-extclk3 outputs scanclk : in std_logic := '0'; -- clock for scan chain scanaclr : in std_logic := '0'; -- asynchronous clear for the scan chain scanread : in std_logic := '0'; -- determines when the scan chain can read in data from the scandata port scanwrite : in std_logic := '0'; -- determines when the scan chain can write out data into pll scandata : in std_logic := '0'; -- data for the scan chain comparator : in std_logic := '0'; -- control the enable0 pulse generation to achieve data realignment in lvds. clk : out std_logic_vector(5 downto 0); -- internal clock outputs (feeds the core) extclk : out std_logic_vector(3 downto 0); -- external clock outputs (feeds pins) clkbad : out std_logic_vector(1 downto 0); -- indicates if inclk0/inclk1 has gone bad enable0 : out std_logic; -- load enable pulse 0 for lvds enable1 : out std_logic; -- load enable pulse 1 for lvds activeclock : out std_logic; -- indicates which input clock is being used clkloss : out std_logic; -- indicates when clock switchover initiates locked : out std_logic; -- indicates when the PLL locks scandataout : out std_logic; -- data output from the scan chain scandone : out std_logic; -- indicates when pll reconfiguration is complete sclkout0 : out std_logic; -- serial clock output 0 for lvds sclkout1 : out std_logic -- serial clock output 1 for lvds ); end altpll; -- BEGINNING OF ARCHITECURE BEHAVIOR architecture behavior of altpll is -- converts uppercase parameter values (e.g. "AUTO") to lowercase ("auto") -- as expected by stratix_pll model function alpha_tolower (given_string : string) return string is -- VARIABLE DECLARATION variable string_length : integer := given_string'length; variable result_string : string(1 to 20) := " "; begin for i in 1 to string_length loop case given_string(i) is when 'A' => result_string(i) := 'a'; when 'B' => result_string(i) := 'b'; when 'C' => result_string(i) := 'c'; when 'D' => result_string(i) := 'd'; when 'E' => result_string(i) := 'e'; when 'F' => result_string(i) := 'f'; when 'G' => result_string(i) := 'g'; when 'H' => result_string(i) := 'h'; when 'I' => result_string(i) := 'i'; when 'J' => result_string(i) := 'j'; when 'K' => result_string(i) := 'k'; when 'L' => result_string(i) := 'l'; when 'M' => result_string(i) := 'm'; when 'N' => result_string(i) := 'n'; when 'O' => result_string(i) := 'o'; when 'P' => result_string(i) := 'p'; when 'Q' => result_string(i) := 'q'; when 'R' => result_string(i) := 'r'; when 'S' => result_string(i) := 's'; when 'T' => result_string(i) := 't'; when 'U' => result_string(i) := 'u'; when 'V' => result_string(i) := 'v'; when 'W' => result_string(i) := 'w'; when 'X' => result_string(i) := 'x'; when 'Y' => result_string(i) := 'y'; when 'Z' => result_string(i) := 'z'; when others => result_string(i) := given_string(i); end case; end loop; return (result_string(1 to string_length)); end; -- The following functions are used to set the default parameters' values for -- Stratix II if user do not specify these parameters' values. function get_clk0_counter (given_string : string) return string is -- VARIABLE DECLARATION variable string_length : integer := given_string'length; variable result_string : string(1 to 20) := " "; begin if (given_string = "g0") then return "c0"; else result_string(1 to string_length) := alpha_tolower(given_string); return (result_string(1 to string_length)); end if; end; -- get feedback source for stratixii function get_clk1_counter (given_string : string) return string is -- VARIABLE DECLARATION variable string_length : integer := given_string'length; variable result_string : string(1 to 20) := " "; begin if (given_string = "g1") then return "c1"; else result_string(1 to string_length) := alpha_tolower(given_string); return (result_string(1 to string_length)); end if; end; function get_clk2_counter (given_string : string) return string is -- VARIABLE DECLARATION variable string_length : integer := given_string'length; variable result_string : string(1 to 20) := " "; begin if (given_string = "g2") then return "c2"; else result_string(1 to string_length) := alpha_tolower(given_string); return (result_string(1 to string_length)); end if; end; function get_clk3_counter (given_string : string) return string is -- VARIABLE DECLARATION variable string_length : integer := given_string'length; variable result_string : string(1 to 20) := " "; begin if (given_string = "g3") then return "c3"; else result_string(1 to string_length) := alpha_tolower(given_string); return (result_string(1 to string_length)); end if; end; function get_clk4_counter (given_string : string) return string is -- VARIABLE DECLARATION variable string_length : integer := given_string'length; variable result_string : string(1 to 20) := " "; begin if (given_string = "l0") then return "c4"; else result_string(1 to string_length) := alpha_tolower(given_string); return (result_string(1 to string_length)); end if; end; function get_clk5_counter (given_string : string) return string is -- VARIABLE DECLARATION variable string_length : integer := given_string'length; variable result_string : string(1 to 20) := " "; begin if (given_string = "l1") then return "c5"; else result_string(1 to string_length) := alpha_tolower(given_string); return (result_string(1 to string_length)); end if; end; function get_enable0_counter (given_string : string) return string is -- VARIABLE DECLARATION variable string_length : integer := given_string'length; variable result_string : string(1 to 20) := " "; begin if (given_string = "l0") then return "c0"; else result_string(1 to string_length) := alpha_tolower(given_string); return (result_string(1 to string_length)); end if; end; function get_enable1_counter (given_string : string) return string is -- VARIABLE DECLARATION variable string_length : integer := given_string'length; variable result_string : string(1 to 20) := " "; begin if (given_string = "l0") then return "c1"; else result_string(1 to string_length) := alpha_tolower(given_string); return (result_string(1 to string_length)); end if; end; -- get feedback source for stratixii function get_feedback_source (given_string : string) return string is -- VARIABLE DECLARATION variable string_length : integer := given_string'length; variable result_string : string(1 to 20) := " "; begin if (given_string = "extclk0") then return "clk0"; else result_string(1 to string_length) := alpha_tolower(given_string); return (result_string(1 to string_length)); end if; end; -- COMPONENT DECLARATION component MF_stratix_pll generic ( operation_mode : string := "normal"; pll_type : string := "auto"; qualify_conf_done : string := "off"; compensate_clock : string := "clk0"; scan_chain : string := "long"; primary_clock : string := "inclk0"; inclk0_input_frequency : integer := 1000; inclk1_input_frequency : integer := 1000; gate_lock_signal : string := "no"; gate_lock_counter : integer := 0; valid_lock_multiplier : integer := 1; invalid_lock_multiplier : integer := 5; switch_over_on_lossclk : string := "off"; switch_over_on_gated_lock : string := "off"; enable_switch_over_counter : string := "off"; switch_over_counter : integer := 0; feedback_source : string := "extclk0"; bandwidth : integer := 0; bandwidth_type : string := "auto"; spread_frequency : integer := 0; down_spread : string := "0.0"; simulation_type : string := "functional"; skip_vco : string := "off"; clk0_multiply_by : integer := 1; clk0_divide_by : integer := 1; clk0_phase_shift : string := "0"; clk0_time_delay : string := "0"; clk0_duty_cycle : integer := 50; clk1_multiply_by : integer := 1; clk1_divide_by : integer := 1; clk1_phase_shift : string := "0"; clk1_time_delay : string := "0"; clk1_duty_cycle : integer := 50; clk2_multiply_by : integer := 1; clk2_divide_by : integer := 1; clk2_phase_shift : string := "0"; clk2_time_delay : string := "0"; clk2_duty_cycle : integer := 50; clk3_multiply_by : integer := 1; clk3_divide_by : integer := 1; clk3_phase_shift : string := "0"; clk3_time_delay : string := "0"; clk3_duty_cycle : integer := 50; clk4_multiply_by : integer := 1; clk4_divide_by : integer := 1; clk4_phase_shift : string := "0"; clk4_time_delay : string := "0"; clk4_duty_cycle : integer := 50; clk5_multiply_by : integer := 1; clk5_divide_by : integer := 1; clk5_phase_shift : string := "0"; clk5_time_delay : string := "0"; clk5_duty_cycle : integer := 50; extclk0_multiply_by : integer := 1; extclk0_divide_by : integer := 1; extclk0_phase_shift : string := "0"; extclk0_time_delay : string := "0"; extclk0_duty_cycle : integer := 50; extclk1_multiply_by : integer := 1; extclk1_divide_by : integer := 1; extclk1_phase_shift : string := "0"; extclk1_time_delay : string := "0"; extclk1_duty_cycle : integer := 50; extclk2_multiply_by : integer := 1; extclk2_divide_by : integer := 1; extclk2_phase_shift : string := "0"; extclk2_time_delay : string := "0"; extclk2_duty_cycle : integer := 50; extclk3_multiply_by : integer := 1; extclk3_divide_by : integer := 1; extclk3_phase_shift : string := "0"; extclk3_time_delay : string := "0"; extclk3_duty_cycle : integer := 50; vco_min : integer := 0; vco_max : integer := 0; vco_center : integer := 0; pfd_min : integer := 0; pfd_max : integer := 0; -- ADVANCED USER PARAMETERS m_initial : integer := 1; -- 1-1024 m : integer := 1; -- 1-1024 n : integer := 1; -- 1-1024 m2 : integer := 1; -- 1-1024 n2 : integer := 1; -- 1-1024 ss : integer := 0; l0_high : integer := 1; -- 1-512 l0_low : integer := 1; -- 1-512 l0_initial : integer := 1; -- 1-512 l0_mode : string := "bypass"; -- bypass,odd,even l0_ph : integer := 0; l0_time_delay : integer := 0; l1_high : integer := 1; l1_low : integer := 1; l1_initial : integer := 1; l1_mode : string := "bypass"; l1_ph : integer := 0; l1_time_delay : integer := 0; g0_high : integer := 1; g0_low : integer := 1; g0_initial : integer := 1; g0_mode : string := "bypass"; g0_ph : integer := 0; g0_time_delay : integer := 0; g1_high : integer := 1; g1_low : integer := 1; g1_initial : integer := 1; g1_mode : string := "bypass"; g1_ph : integer := 0; g1_time_delay : integer := 0; g2_high : integer := 1; g2_low : integer := 1; g2_initial : integer := 1; g2_mode : string := "bypass"; g2_ph : integer := 0; g2_time_delay : integer := 0; g3_high : integer := 1; g3_low : integer := 1; g3_initial : integer := 1; g3_mode : string := "bypass"; g3_ph : integer := 0; g3_time_delay : integer := 0; e0_high : integer := 1; e0_low : integer := 1; e0_initial : integer := 1; e0_mode : string := "bypass"; e0_ph : integer := 0; e0_time_delay : integer := 0; e1_high : integer := 1; e1_low : integer := 1; e1_initial : integer := 1; e1_mode : string := "bypass"; e1_ph : integer := 0; e1_time_delay : integer := 0; e2_high : integer := 1; e2_low : integer := 1; e2_initial : integer := 1; e2_mode : string := "bypass"; e2_ph : integer := 0; e2_time_delay : integer := 0; e3_high : integer := 1; e3_low : integer := 1; e3_initial : integer := 1; e3_mode : string := "bypass"; e3_ph : integer := 0; e3_time_delay : integer := 0; m_ph : integer := 0; m_time_delay : integer := 0; n_time_delay : integer := 0; extclk0_counter : string := "e0"; extclk1_counter : string := "e1"; extclk2_counter : string := "e2"; extclk3_counter : string := "e3"; clk0_counter : string := "g0"; clk1_counter : string := "g1"; clk2_counter : string := "g2"; clk3_counter : string := "g3"; clk4_counter : string := "l0"; clk5_counter : string := "l1"; enable0_counter : string := "l0"; enable1_counter : string := "l0"; charge_pump_current : integer := 2; loop_filter_r : string := "1.0"; loop_filter_c : natural := 5 ); port ( inclk : in std_logic_vector(1 downto 0) := (OTHERS=>'0'); fbin : in std_logic := '1'; ena : in std_logic := '1'; clkswitch : in std_logic := '0'; areset : in std_logic := '0'; pfdena : in std_logic := '1'; clkena : in std_logic_vector(5 downto 0) := (OTHERS=>'1'); extclkena : in std_logic_vector(3 downto 0) := (OTHERS=>'1'); scanclk : in std_logic := '0'; scanaclr : in std_logic := '0'; scandata : in std_logic := '0'; clk : out std_logic_vector(5 downto 0); extclk : out std_logic_vector(3 downto 0); clkbad : out std_logic_vector(1 downto 0); activeclock : out std_logic; clkloss : out std_logic; locked : out std_logic; scandataout : out std_logic; -- lvds specific ports comparator : in std_logic := '0'; enable0 : out std_logic; enable1 : out std_logic ); end component; component MF_stratixii_pll generic ( operation_mode : string := "normal"; pll_type : string := "auto"; qualify_conf_done : string := "off"; compensate_clock : string := "clk0"; inclk0_input_frequency : integer := 1000; inclk1_input_frequency : integer := 1000; gate_lock_signal : string := "no"; gate_lock_counter : integer := 0; valid_lock_multiplier : integer := 1; invalid_lock_multiplier : integer := 5; switch_over_type : string := "auto"; switch_over_on_lossclk : string := "off"; switch_over_on_gated_lock : string := "off"; enable_switch_over_counter : string := "off"; switch_over_counter : integer := 0; feedback_source : string := "extclk0"; bandwidth : integer := 0; bandwidth_type : string := "auto"; spread_frequency : integer := 0; down_spread : string := "0.0"; simulation_type : string := "functional"; clk0_multiply_by : integer := 1; clk0_divide_by : integer := 1; clk0_phase_shift : string := "0"; clk0_duty_cycle : integer := 50; clk1_multiply_by : integer := 1; clk1_divide_by : integer := 1; clk1_phase_shift : string := "0"; clk1_duty_cycle : integer := 50; clk2_multiply_by : integer := 1; clk2_divide_by : integer := 1; clk2_phase_shift : string := "0"; clk2_duty_cycle : integer := 50; clk3_multiply_by : integer := 1; clk3_divide_by : integer := 1; clk3_phase_shift : string := "0"; clk3_duty_cycle : integer := 50; clk4_multiply_by : integer := 1; clk4_divide_by : integer := 1; clk4_phase_shift : string := "0"; clk4_duty_cycle : integer := 50; clk5_multiply_by : integer := 1; clk5_divide_by : integer := 1; clk5_phase_shift : string := "0"; clk5_duty_cycle : integer := 50; vco_min : integer := 0; vco_max : integer := 0; vco_center : integer := 0; pfd_min : integer := 0; pfd_max : integer := 0; -- ADVANCED USER PARAMETERS m_initial : integer := 1; -- 1-1024 m : integer := 1; -- 1-1024 n : integer := 1; -- 1-1024 m2 : integer := 1; -- 1-1024 n2 : integer := 1; -- 1-1024 ss : integer := 0; c0_high : integer := 1; -- 1-512 c0_low : integer := 1; -- 1-512 c0_initial : integer := 1; -- 1-512 c0_mode : string := "bypass"; -- bypass,odd,even c0_ph : integer := 0; c1_high : integer := 1; c1_low : integer := 1; c1_initial : integer := 1; c1_mode : string := "bypass"; c1_ph : integer := 0; c2_high : integer := 1; c2_low : integer := 1; c2_initial : integer := 1; c2_mode : string := "bypass"; c2_ph : integer := 0; c3_high : integer := 1; c3_low : integer := 1; c3_initial : integer := 1; c3_mode : string := "bypass"; c3_ph : integer := 0; c4_high : integer := 1; c4_low : integer := 1; c4_initial : integer := 1; c4_mode : string := "bypass"; c4_ph : integer := 0; c5_high : integer := 1; c5_low : integer := 1; c5_initial : integer := 1; c5_mode : string := "bypass"; c5_ph : integer := 0; m_ph : integer := 0; c1_use_casc_in : string := "off"; c2_use_casc_in : string := "off"; c3_use_casc_in : string := "off"; c4_use_casc_in : string := "off"; c5_use_casc_in : string := "off"; clk0_counter : string := "c0"; clk1_counter : string := "c1"; clk2_counter : string := "c2"; clk3_counter : string := "c3"; clk4_counter : string := "c4"; clk5_counter : string := "c5"; enable0_counter : string := "c0"; enable1_counter : string := "c0"; sclkout0_phase_shift : string := "0"; sclkout1_phase_shift : string := "0"; vco_multiply_by : integer := 1; vco_divide_by : integer := 1; charge_pump_current : integer := 2; loop_filter_r : string := "1.0"; loop_filter_c : natural := 5 ); port ( inclk : in std_logic_vector(1 downto 0) := (OTHERS=>'0'); fbin : in std_logic := '1'; ena : in std_logic := '1'; clkswitch : in std_logic := '0'; areset : in std_logic := '0'; pfdena : in std_logic := '1'; scanclk : in std_logic := '1'; scanread : in std_logic := '1'; scanwrite : in std_logic := '1'; scandata : in std_logic := '1'; clk : out std_logic_vector(5 downto 0); clkbad : out std_logic_vector(1 downto 0); activeclock : out std_logic; clkloss : out std_logic; locked : out std_logic; scandataout : out std_logic; scandone : out std_logic; -- lvds specific ports enable0 : out std_logic; enable1 : out std_logic; sclkout : out std_logic_vector(1 downto 0) ); end component; signal locked_tmp : std_logic; begin -- checking for invalid parameters MSG: process begin if (clk5_multiply_by <= 0) then ASSERT FALSE REPORT "The clk5_multiply_by parameter must be greater than 0" SEVERITY ERROR; end if; if (clk4_multiply_by <= 0) then ASSERT FALSE REPORT "The clk4_multiply_by parameter must be greater than 0" SEVERITY ERROR; end if; if (clk3_multiply_by <= 0) then ASSERT FALSE REPORT "The clk3_multiply_by parameter must be greater than 0" SEVERITY ERROR; end if; if (clk2_multiply_by <= 0) then ASSERT FALSE REPORT "The clk2_multiply_by parameter must be greater than 0" SEVERITY ERROR; end if; if (clk1_multiply_by <= 0) then ASSERT FALSE REPORT "The clk1_multiply_by parameter must be greater than 0" SEVERITY ERROR; end if; if (clk0_multiply_by <= 0) then ASSERT FALSE REPORT "The clk0_multiply_by parameter must be greater than 0" SEVERITY ERROR; end if; if (clk5_divide_by <= 0) then ASSERT FALSE REPORT "The clk5_divide_by parameter must be greater than 0" SEVERITY ERROR; end if; if (clk4_divide_by <= 0) then ASSERT FALSE REPORT "The clk4_divide_by parameter must be greater than 0" SEVERITY ERROR; end if; if (clk3_divide_by <= 0) then ASSERT FALSE REPORT "The clk3_divide_by parameter must be greater than 0" SEVERITY ERROR; end if; if (clk2_divide_by <= 0) then ASSERT FALSE REPORT "The clk2_divide_by parameter must be greater than 0" SEVERITY ERROR; end if; if (clk1_divide_by <= 0) then ASSERT FALSE REPORT "The clk1_divide_by parameter must be greater than 0" SEVERITY ERROR; end if; if (clk0_divide_by <= 0) then ASSERT FALSE REPORT "The clk0_divide_by parameter must be greater than 0" SEVERITY ERROR; end if; if (extclk3_multiply_by <= 0) then ASSERT FALSE REPORT "The extclk3_multiply_by parameter must be greater than 0" SEVERITY ERROR; end if; if (extclk2_multiply_by <= 0) then ASSERT FALSE REPORT "The extclk2_multiply_by parameter must be greater than 0" SEVERITY ERROR; end if; if (extclk1_multiply_by <= 0) then ASSERT FALSE REPORT "The extclk1_multiply_by parameter must be greater than 0" SEVERITY ERROR; end if; if (extclk0_multiply_by <= 0) then ASSERT FALSE REPORT "The extclk0_multiply_by parameter must be greater than 0" SEVERITY ERROR; end if; if (extclk3_divide_by <= 0) then ASSERT FALSE REPORT "The extclk3_divide_by parameter must be greater than 0" SEVERITY ERROR; end if; if (extclk2_divide_by <= 0) then ASSERT FALSE REPORT "The extclk2_divide_by parameter must be greater than 0" SEVERITY ERROR; end if; if (extclk1_divide_by <= 0) then ASSERT FALSE REPORT "The extclk1_divide_by parameter must be greater than 0" SEVERITY ERROR; end if; if (extclk0_divide_by <= 0) then ASSERT FALSE REPORT "The extclk0_divide_by parameter must be greater than 0" SEVERITY ERROR; end if; if not ((primary_clock = "inclk0") or (primary_clock = "inclk1")) then ASSERT FALSE REPORT "The primary clock is set to an illegal value" SEVERITY ERROR; end if; wait; end process MSG; -- For fast mode, the stratix pll atom model will give active low signal on locked output. -- Therefore, need to invert the lock signal for fast mode as in user view, locked signal is -- always active high. locked <= (not locked_tmp) when ((IS_FAMILY_STRATIXII(intended_device_family) = false) and alpha_tolower(pll_type) = "fast") else locked_tmp; -- Instantiate stratix_pll STRATIX_ALTPLL: if (IS_FAMILY_STRATIXII(intended_device_family) = false) generate M0: MF_stratix_pll generic map( operation_mode => alpha_tolower(operation_mode), pll_type => alpha_tolower(pll_type), qualify_conf_done => alpha_tolower(qualify_conf_done), compensate_clock => alpha_tolower(compensate_clock), scan_chain => alpha_tolower(scan_chain), primary_clock => alpha_tolower(primary_clock), inclk0_input_frequency => inclk0_input_frequency, inclk1_input_frequency => inclk1_input_frequency, gate_lock_signal => alpha_tolower(gate_lock_signal), gate_lock_counter => gate_lock_counter, valid_lock_multiplier => valid_lock_multiplier, invalid_lock_multiplier => invalid_lock_multiplier, switch_over_on_lossclk => alpha_tolower(switch_over_on_lossclk), switch_over_on_gated_lock => alpha_tolower(switch_over_on_gated_lock), enable_switch_over_counter => alpha_tolower(enable_switch_over_counter), switch_over_counter => switch_over_counter, feedback_source => alpha_tolower(feedback_source), bandwidth => bandwidth, bandwidth_type => alpha_tolower(bandwidth_type), spread_frequency => spread_frequency, down_spread => down_spread, simulation_type => alpha_tolower(simulation_type), skip_vco => alpha_tolower(skip_vco), -- internal clock specifications clk5_multiply_by => clk5_multiply_by, clk4_multiply_by => clk4_multiply_by, clk3_multiply_by => clk3_multiply_by, clk2_multiply_by => clk2_multiply_by, clk1_multiply_by => clk1_multiply_by, clk0_multiply_by => clk0_multiply_by, clk5_divide_by => clk5_divide_by, clk4_divide_by => clk4_divide_by, clk3_divide_by => clk3_divide_by, clk2_divide_by => clk2_divide_by, clk1_divide_by => clk1_divide_by, clk0_divide_by => clk0_divide_by, clk5_phase_shift => clk5_phase_shift, clk4_phase_shift => clk4_phase_shift, clk3_phase_shift => clk3_phase_shift, clk2_phase_shift => clk2_phase_shift, clk1_phase_shift => clk1_phase_shift, clk0_phase_shift => clk0_phase_shift, clk5_time_delay => clk5_time_delay, clk4_time_delay => clk4_time_delay, clk3_time_delay => clk3_time_delay, clk2_time_delay => clk2_time_delay, clk1_time_delay => clk1_time_delay, clk0_time_delay => clk0_time_delay, clk5_duty_cycle => clk5_duty_cycle, clk4_duty_cycle => clk4_duty_cycle, clk3_duty_cycle => clk3_duty_cycle, clk2_duty_cycle => clk2_duty_cycle, clk1_duty_cycle => clk1_duty_cycle, clk0_duty_cycle => clk0_duty_cycle, -- external clock specifications extclk3_multiply_by => extclk3_multiply_by, extclk2_multiply_by => extclk2_multiply_by, extclk1_multiply_by => extclk1_multiply_by, extclk0_multiply_by => extclk0_multiply_by, extclk3_divide_by => extclk3_divide_by, extclk2_divide_by => extclk2_divide_by, extclk1_divide_by => extclk1_divide_by, extclk0_divide_by => extclk0_divide_by, extclk3_phase_shift => extclk3_phase_shift, extclk2_phase_shift => extclk2_phase_shift, extclk1_phase_shift => extclk1_phase_shift, extclk0_phase_shift => extclk0_phase_shift, extclk3_time_delay => extclk3_time_delay, extclk2_time_delay => extclk2_time_delay, extclk1_time_delay => extclk1_time_delay, extclk0_time_delay => extclk0_time_delay, extclk3_duty_cycle => extclk3_duty_cycle, extclk2_duty_cycle => extclk2_duty_cycle, extclk1_duty_cycle => extclk1_duty_cycle, extclk0_duty_cycle => extclk0_duty_cycle, -- advanced user parameters vco_min => vco_min, vco_max => vco_max, vco_center => vco_center, pfd_min => pfd_min, pfd_max => pfd_max, m_initial => m_initial, m => m, n => n, m2 => m2, n2 => n2, ss => ss, l0_high => l0_high, l1_high => l1_high, g0_high => g0_high, g1_high => g1_high, g2_high => g2_high, g3_high => g3_high, e0_high => e0_high, e1_high => e1_high, e2_high => e2_high, e3_high => e3_high, l0_low => l0_low, l1_low => l1_low, g0_low => g0_low, g1_low => g1_low, g2_low => g2_low, g3_low => g3_low, e0_low => e0_low, e1_low => e1_low, e2_low => e2_low, e3_low => e3_low, l0_initial => l0_initial, l1_initial => l1_initial, g0_initial => g0_initial, g1_initial => g1_initial, g2_initial => g2_initial, g3_initial => g3_initial, e0_initial => e0_initial, e1_initial => e1_initial, e2_initial => e2_initial, e3_initial => e3_initial, l0_mode => alpha_tolower(l0_mode), l1_mode => alpha_tolower(l1_mode), g0_mode => alpha_tolower(g0_mode), g1_mode => alpha_tolower(g1_mode), g2_mode => alpha_tolower(g2_mode), g3_mode => alpha_tolower(g3_mode), e0_mode => alpha_tolower(e0_mode), e1_mode => alpha_tolower(e1_mode), e2_mode => alpha_tolower(e2_mode), e3_mode => alpha_tolower(e3_mode), l0_ph => l0_ph, l1_ph => l1_ph, g0_ph => g0_ph, g1_ph => g1_ph, g2_ph => g2_ph, g3_ph => g3_ph, e0_ph => e0_ph, e1_ph => e1_ph, e2_ph => e2_ph, e3_ph => e3_ph, m_ph => m_ph, l0_time_delay => l0_time_delay, l1_time_delay => l1_time_delay, g0_time_delay => g0_time_delay, g1_time_delay => g1_time_delay, g2_time_delay => g2_time_delay, g3_time_delay => g3_time_delay, e0_time_delay => e0_time_delay, e1_time_delay => e1_time_delay, e2_time_delay => e2_time_delay, e3_time_delay => e3_time_delay, m_time_delay => m_time_delay, n_time_delay => n_time_delay, extclk3_counter => alpha_tolower(extclk3_counter), extclk2_counter => alpha_tolower(extclk2_counter), extclk1_counter => alpha_tolower(extclk1_counter), extclk0_counter => alpha_tolower(extclk0_counter), clk5_counter => alpha_tolower(clk5_counter), clk4_counter => alpha_tolower(clk4_counter), clk3_counter => alpha_tolower(clk3_counter), clk2_counter => alpha_tolower(clk2_counter), clk1_counter => alpha_tolower(clk1_counter), clk0_counter => alpha_tolower(clk0_counter), enable0_counter => alpha_tolower(enable0_counter), enable1_counter => alpha_tolower(enable1_counter), charge_pump_current => charge_pump_current, loop_filter_r => loop_filter_r, loop_filter_c => loop_filter_c ) port map ( inclk => inclk, fbin => fbin, ena => pllena, clkswitch => clkswitch, areset => areset, pfdena => pfdena, clkena => clkena, extclkena => extclkena, scanclk => scanclk, scanaclr => scanaclr, scandata => scandata, comparator => comparator, clk => clk, extclk => extclk, clkbad => clkbad, enable0 => enable0, enable1 => enable1, activeclock => activeclock, clkloss => clkloss, locked => locked_tmp, scandataout => scandataout ); end generate STRATIX_ALTPLL; -- Instantiate stratixii_pll STRATIXII_ALTPLL: if (IS_FAMILY_STRATIXII(intended_device_family) = true) generate M1 : MF_stratixii_pll generic map( operation_mode => alpha_tolower(operation_mode), pll_type => alpha_tolower(pll_type), qualify_conf_done => alpha_tolower(qualify_conf_done), compensate_clock => alpha_tolower(compensate_clock), inclk0_input_frequency => inclk0_input_frequency, inclk1_input_frequency => inclk1_input_frequency, gate_lock_signal => alpha_tolower(gate_lock_signal), gate_lock_counter => gate_lock_counter, valid_lock_multiplier => valid_lock_multiplier, invalid_lock_multiplier => invalid_lock_multiplier, switch_over_type => alpha_tolower(switch_over_type), switch_over_on_lossclk => alpha_tolower(switch_over_on_lossclk), switch_over_on_gated_lock => alpha_tolower(switch_over_on_gated_lock), enable_switch_over_counter => alpha_tolower(enable_switch_over_counter), switch_over_counter => switch_over_counter, feedback_source => get_feedback_source(feedback_source), bandwidth => bandwidth, bandwidth_type => alpha_tolower(bandwidth_type), spread_frequency => spread_frequency, down_spread => down_spread, simulation_type => alpha_tolower(simulation_type), -- internal clock specifications clk5_multiply_by => clk5_multiply_by, clk4_multiply_by => clk4_multiply_by, clk3_multiply_by => clk3_multiply_by, clk2_multiply_by => clk2_multiply_by, clk1_multiply_by => clk1_multiply_by, clk0_multiply_by => clk0_multiply_by, clk5_divide_by => clk5_divide_by, clk4_divide_by => clk4_divide_by, clk3_divide_by => clk3_divide_by, clk2_divide_by => clk2_divide_by, clk1_divide_by => clk1_divide_by, clk0_divide_by => clk0_divide_by, clk5_phase_shift => clk5_phase_shift, clk4_phase_shift => clk4_phase_shift, clk3_phase_shift => clk3_phase_shift, clk2_phase_shift => clk2_phase_shift, clk1_phase_shift => clk1_phase_shift, clk0_phase_shift => clk0_phase_shift, clk5_duty_cycle => clk5_duty_cycle, clk4_duty_cycle => clk4_duty_cycle, clk3_duty_cycle => clk3_duty_cycle, clk2_duty_cycle => clk2_duty_cycle, clk1_duty_cycle => clk1_duty_cycle, clk0_duty_cycle => clk0_duty_cycle, -- advanced user parameters vco_min => vco_min, vco_max => vco_max, vco_center => vco_center, pfd_min => pfd_min, pfd_max => pfd_max, m_initial => m_initial, m => m, n => n, m2 => m2, n2 => n2, ss => ss, c0_high => c0_high, c1_high => c1_high, c2_high => c2_high, c3_high => c3_high, c4_high => c4_high, c5_high => c5_high, c0_low => c0_low, c1_low => c1_low, c2_low => c2_low, c3_low => c3_low, c4_low => c4_low, c5_low => c5_low, c0_initial => c0_initial, c1_initial => c1_initial, c2_initial => c2_initial, c3_initial => c3_initial, c4_initial => c4_initial, c5_initial => c5_initial, c0_mode => alpha_tolower(c0_mode), c1_mode => alpha_tolower(c1_mode), c2_mode => alpha_tolower(c2_mode), c3_mode => alpha_tolower(c3_mode), c4_mode => alpha_tolower(c4_mode), c5_mode => alpha_tolower(c5_mode), c0_ph => c0_ph, c1_ph => c1_ph, c2_ph => c2_ph, c3_ph => c3_ph, c4_ph => c4_ph, c5_ph => c5_ph, m_ph => m_ph, c1_use_casc_in => c1_use_casc_in, c2_use_casc_in => c2_use_casc_in, c3_use_casc_in => c3_use_casc_in, c4_use_casc_in => c4_use_casc_in, c5_use_casc_in => c5_use_casc_in, clk5_counter => get_clk5_counter(clk5_counter), clk4_counter => get_clk4_counter(clk4_counter), clk3_counter => get_clk3_counter(clk3_counter), clk2_counter => get_clk2_counter(clk2_counter), clk1_counter => get_clk1_counter(clk1_counter), clk0_counter => get_clk0_counter(clk0_counter), enable0_counter => get_enable0_counter(enable0_counter), enable1_counter => get_enable1_counter(enable1_counter), sclkout0_phase_shift => sclkout0_phase_shift, sclkout1_phase_shift => sclkout1_phase_shift, vco_multiply_by => vco_multiply_by, vco_divide_by => vco_divide_by, charge_pump_current => charge_pump_current, loop_filter_r => loop_filter_r, loop_filter_c => loop_filter_c ) port map ( inclk => inclk, fbin => fbin, ena => pllena, clkswitch => clkswitch, areset => areset, pfdena => pfdena, scanclk => scanclk, scanread => scanread, scanwrite => scanwrite, scandata => scandata, clk => clk, clkbad => clkbad, enable0 => enable0, enable1 => enable1, activeclock => activeclock, clkloss => clkloss, locked => locked_tmp, scandataout => scandataout, scandone => scandone, sclkout(0) => sclkout0, sclkout(1) => sclkout1 ); end generate STRATIXII_ALTPLL; end behavior; -- END ARCHITECTURE BEHAVIOR -- START ENTITY HEADER --------------------------------------------------------- -- -- Entity Name : HSSI_PLL -- -- Description : This is the Phase Locked Loop (PLL) model used by altcdr_rx -- and altcdr_tx. Simple PLL model with 1 clock input (clk) -- and 2 clock outputs (clk0 & clk1). -- -- Limitations : Only capable of multiplying and dividing the input clock -- frequency. There is no support for phase shifts, uneven duty -- cycles or other fancy PLL features, since the Mercury CDR -- does not need these features. -- -- Expected results : 2 output clocks - clk0 and clk1. Locked output indicates -- when the PLL locks. -- -- END ENTITY HEADER ----------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.all; -- ENTITY DECLARATION entity hssi_pll is generic ( clk0_multiply_by : integer := 1; clk1_divide_by : integer := 1; input_frequency : integer := 1000 -- period in ps ); port ( clk : in std_logic; -- required port, input clock areset : in std_logic := '0'; -- asynchronous reset clk0 : out std_logic; -- output clock0 clk1 : out std_logic; -- output clock1 locked : out std_logic -- PLL lock signal ); end hssi_pll; -- BEGINNING OF ARCHITECTURE BEHAVIOR architecture behavior of hssi_pll is -- SIGNAL DECLARATION SIGNAL clk0_tmp : std_logic := 'X'; SIGNAL clk1_tmp : std_logic := 'X'; SIGNAL clk0_period : time := 0 ps; SIGNAL clk1_period : time := 0 ps; SIGNAL half_inclk : time := 0 ps; SIGNAL pll_lock : std_logic := '0'; SIGNAL clk_check : std_logic := '0'; SIGNAL lock_on_rise : integer := 0; SIGNAL lock_on_fall : integer := 0; begin -- monitor the input clock to determine when the pll locks -- or when it loses lock due to input frequency or duty cycle violation -- also performs the reset logic and the generation of 2 output clocks process (clk, pll_lock, clk_check, areset) -- VARIABLE DECLARATION variable start_lock_count : integer := 0; variable stop_lock_count : integer := 0; variable pll_rising_edge_count : integer := 0; variable lock_low : integer := 2; variable lock_high : integer := 2; variable inclk_ps : time := 0 ps; variable pll_last_rising_edge : time := 0 ps; variable pll_last_falling_edge : time := 0 ps; variable pll_cycle : time := 0 ps; variable pll_duty_cycle : time := 0 ps; variable clk_per_tolerance : time := 0 ps; variable expected_next_clk_edge : time := 0 ps; variable violation : boolean := false; variable pll_lock_tmp : std_logic := '0'; variable last_synchronizing_rising_edge_for_clk0 : time := 0 ps; variable last_synchronizing_rising_edge_for_clk1 : time := 0 ps; variable clk0_synchronizing_period : time := 0 ps; variable clk1_synchronizing_period : time := 0 ps; variable input_cycles_per_clk0 : integer := 0; variable input_cycles_per_clk1 : integer := 0; variable input_cycle_count_to_sync0 : integer := 0; variable input_cycle_count_to_sync1 : integer := 0; variable clk0_cycles_per_sync_period : integer := clk0_multiply_by; variable clk1_cycles_per_sync_period : integer := 1; variable vco_per : time := 0 ps; variable high_time : time := 0 ps; variable low_time : time := 0 ps; variable sched_time : time := 0 ps; variable tmp_per : integer := 0; variable temp : integer := 0; variable tmp_rem : integer := 0; variable my_rem : integer := 0; variable l : integer := 1; variable cycle_to_adjust : integer := 0; variable schedule_clk0 : boolean := false; variable schedule_clk1 : boolean := false; variable init : boolean := true; variable output_value : std_logic := '0'; begin -- initialize variables if (init) then clk0_cycles_per_sync_period := clk0_multiply_by; clk1_cycles_per_sync_period := clk0_multiply_by; input_cycles_per_clk0 := 1; input_cycles_per_clk1 := clk1_divide_by; init := false; end if; -- reset logic if (areset = '1') then pll_rising_edge_count := 0; violation := false; pll_lock_tmp := '0'; pll_lock <= '0'; start_lock_count := 1; stop_lock_count := 0; clk0_tmp <= 'X'; clk1_tmp <= 'X'; else -- calculate the required periods if (pll_rising_edge_count = 0) then inclk_ps := (input_frequency / 1 ) * 1 ps; half_inclk <= inclk_ps/2; clk_per_tolerance := 0.025 * inclk_ps; -- allow input clock period to deviate by 2.5% clk0_period <= inclk_ps / clk0_multiply_by; clk1_period <= (inclk_ps / clk0_multiply_by) * clk1_divide_by; pll_duty_cycle := inclk_ps/2; end if; -- rising edge of input clock if (clk'event and (clk = '1')) then if (pll_lock_tmp = '1') then clk_check <= not clk_check after (inclk_ps+clk_per_tolerance)/2.0; end if; if (pll_rising_edge_count = 0) then pll_last_rising_edge := NOW; -- at 2nd rising edge elsif (pll_rising_edge_count = 1) then pll_cycle := now - pll_last_rising_edge; -- calculate period -- input clock period violation check if ((NOW - pll_last_rising_edge) < (inclk_ps - clk_per_tolerance) or (NOW - pll_last_rising_edge) > (inclk_ps + clk_per_tolerance)) then ASSERT FALSE REPORT " Inclock Period Violation " SEVERITY WARNING; violation := true; if (pll_lock = '1') then stop_lock_count := stop_lock_count + 1; if (stop_lock_count = lock_low) then pll_lock_tmp := '0'; end if; else start_lock_count := 1; end if; else violation := false; end if; -- duty cycle violation check if ((now - pll_last_falling_edge) < (pll_duty_cycle - clk_per_tolerance/2) or (now - pll_last_falling_edge) > (pll_duty_cycle + clk_per_tolerance/2)) then ASSERT FALSE REPORT "Duty Cycle Violation" SEVERITY WARNING; violation := true; else violation := false; end if; else -- not 2nd rising edge pll_cycle := now - pll_last_rising_edge; -- calculate period if ((now - pll_last_rising_edge) < (inclk_ps - clk_per_tolerance) or (now - pll_last_rising_edge) > (inclk_ps + clk_per_tolerance)) then ASSERT FALSE REPORT "Cycle Violation" SEVERITY WARNING; violation := true; if (pll_lock = '1') then stop_lock_count := stop_lock_count + 1; if (stop_lock_count = lock_low) then pll_lock_tmp := '0'; end if; else start_lock_count := 1; end if; else violation := false; end if; end if; pll_last_rising_edge := now; pll_rising_edge_count := pll_rising_edge_count +1; -- if there is no input clock violation detected, schedule clk0 and clk1 events if (not violation) then if (pll_lock_tmp = '1') then input_cycle_count_to_sync0 := input_cycle_count_to_sync0 + 1; if (input_cycle_count_to_sync0 = input_cycles_per_clk0) then clk0_synchronizing_period := now - last_synchronizing_rising_edge_for_clk0; last_synchronizing_rising_edge_for_clk0 := now; schedule_clk0 := true; input_cycle_count_to_sync0 := 0; end if; input_cycle_count_to_sync1 := input_cycle_count_to_sync1 + 1; if (input_cycle_count_to_sync1 = input_cycles_per_clk1) then clk1_synchronizing_period := now - last_synchronizing_rising_edge_for_clk1; last_synchronizing_rising_edge_for_clk1 := now; schedule_clk1 := true; input_cycle_count_to_sync1 := 0; end if; else start_lock_count := start_lock_count + 1; if (start_lock_count >= lock_high) then pll_lock_tmp := '1'; lock_on_rise <= 1; input_cycle_count_to_sync0 := 0; input_cycle_count_to_sync1 := 0; if (last_synchronizing_rising_edge_for_clk0 = 0 ps) then clk0_synchronizing_period := pll_cycle; else clk0_synchronizing_period := now - last_synchronizing_rising_edge_for_clk0; end if; if (last_synchronizing_rising_edge_for_clk1 = 0 ps) then clk1_synchronizing_period := ((pll_cycle/1 ps) * clk1_divide_by) * 1 ps; else clk1_synchronizing_period := now - last_synchronizing_rising_edge_for_clk1; end if; last_synchronizing_rising_edge_for_clk0 := now; last_synchronizing_rising_edge_for_clk1 := now; schedule_clk0 := true; schedule_clk1 := true; end if; end if; else start_lock_count := 0; end if; -- falling edge of input clock elsif (clk'event and (clk = '0')) then if (pll_lock_tmp = '1') then clk_check <= not clk_check after (inclk_ps+clk_per_tolerance)/2.0; -- check for duty cycle violation if (now > 0 ns and ((now - pll_last_rising_edge) < (pll_duty_cycle - clk_per_tolerance/2) or (now - pll_last_rising_edge) > (pll_duty_cycle + clk_per_tolerance/2))) then ASSERT FALSE REPORT "Duty Cycle Violation" SEVERITY WARNING; violation := true; if (pll_lock = '1') then stop_lock_count := stop_lock_count + 1; if (stop_lock_count = lock_low) then pll_lock_tmp := '0'; end if; end if; else violation := false; end if; elsif (pll_rising_edge_count > 0) then start_lock_count := start_lock_count + 1; end if; pll_last_falling_edge := now; else -- not rising edge or falling edge of input clock, perform clock check if (pll_lock_tmp = '1') then if (clk = '1') then expected_next_clk_edge := pll_last_rising_edge + (inclk_ps+clk_per_tolerance)/2.0; else expected_next_clk_edge := pll_last_falling_edge + (inclk_ps+clk_per_tolerance)/2.0; end if; violation := false; if (now < expected_next_clk_edge) then clk_check <= not clk_check after (expected_next_clk_edge - now); elsif (now = expected_next_clk_edge) then clk_check <= not clk_check after (inclk_ps+clk_per_tolerance)/2.0; else ASSERT FALSE REPORT "Inclock Period Violation" SEVERITY WARNING; violation := true; if (pll_lock = '1') then stop_lock_count := stop_lock_count + 1; if (stop_lock_count = lock_low) then pll_lock_tmp := '0'; else clk_check <= not clk_check after (inclk_ps/2.0); end if; end if; end if; end if; end if; pll_lock <= pll_lock_tmp; -- on lost of pll lock, reset variables if (pll_lock'event and (pll_lock = '0')) then start_lock_count := 1; stop_lock_count := 0; lock_on_rise <= 0; lock_on_fall <= 0; clk0_tmp <= 'X'; clk1_tmp <= 'X'; end if; end if; -- if not areset -- schedule clk0 output if (schedule_clk0) then sched_time := 0 ps; cycle_to_adjust := 0; l := 1; output_value := '1'; temp := clk0_synchronizing_period/1 ps; my_rem := temp rem clk0_cycles_per_sync_period; for i in 1 to clk0_cycles_per_sync_period loop tmp_per := temp/clk0_cycles_per_sync_period; if (my_rem /= 0 and l <= my_rem) then tmp_rem := (clk0_cycles_per_sync_period * l) rem my_rem; cycle_to_adjust := (clk0_cycles_per_sync_period * l) / my_rem; if (tmp_rem /= 0) then cycle_to_adjust := cycle_to_adjust + 1; end if; end if; if (cycle_to_adjust = i) then tmp_per := tmp_per + 1; l := l + 1; end if; vco_per := tmp_per * 1 ps; high_time := (tmp_per/2) * 1 ps; if (tmp_per rem 2 /= 0) then high_time := high_time + 1 ps; end if; low_time := vco_per - high_time; for j in 1 to 2 loop clk0_tmp <= transport output_value after sched_time; output_value := not output_value; if (output_value = '0') then sched_time := sched_time + high_time; elsif (output_value = '1') then sched_time := sched_time + low_time; end if; end loop; end loop; schedule_clk0 := false; end if; -- schedule clk1 output if (schedule_clk1) then sched_time := 0 ps; cycle_to_adjust := 0; l := 1; output_value := '1'; temp := clk1_synchronizing_period/1 ps; my_rem := temp rem clk1_cycles_per_sync_period; for i in 1 to clk1_cycles_per_sync_period loop tmp_per := temp/clk1_cycles_per_sync_period; if (my_rem /= 0 and l <= my_rem) then tmp_rem := (clk1_cycles_per_sync_period * l) rem my_rem; cycle_to_adjust := (clk1_cycles_per_sync_period * l) / my_rem; if (tmp_rem /= 0) then cycle_to_adjust := cycle_to_adjust + 1; end if; end if; if (cycle_to_adjust = i) then tmp_per := tmp_per + 1; l := l + 1; end if; vco_per := tmp_per * 1 ps; high_time := (tmp_per/2) * 1 ps; if (tmp_per rem 2 /= 0) then high_time := high_time + 1 ps; end if; low_time := vco_per - high_time; for j in 1 to 2 loop clk1_tmp <= transport output_value after sched_time; output_value := not output_value; if (output_value = '0') then sched_time := sched_time + high_time; elsif (output_value = '1') then sched_time := sched_time + low_time; end if; end loop; end loop; schedule_clk1 := false; end if; end process; -- assign signals to output ports clk0 <= clk0_tmp; clk1 <= clk1_tmp; locked <= pll_lock; end behavior; -- END ARCHITECTURE BEHAVIOR -- START ENTITY HEADER --------------------------------------------------------- -- -- Entity Name : MF_RAM7X20_SYN -- -- Description : This is the RAM model used by HSSI_FIFO for writing and reading -- into the FIFO -- -- Limitations : Reading from the RAM is address-triggered, -- writing is clock-triggered -- RAM depth is fixed to 7, maximum width is 20 -- -- Expected results : data output from the RAM -- -- END ENTITY HEADER ----------------------------------------------------------- library IEEE; use IEEE.std_logic_1164.all; -- ENTITY DECLARATION entity MF_ram7x20_syn is generic ( ram_width : integer := 20 ); port ( wclk : in std_logic; -- the write clock rst_l : in std_logic := '1'; -- active low, asynchronous reset addr_wr : in std_logic_vector(2 downto 0); -- write address addr_rd : in std_logic_vector(2 downto 0); -- read address datain : in std_logic_vector(ram_width-1 downto 0); -- data input to the RAM we : in std_logic := '0'; -- write enable re : in std_logic := '0'; -- read enable data_out : out std_logic_vector(ram_width-1 downto 0) -- data output of the RAM ); end MF_ram7x20_syn; -- BEGINNING OF ARCHITECTURE HSSI_RAM7X20_SYN architecture hssi_ram7x20_syn of MF_ram7x20_syn is -- SIGNAL DECLARATION signal ram_array_d_0 : std_logic_vector(ram_width-1 downto 0) := (OTHERS => '0'); signal ram_array_d_1 : std_logic_vector(ram_width-1 downto 0) := (OTHERS => '0'); signal ram_array_d_2 : std_logic_vector(ram_width-1 downto 0) := (OTHERS => '0'); signal ram_array_d_3 : std_logic_vector(ram_width-1 downto 0) := (OTHERS => '0'); signal ram_array_d_4 : std_logic_vector(ram_width-1 downto 0) := (OTHERS => '0'); signal ram_array_d_5 : std_logic_vector(ram_width-1 downto 0) := (OTHERS => '0'); signal ram_array_d_6 : std_logic_vector(ram_width-1 downto 0) := (OTHERS => '0'); signal ram_array_q_0 : std_logic_vector(ram_width-1 downto 0) := (OTHERS => '0'); signal ram_array_q_1 : std_logic_vector(ram_width-1 downto 0) := (OTHERS => '0'); signal ram_array_q_2 : std_logic_vector(ram_width-1 downto 0) := (OTHERS => '0'); signal ram_array_q_3 : std_logic_vector(ram_width-1 downto 0) := (OTHERS => '0'); signal ram_array_q_4 : std_logic_vector(ram_width-1 downto 0) := (OTHERS => '0'); signal ram_array_q_5 : std_logic_vector(ram_width-1 downto 0) := (OTHERS => '0'); signal ram_array_q_6 : std_logic_vector(ram_width-1 downto 0) := (OTHERS => '0'); signal data_reg_0 : std_logic_vector(ram_width-1 downto 0) := (OTHERS => '0'); signal data_reg_1 : std_logic_vector(ram_width-1 downto 0) := (OTHERS => '0'); signal data_reg_2 : std_logic_vector(ram_width-1 downto 0) := (OTHERS => '0'); signal data_reg_3 : std_logic_vector(ram_width-1 downto 0) := (OTHERS => '0'); signal data_reg_4 : std_logic_vector(ram_width-1 downto 0) := (OTHERS => '0'); signal data_reg_5 : std_logic_vector(ram_width-1 downto 0) := (OTHERS => '0'); signal data_reg_6 : std_logic_vector(ram_width-1 downto 0) := (OTHERS => '0'); signal data_out_i : std_logic_vector(ram_width-1 downto 0) := (OTHERS => '0'); begin -- assignment data_reg_0 <= datain when addr_wr = "000" else ram_array_q_0; data_reg_1 <= datain when addr_wr = "001" else ram_array_q_1; data_reg_2 <= datain when addr_wr = "010" else ram_array_q_2; data_reg_3 <= datain when addr_wr = "011" else ram_array_q_3; data_reg_4 <= datain when addr_wr = "100" else ram_array_q_4; data_reg_5 <= datain when addr_wr = "101" else ram_array_q_5; data_reg_6 <= datain when addr_wr = "110" else ram_array_q_6; data_out <= data_out_i when re = '1' else (OTHERS => '0'); -- PROCESS DECLARATION process (wclk, rst_l, addr_wr, addr_rd, datain, ram_array_q_0, ram_array_q_1, ram_array_q_2, ram_array_q_3, ram_array_q_4, ram_array_q_5, ram_array_q_6, data_reg_0, data_reg_1, data_reg_2, data_reg_3, data_reg_4, data_reg_5, data_reg_6) -- VARIABLE DECLARATION variable dataout_tmp : std_logic_vector(ram_width-1 downto 0); begin -- Modelling the read port -- Assuming address triggered operation only case addr_rd is when "000" => data_out_i <= ram_array_q_0; when "001" => data_out_i <= ram_array_q_1; when "010" => data_out_i <= ram_array_q_2; when "011" => data_out_i <= ram_array_q_3; when "100" => data_out_i <= ram_array_q_4; when "101" => data_out_i <= ram_array_q_5; when "110" => data_out_i <= ram_array_q_6; when others => data_out_i <= data_out_i; end case; if (re = '1') then dataout_tmp := data_out_i; else dataout_tmp := (OTHERS => '0'); end if; -- reset if (rst_l = '0') then ram_array_q_0 <= (OTHERS => '0'); ram_array_q_1 <= (OTHERS => '0'); ram_array_q_2 <= (OTHERS => '0'); ram_array_q_3 <= (OTHERS => '0'); ram_array_q_4 <= (OTHERS => '0'); ram_array_q_5 <= (OTHERS => '0'); ram_array_q_6 <= (OTHERS => '0'); else -- Modelling the write port if (wclk'event and wclk = '1') then ram_array_q_0 <= ram_array_d_0; ram_array_q_1 <= ram_array_d_1; ram_array_q_2 <= ram_array_d_2; ram_array_q_3 <= ram_array_d_3; ram_array_q_4 <= ram_array_d_4; ram_array_q_5 <= ram_array_d_5; ram_array_q_6 <= ram_array_d_6; end if; if (we = '1') then -- write enabled ram_array_d_0 <= data_reg_0; ram_array_d_1 <= data_reg_1; ram_array_d_2 <= data_reg_2; ram_array_d_3 <= data_reg_3; ram_array_d_4 <= data_reg_4; ram_array_d_5 <= data_reg_5; ram_array_d_6 <= data_reg_6; else ram_array_d_0 <= ram_array_q_0; ram_array_d_1 <= ram_array_q_1; ram_array_d_2 <= ram_array_q_2; ram_array_d_3 <= ram_array_q_3; ram_array_d_4 <= ram_array_q_4; ram_array_d_5 <= ram_array_q_5; ram_array_d_6 <= ram_array_q_6; end if; end if; end process; end hssi_ram7x20_syn; -- END ARCHITECTURE HSSI_RAM7X20_SYN -- START ENTITY HEADER --------------------------------------------------------- -- -- Entity Name : HSSI_FIFO -- -- Description : The FIFO model used by altcdr_rx and altcdr_tx to synchronize -- data between 2 clock domains -- -- Limitations : FIFO depth is limited to 7 words only, -- the overflow and empty signals are active low in this model -- -- Expected results : data read from the FIFO, empty and overflow signals -- (active low) to indicate when FIFO is empty or full -- -- END ENTITY HEADER ----------------------------------------------------------- library IEEE; use IEEE.std_logic_1164.all; -- ENTITY DECLARATION entity hssi_fifo is generic ( channel_width : integer := 1 ); port ( datain : in std_logic_vector(channel_width-1 downto 0); -- data input to the FIFO clk0 : in std_logic; -- FIFO write clock clk1 : in std_logic; -- FIFO read clock we : in std_logic := '1'; -- write enable re : in std_logic := '1'; -- read enable reset : in std_logic := '0'; -- asynchronous reset dataout : out std_logic_vector(channel_width-1 downto 0); -- data output of the FIFO empty : out std_logic; -- active low, to indicate FIFO is empty overflow : out std_logic -- active low, to indicate FIFO is full ); end hssi_fifo; -- BEGINNING OF ARCHITECTURE SYNCHRONIZER architecture synchronizer of hssi_fifo is -- SIGNAL DECLARATION signal ram_we : std_logic := '0'; signal ram_reset : std_logic := '1'; signal ram_re : std_logic := '0'; signal ram_datain : std_logic_vector (channel_width-1 downto 0) := (OTHERS=>'0'); signal ram_dataout : std_logic_vector (channel_width-1 downto 0) := (OTHERS=>'0'); signal wrPtr0 : std_logic_vector (2 downto 0) := (OTHERS=>'0'); signal wrPtr1 : std_logic_vector (2 downto 0) := (OTHERS=>'0'); signal wrPtr2 : std_logic_vector (2 downto 0) := (OTHERS=>'0'); signal wrPtr : std_logic_vector (2 downto 0) := (OTHERS=>'0'); signal rdPtr : std_logic_vector (2 downto 0) := (OTHERS=>'0'); signal preRdPtr : std_logic_vector (2 downto 0) := (OTHERS=>'0'); signal preRdPtr1 : std_logic_vector (2 downto 0) := "110"; signal preRdPtr2 : std_logic_vector (2 downto 0) := "110"; signal wrAddr : std_logic_vector (2 downto 0) := (OTHERS=>'0'); signal dataout_tmp : std_logic_vector (channel_width-1 downto 0) := (OTHERS=>'0'); signal empty_tmp : std_logic := '1'; signal need_init : boolean := true; -- COMPONENT DECLARATION component MF_ram7x20_syn generic ( ram_width : integer := 20 ); port ( wclk : in std_logic; rst_l : in std_logic := '1'; addr_wr : in std_logic_vector(2 downto 0); addr_rd : in std_logic_vector(2 downto 0); datain : in std_logic_vector(ram_width-1 downto 0); we : in std_logic := '0'; re : in std_logic := '0'; data_out : out std_logic_vector(ram_width-1 downto 0) ); end component; begin -- reset is active low on MF_ram7x20_syn ram_reset <= not reset; ram_re <= (re and empty_tmp); -- instantiate MF_ram7x20_syn for reading and writing data FIFO_RAM: MF_ram7x20_syn generic map ( ram_width => channel_width ) port map ( wclk => clk0, rst_l => ram_reset, addr_wr => wrAddr, addr_rd => rdPtr, datain => ram_datain, we => ram_we, re => ram_re, data_out => ram_dataout ); process (clk0, clk1, reset, we, re, datain, wrPtr, wrPtr0, wrPtr1, wrPtr2, rdPtr, preRdPtr, preRdPtr1, preRdPtr2) -- VARIABLE DECLARATION variable overflow_tmp_b : std_logic := '1'; -- active low variable empty_tmp_var_b : std_logic := '1'; -- active low begin -- initialize variables and signals if ((now = 0 ns) or (need_init = true)) then dataout_tmp <= (OTHERS => '0'); ram_datain <= (OTHERS => '0'); overflow_tmp_b := '1'; empty_tmp <= '1'; empty_tmp_var_b := '1'; wrAddr <= (OTHERS=>'0'); rdPtr <= (OTHERS=>'0'); wrPtr <= (OTHERS=>'0'); wrPtr0 <= (OTHERS=>'0'); wrPtr1 <= (OTHERS=>'0'); wrPtr2 <= (OTHERS=>'0'); preRdPtr <= (OTHERS=>'0'); preRdPtr1 <= "110"; preRdPtr2 <= "110"; ram_we <= '0'; need_init <= false; end if; -- reset logic if (reset = '1') then dataout_tmp <= (OTHERS => '0'); ram_datain <= (OTHERS => '0'); overflow_tmp_b := '0'; empty_tmp <= '0'; empty_tmp_var_b := '0'; wrAddr <= (OTHERS=>'0'); rdPtr <= (OTHERS=>'0'); wrPtr <= (OTHERS=>'0'); wrPtr0 <= (OTHERS=>'0'); wrPtr1 <= (OTHERS=>'0'); wrPtr2 <= (OTHERS=>'0'); preRdPtr <= (OTHERS=>'0'); preRdPtr1 <= "110"; preRdPtr2 <= "110"; ram_we <= '0'; else -- on read clock's rising edge, increment the read pointer and output data if (clk1'event and (clk1 = '1')) then if ((re = '1') and (empty_tmp_var_b = '1')) then dataout_tmp <= ram_dataout; case rdPtr is when "000" => rdPtr <= "001"; when "001" => rdPtr <= "010"; when "010" => rdPtr <= "011"; when "011" => rdPtr <= "100"; when "100" => rdPtr <= "101"; when "101" => rdPtr <= "110"; when "110" => rdPtr <= "000"; when others => rdPtr <= "000"; end case; preRdPtr <= rdPtr; else dataout_tmp <= dataout_tmp; end if; --synchronize write pointers. wrPtr1 <= wrPtr; wrPtr2 <= wrPtr1; end if; -- on write clock's rising edge, increment the write pointer and send data to the ram if (clk0'event and (clk0 = '1')) then wrPtr <= wrPtr0; if ((we = '1') and (overflow_tmp_b = '1')) then ram_we <= '1'; ram_datain <= datain; wrAddr <= wrPtr0; case wrPtr0 is when "000" => wrPtr0 <= "001"; when "001" => wrPtr0 <= "010"; when "010" => wrPtr0 <= "011"; when "011" => wrPtr0 <= "100"; when "100" => wrPtr0 <= "101"; when "101" => wrPtr0 <= "110"; when "110" => wrPtr0 <= "000"; when others => wrPtr0 <= "000"; end case; else ram_we <= '0'; wrAddr <= wrAddr; ram_datain <= ram_datain; wrPtr0 <= wrPtr0; end if; --synchronize read pointers. preRdPtr1 <= preRdPtr; preRdPtr2 <= preRdPtr1; end if; -- determine if the RAM/FIFO is full/empty if (wrPtr0 = preRdPtr2) then overflow_tmp_b := '0'; else overflow_tmp_b := '1'; end if; if ((rdPtr = wrPtr2) and (overflow_tmp_b = '1')) then empty_tmp_var_b := '0'; else empty_tmp_var_b := '1'; end if; end if; empty_tmp <= empty_tmp_var_b; overflow <= overflow_tmp_b; end process; -- assignments empty <= empty_tmp; dataout <= dataout_tmp; end synchronizer; -- END ARCHITECTURE SYNCHRONIZER -- START ENTITY HEADER --------------------------------------------------------- -- -- Entity Name : HSSI_RX -- -- Description : This is the receiver model used by altcdr_rx. Performs -- deserialization of input data. -- -- Limitations : Assumes that the clock is already perfectly synchronized to the -- incoming data -- -- Expected results: data output from the deserializer, slow clock (clkout) -- generated by the RX, run length violation flag (rlv), and -- locked output to indicate when the RX has failed to lock -- onto the input data signal (not simulated) -- -- END ENTITY HEADER ----------------------------------------------------------- library IEEE, std; use IEEE.std_logic_1164.all; -- ENTITY DECLARATION entity hssi_rx is generic ( channel_width : integer := 20; operation_mode : string := "CDR"; run_length : integer := 1 ); port ( clk : in std_logic; -- fast clock coreclk : in std_logic; -- core clock (slow) datain : in std_logic; -- data input to the receiver areset : in std_logic := '0'; -- asynchronous reset feedback : in std_logic := '0'; -- data feedback port fbkcntl : in std_logic := '0'; -- feedback control port dataout : out std_logic_vector(channel_width-1 downto 0); -- data output of the RX clkout : out std_logic; -- slow clock generated by the RX rlv : out std_logic; -- data run length violation flag locked : out std_logic -- RX lost of lock indicator ); end hssi_rx; -- BEGINNING OF ARCHITECTURE HSSI_RECEIVER architecture hssi_receiver of hssi_rx is begin process (clk, coreclk, areset, fbkcntl) -- VARIABLE DECLARATION variable clk_count : integer := channel_width; --follow the 1st edge variable rlv_count : integer := 0; variable deser_data_arr : std_logic_vector(channel_width-1 downto 0) := (OTHERS=>'0'); variable dataout_tmp : std_logic_vector(channel_width-1 downto 0) := (OTHERS=>'0'); variable clkout_tmp : std_logic := '0'; variable rlv_tmp : std_logic := '0'; variable locked_tmp : std_logic := '0'; variable clkout_last_value : std_logic := '0'; variable datain_int : std_logic := '0'; variable last_datain : std_logic := '0'; variable data_changed : std_logic := '0'; variable rlv_flag : std_logic := '0'; variable rlv_set : std_logic := '0'; variable need_init : boolean := true; begin -- initialize variables if ((now = 0 ns) or (need_init = true)) then dataout_tmp := (OTHERS => '0'); clkout_last_value := '0'; rlv_tmp := '0'; clkout_tmp := '0'; data_changed := '0'; clk_count := channel_width; need_init := false; end if; -- reset logic if (areset = '1') then dataout_tmp := (OTHERS => '0'); clkout_tmp := '0'; clk_count := channel_width; rlv_tmp := '0'; locked_tmp := '0'; clkout_last_value := clk; for i in channel_width-1 downto 0 loop deser_data_arr(i) := '0'; end loop; rlv_count := 0; rlv_flag := '0'; rlv_set := '0'; last_datain := 'X'; data_changed := '0'; -- deserialization and run length violation (rlv) checking else -- data comes either from the feedback port or the datain port if (fbkcntl = '1') then datain_int := feedback; else datain_int := datain; end if; -- fast clock if (clk'event and (clk = '1')) then -- generation of clkout if ((clkout_last_value /= '1') and (clkout_last_value /= '0')) then clkout_last_value := clk; clkout_tmp := clk; end if; if (clk_count = channel_width) then clk_count :=0; clkout_tmp := not (clkout_last_value); elsif (clk_count = (channel_width+1)/2) then clkout_tmp := not (clkout_last_value); elsif (clk_count < channel_width) then clkout_tmp := clkout_last_value; end if; clk_count := clk_count + 1; -- run length violation checking if (operation_mode = "CDR") then if (last_datain /= datain_int) then data_changed := '1'; last_datain := datain_int; else -- datain has not changed rlv_count := rlv_count + 1; data_changed := '0'; end if; if (rlv_count > run_length) then rlv_set := '1'; rlv_flag := '1'; else rlv_set := '0'; end if; if (data_changed = '1') then rlv_count := 1; end if; end if; end if; if (coreclk'event and (coreclk = '1')) then -- output the rlv status with the rising edge of the slow clock if (operation_mode = "CDR") then if (rlv_flag = '1') then rlv_tmp := '1'; if (rlv_set = '0') then rlv_flag := '0'; end if; else rlv_tmp := '0'; end if; end if; end if; -- deserialization if (clk'event and (clk = '0')) then if ((clkout_last_value /= '1') and (clkout_last_value /= '0')) then clkout_last_value := clk; clkout_tmp := clk; end if; if (clk_count = 3) then dataout_tmp(channel_width-1 downto 0) := deser_data_arr; end if; for i in channel_width-1 downto 1 loop deser_data_arr(i) := deser_data_arr(i-1); end loop; deser_data_arr(0) := datain_int; end if; if (clkout_tmp /= 'U') then clkout_last_value := clkout_tmp; end if; end if; -- assign signals to the output ports clkout <= clkout_tmp; dataout <= dataout_tmp; rlv <= rlv_tmp; locked <= locked_tmp; end process; end hssi_receiver; -- END ARCHITECTURE HSSI_RECEIVER -- START ENTITY HEADER --------------------------------------------------------- -- -- Entity Name : HSSI_TX -- -- Description : The transmitter module used by altcdr_tx. Performs -- serialization of output data. -- -- Limitations : -- -- Expected results : Serial data output (dataout) and generated slow clock -- (clkout) -- -- END ENTITY HEADER ----------------------------------------------------------- library IEEE; use IEEE.std_logic_1164.all; -- ENTITY DECLARATION entity hssi_tx is generic ( channel_width : integer := 1 ); port ( clk : in std_logic; -- required port, fast clock datain : in std_logic_vector(channel_width-1 downto 0); -- required port, parallel input data areset : in std_logic := '0'; -- asynchronous reset dataout : out std_logic; -- serial data output clkout : out std_logic -- generated output clock ); end hssi_tx; -- BEGINNING OF ARCHITECTURE TRANSMITTER architecture transmitter of hssi_tx is begin process (clk, areset) -- need to generate clkout here -- VARIABLE DECLARATION variable i : integer := 0; variable fast_clk_count : integer := channel_width; -- always follow the first edge variable indata : std_logic_vector(channel_width-1 downto 0) := (OTHERS=>'0'); variable regdata : std_logic_vector(channel_width-1 downto 0) := (OTHERS=>'0'); variable dataout_tmp : std_logic := '0'; variable clkout_tmp : std_logic := '0'; variable clkout_last_value : std_logic := 'X'; begin -- reset logic if (areset = '1') then dataout_tmp := '0'; clkout_tmp := '0'; fast_clk_count := channel_width; for i in channel_width-1 downto 0 loop -- reset register indata(i) := '0'; regdata(i) := '0'; end loop; else -- rising edge of the fast clock if (clk'event and (clk = '1')) then if ((clkout_last_value /= '1') and (clkout_last_value /= '0')) then --for initial value clkout_last_value := clk; clkout_tmp := clk; end if; -- generate clkout if (fast_clk_count = channel_width) then fast_clk_count := 0; clkout_tmp := not (clkout_last_value); elsif (fast_clk_count = (channel_width+1)/2) then clkout_tmp := not (clkout_last_value); elsif (fast_clk_count < channel_width) then clkout_tmp := clkout_last_value; end if; fast_clk_count := fast_clk_count + 1; -- serialize data -- on 3rd rising edge, start to shift data out if (fast_clk_count = 3) then for i in channel_width-1 downto 0 loop regdata(i) := indata(i); end loop; end if; -- send the MSB of regdata out dataout_tmp := regdata(channel_width - 1); -- shift data up for i in channel_width-1 downto 1 loop regdata(i) := regdata(i-1); end loop; end if; -- on the falling edge of the fast clock if (clk'event and (clk = '0')) then if ((clkout_last_value /= '1') and (clkout_last_value /= '0')) then --for initial value clkout_last_value := clk; clkout_tmp := clk; end if; -- load data from datain port on 3rd falling edge of the fast clock if (fast_clk_count = 3) then indata := datain(channel_width-1 downto 0); end if; end if; end if; if (clkout_tmp /= 'U') then clkout_last_value := clkout_tmp; end if; dataout <= dataout_tmp; clkout <= clkout_tmp; end process; end transmitter; -- END ARCHITECTURE TRANSMITTER -- START ENTITY HEADER --------------------------------------------------------- -- -- Entity Name : ALTCDR_RX -- -- Description : Clock Data Recovery (CDR) Receiver behavioral model. Consists -- of CDR receiver for deserialization, a Phase Locked Loop (PLL) -- and FIFO. -- -- Limitations : Available for the Mercury device family only -- -- Expected results : Deserialized data output (rx_out), recovered global data -- clock (rx_outclock), PLL lock signal, RX lost of lock signal, -- RX run length violation signal, RX FIFO full and empty -- signals (active high), recovered clock per channel -- (rx_rec_clk) -- -- END ENTITY HEADER ----------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use work.pllpack.all; -- ENTITY DECLARATION entity altcdr_rx is generic ( number_of_channels : positive := 1; deserialization_factor : positive := 1; inclock_period : positive; -- required parameter inclock_boost : positive := 1; run_length : integer := 62; -- default based on SONET requirements bypass_fifo : string := "OFF"; intended_device_family : string := "MERCURY"; lpm_type : string := "altcdr_rx" ); port ( rx_in : in std_logic_vector(number_of_channels-1 downto 0); -- required port, data input rx_inclock : in std_logic; -- required port, reference input clock rx_coreclock : in std_logic; -- required port, core clock rx_aclr : in std_logic := '0'; -- asynchronous clear for the RX and FIFO logic rx_pll_aclr : in std_logic := '0'; -- asynchronous clear for the PLL rx_fifo_rden : in std_logic_vector(number_of_channels-1 downto 0) := (OTHERS => '1'); -- FIFO read enable rx_out : out std_logic_vector(deserialization_factor*number_of_channels-1 downto 0); -- data output rx_outclock : out std_logic; -- global core clock recovered from channel 0 rx_pll_locked : out std_logic; -- PLL lock rx_locklost : out std_logic_vector(number_of_channels-1 downto 0); -- RX lost of lock wrt data input rx_rlv : out std_logic_vector(number_of_channels-1 downto 0); -- RX data run length violation rx_full : out std_logic_vector(number_of_channels-1 downto 0); -- RX FIFO full rx_empty : out std_logic_vector(number_of_channels-1 downto 0); -- RX FIFO empty rx_rec_clk : out std_logic_vector(number_of_channels-1 downto 0) -- recovered clock from each channel ); end altcdr_rx; -- BEGINNING OF ARCHITECTURE STRUCT architecture struct of altcdr_rx is -- VARIABLE AND TYPE DECLARATION type cdrword is array (number_of_channels downto 0) of std_logic_vector(deserialization_factor-1 downto 0); signal w_rx_inclock0 : std_logic := '0'; signal w_rx_clkout : std_logic_vector(number_of_channels-1 downto 0) := (OTHERS=>'0'); signal w_rx_out : cdrword; signal fifo_rx_out : std_logic_vector(deserialization_factor*number_of_channels-1 downto 0) := (OTHERS=>'0'); signal i_rx_out : std_logic_vector(deserialization_factor*number_of_channels-1 downto 0) := (OTHERS=>'0'); signal fifo_empty : std_logic_vector(number_of_channels-1 downto 0) := (OTHERS=>'0'); signal fifo_full : std_logic_vector(number_of_channels-1 downto 0) := (OTHERS=>'0'); -- COMPONENT DECLARATION -- HSSI_PLL component hssi_pll generic ( clk0_multiply_by : integer := 1; input_frequency : integer := 1000 -- period in ps ); port ( clk : in std_logic := '0'; areset : in std_logic := '0'; clk0 : out std_logic; locked : out std_logic ); end component; -- hssi _pll -- HSSI_RX component hssi_rx generic ( channel_width : integer := 20; operation_mode : string := "CDR"; run_length : integer := 1 ); port ( clk : in std_logic; coreclk : in std_logic; datain : in std_logic; areset : in std_logic := '0'; dataout : out std_logic_vector(channel_width-1 downto 0); clkout : out std_logic; rlv : out std_logic; locked : out std_logic ); end component; -- hssi_rx -- HSSI_FIFO component hssi_fifo generic ( channel_width : integer := 20 ); port ( datain : in std_logic_vector(channel_width-1 downto 0); clk0 : in std_logic; clk1 : in std_logic; re : in std_logic := '0'; reset : in std_logic := '0'; dataout : out std_logic_vector(channel_width-1 downto 0); empty : out std_logic; overflow : out std_logic ); end component; -- hssi_fifo constant RUN_LENGTH_MAX : integer := 62; begin -- checking for invalid parameters MSG: process begin if (number_of_channels <= 0) then ASSERT FALSE REPORT "The number_of_channels parameter must be greater than 0" SEVERITY ERROR; end if; if (run_length > RUN_LENGTH_MAX) then ASSERT FALSE REPORT "The run_length parameter must be greater than " & int2str(RUN_LENGTH_MAX) SEVERITY ERROR; end if; if not (((deserialization_factor >= 3) and (deserialization_factor <= 12)) or (deserialization_factor = 14) or (deserialization_factor = 16) or (deserialization_factor = 18) or (deserialization_factor = 20)) then ASSERT FALSE REPORT "Illegal value for deserialization_factor parameter " & int2str(deserialization_factor) & " -- value " & "must be in the range 3 to 12, inclusive, or must be one of 14, 16, 18, or 20" SEVERITY ERROR; end if; wait; end process MSG; -- Generate the required numbers of PLL, FIFO and receiver modules -- PLL PLL: hssi_pll generic map ( clk0_multiply_by => inclock_boost, input_frequency => inclock_period ) port map ( clk => rx_inclock, areset => rx_pll_aclr, clk0 => w_rx_inclock0, locked => rx_pll_locked ); -- Receiver RX_GEN: for i in 0 to number_of_channels-1 generate RX: hssi_rx generic map ( channel_width => deserialization_factor, operation_mode => "CDR", run_length => run_length ) port map ( clk => w_rx_inclock0, coreclk => rx_coreclock, datain => rx_in(i), areset => rx_aclr, dataout => w_rx_out(i), clkout => w_rx_clkout(i), rlv => rx_rlv(i), locked => rx_locklost(i) ); end generate; -- FIFO FIFO_GEN: for i in 0 to number_of_channels-1 generate FIFO: hssi_fifo generic map ( channel_width => deserialization_factor ) port map ( datain => w_rx_out(i), clk0 => w_rx_clkout(i), clk1 => rx_coreclock, re => rx_fifo_rden(i), reset => rx_aclr, dataout => fifo_rx_out((i+1)*deserialization_factor-1 downto i*deserialization_factor), overflow => fifo_full(i), empty => fifo_empty(i) ); end generate; -- data output from the receiver part, for use as rx_out when FIFO is bypassed IRX: for i in 0 to number_of_channels-1 generate i_rx_out((i+1)*deserialization_factor-1 downto i* deserialization_factor) <= w_rx_out(i); end generate; -- Assign the correct signals to the correct output ports rx_outclock <= w_rx_clkout(0); rx_rec_clk <= w_rx_clkout; rx_out <= fifo_rx_out when bypass_fifo = "OFF" else i_rx_out; rx_empty <= not fifo_empty when bypass_fifo = "OFF" else (others => 'X'); rx_full <= not fifo_full when bypass_fifo = "OFF" else (others => 'X'); end struct; -- END ARCHITECTURE STRUCT -- START ENTITY HEADER --------------------------------------------------------- -- -- Entity Name : ALTCDR_TX -- -- Description : The Clock Data Recovery (CDR) transmitter behavioral -- model. Consists of CDR transmitter for serialization, -- a PLL and FIFO. -- -- Limitations : Available for the Mercury device family only. -- -- Expected results : Serial data output (tx_out), generated slow clock -- (tx_clkout), FIFO full signal (tx_full), FIFO empty signal -- (tx_empty), PLL lock signal (tx_pll_locked) -- -- END ENTITY HEADER ----------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use work.pllpack.all; -- ENTITY DECLARATION entity altcdr_tx is generic ( number_of_channels : positive := 1; deserialization_factor : positive := 1; inclock_period : positive; -- required parameter inclock_boost : positive := 1; bypass_fifo : string := "OFF"; intended_device_family : string := "MERCURY"; lpm_type : string := "altcdr_tx" ); port ( tx_in : in std_logic_vector(deserialization_factor*number_of_channels-1 downto 0); -- required port, parallel data input tx_inclock : in std_logic; -- required port, input reference clock tx_coreclock : in std_logic; -- required port, input core clock tx_aclr : in std_logic := '0'; -- asynchronous clear for TX and FIFO tx_pll_aclr : in std_logic := '0'; -- asynchronous clear for PLL tx_fifo_wren : in std_logic_vector(number_of_channels-1 downto 0) := (OTHERS => '1'); -- FIFO write enable tx_out : out std_logic_vector(number_of_channels-1 downto 0); -- serial data output tx_outclock : out std_logic; -- generated slow clock tx_pll_locked : out std_logic; -- PLL lock signal tx_empty : out std_logic_vector(number_of_channels-1 downto 0); -- FIFO empty signal tx_full : out std_logic_vector(number_of_channels-1 downto 0) -- FIFO full signal ); end altcdr_tx; -- BEGINNING OF ARCHITECTURE STRUCT architecture struct of altcdr_tx is -- SIGNAL AND TYPE DECLARATION type cdrword is array (number_of_channels downto 0) of std_logic_vector(deserialization_factor-1 downto 0); signal fifo_out : cdrword; signal tx_data_in : cdrword; signal i_tx_in : cdrword; signal w_tx_inclock0 : std_logic := '0'; signal w_tx_clkout : std_logic_vector(number_of_channels-1 downto 0) := (OTHERS=>'0'); signal i_tx_out : std_logic_vector(deserialization_factor*number_of_channels-1 downto 0) := (OTHERS=>'0'); signal fifo_empty : std_logic_vector(number_of_channels-1 downto 0) := (OTHERS=>'0'); signal fifo_full : std_logic_vector(number_of_channels-1 downto 0) := (OTHERS=>'1'); -- COMPONENT DECLARATION -- HSSI_PLL component hssi_pll generic ( clk0_multiply_by : integer := 1; input_frequency : integer := 1000 ); port ( clk : in std_logic := '0'; areset : in std_logic := '0'; clk0 : out std_logic; locked : out std_logic ); end component; -- hssi_pll -- HSSI_TX component hssi_tx generic ( channel_width : integer := 20 ); port ( clk : in std_logic; datain : in std_logic_vector(channel_width-1 downto 0); areset : in std_logic := '0'; clkout : out std_logic; dataout : out std_logic ); end component; -- hssi_tx -- HSSI_FIFO component hssi_fifo generic ( channel_width : integer := 20 ); port ( datain : in std_logic_vector(channel_width-1 downto 0); clk0 : in std_logic; clk1 : in std_logic; we : in std_logic := '0'; reset : in std_logic := '0'; dataout : out std_logic_vector(channel_width-1 downto 0); empty : out std_logic; overflow : out std_logic ); end component; -- hssi_fifo begin -- checking for invalid parameters MSG: process begin if (number_of_channels <= 0) then ASSERT FALSE REPORT "The number_of_channels parameter must be greater than 0" SEVERITY ERROR; end if; if not (((deserialization_factor >= 3) and (deserialization_factor <= 12)) or (deserialization_factor = 14) or (deserialization_factor = 16) or (deserialization_factor = 18) or (deserialization_factor = 20)) then ASSERT FALSE REPORT "Illegal value for deserialization_factor parameter " & int2str(deserialization_factor) & " -- value " & "must be in the range 3 to 12, inclusive, or must be one of 14, 16, 18, or 20" SEVERITY ERROR; end if; wait; end process MSG; -- COMPONENT INSTANTIATION PLL_GEN: hssi_pll generic map ( clk0_multiply_by => inclock_boost, input_frequency => inclock_period ) port map ( clk => tx_inclock, areset => tx_pll_aclr, clk0 => w_tx_inclock0, locked => tx_pll_locked ); FIFO_GEN: for i in 0 to number_of_channels-1 generate FIFO: hssi_fifo generic map ( channel_width => deserialization_factor ) port map ( clk0 => tx_coreclock, clk1 => w_tx_clkout(i), we => tx_fifo_wren(i), reset => tx_aclr, datain => tx_in(((i+1)*deserialization_factor-1) downto (i*deserialization_factor)), overflow => fifo_full(i), empty => fifo_empty(i), dataout => fifo_out(i) ); end generate FIFO_GEN; TX_GEN: for i in 0 to number_of_channels-1 generate TX: hssi_tx generic map ( channel_width => deserialization_factor ) port map ( clk => w_tx_inclock0, datain => tx_data_in(i), areset => tx_aclr, clkout => w_tx_clkout(i), dataout => tx_out(i) ); end generate TX_GEN; -- break input data to an array of signals IRX: for i in 0 to number_of_channels-1 generate i_tx_in(i) <= tx_in(((i+1)*deserialization_factor-1) downto (i*deserialization_factor)); end generate IRX; -- signal assignments tx_data_in <= fifo_out when bypass_fifo = "OFF" else i_tx_in; tx_empty <= not fifo_empty when bypass_fifo = "OFF" else (OTHERS => 'X'); tx_full <= not fifo_full when bypass_fifo = "OFF" else (OTHERS => 'X'); tx_outclock <= w_tx_clkout(0); end struct; -- END ARCHITECTURE STRUCT ---START_ENTITY_HEADER--------------------------------------------------------- -- -- Entity Name : stratixii_lvds_rx -- -- Description : Stratix II lvds receiver. Support both the dpa and non-dpa -- mode. -- -- Limitation : Only available to Stratix II. -- -- Results Expected: Deserialized output data, dpa lock signal and status bit -- indicating whether maximum bitslip has been reached. -- ---END_ENTITY_HEADER----------------------------------------------------------- -- LIBRARY USED---------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; -- ENTITY DECLARATION entity stratixii_lvds_rx is -- GENERIC DECLARATION generic ( number_of_channels : natural; -- Required parameter deserialization_factor : natural; -- Required parameter enable_dpa_mode : string := "OFF"; data_align_rollover : natural := 10; lose_lock_on_one_change : string := "OFF"; reset_fifo_at_first_lock : string := "ON" ); -- PORT DECLARATION port ( --INPUT PORT DECLARATION rx_in : in std_logic_vector(number_of_channels-1 downto 0); --Required port rx_fastclk : in std_logic; --Required port rx_enable : in std_logic := '1'; rx_locked : in std_logic; rx_reset : in std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); rx_dpll_hold : in std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); rx_dpll_enable : in std_logic_vector(number_of_channels-1 downto 0) := (others => '1'); rx_fifo_reset : in std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); rx_channel_data_align : in std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); rx_cda_reset : in std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); -- OUTPUT PORT DECLARATION rx_out : out std_logic_vector(deserialization_factor*number_of_channels -1 downto 0); rx_dpa_locked : out std_logic_vector(number_of_channels-1 downto 0); rx_cda_max : out std_logic_vector(number_of_channels-1 downto 0) := (others => '0') ); end stratixii_lvds_rx; -- END OF ENTITY -- BEGINNING OF ARCHITECTURE -- ARCHITECTURE DECLARATION architecture behavior of stratixii_lvds_rx is -- CONSTANT DECLARATION constant REGISTER_WIDTH : natural := deserialization_factor * number_of_channels; constant MUX_WIDTH : natural := 12; -- TYPE DECLARATION type CHANNEL_CNT is array (number_of_channels-1 downto 0) of integer; type CHANNEL_BOOL is array (number_of_channels-1 downto 0) of boolean; type DPA_FIFO_RAM is array (number_of_channels -1 downto 0) of std_logic_vector(5 downto 0); type BITSLIP_REG_CHAIN is array (number_of_channels-1 downto 0) of std_logic_vector(MUX_WIDTH-1 downto 0); -- SIGNAL DECLARATION -- constant signals signal temp_high : std_logic_vector (5 downto 0):= (others => '1'); signal temp_clk : std_logic_vector (4 downto 1):= (others => '0'); signal fifo_write_clk : std_logic := '0'; signal fifo_read_clk : std_logic := '0'; signal temp_zero : std_logic := '0'; signal enable0_reg : std_logic := '0'; signal enable_negedge_count : boolean := false; signal rx_shift_reg : std_logic_vector(REGISTER_WIDTH-1 downto 0) := (others => '0'); signal rx_parallel_load_reg : std_logic_vector(REGISTER_WIDTH-1 downto 0) := (others => '0'); signal rx_in_reg : std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); signal fifo_out_sync_reg : std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); signal bitslip_mux_out : std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); signal dpa_in : std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); signal retime_data : std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); signal dpll_lock : std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); signal dpll_first_lock : std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); signal rx_channel_data_align_pre : std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); signal ram_array : DPA_FIFO_RAM := (others => (others => '0')); signal rx_in_mux : std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); signal dpa_fifo_in : std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); signal dpa_fifo_out : std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); signal rx_in_reg_clk : std_logic := '0'; signal rx_bload : std_logic := '0'; begin -- SIGNAL ASSIGNMENTS rx_out <= rx_parallel_load_reg; rx_in_mux <= rx_in_reg when (enable_dpa_mode = "OFF") else dpa_fifo_out; dpa_fifo_in <= retime_data; dpa_fifo_out <= fifo_out_sync_reg; fifo_write_clk <= rx_fastclk; fifo_read_clk <= rx_fastclk; rx_in_reg_clk <= rx_fastclk; rx_dpa_locked <= dpll_lock; rx_bload <= enable0_reg; -- PROCESS DECLARATION -- Basic error checking for invalid deserialization factors MSG: process begin wait; end process; -- MSG process -- the deserializer STRATIXII_DESER : process(rx_fastclk) begin if (deserialization_factor > 2) then if (rx_fastclk'event and (rx_fastclk = '1')) then if (rx_bload = '1') then rx_parallel_load_reg <= rx_shift_reg; end if; for i in 0 to number_of_channels -1 loop for x in deserialization_factor-1 downto 1 loop rx_shift_reg(x + (i * deserialization_factor)) <= rx_shift_reg(x-1 + (i * deserialization_factor)); end loop; rx_shift_reg(i * deserialization_factor) <= bitslip_mux_out(i); end loop; -- Registering load enable signal enable0_reg <= rx_enable; end if; end if; end process STRATIXII_DESER; -- input synchronization register IN_SYNC_REGISTER : process (rx_in_reg_clk) begin if (rx_in_reg_clk = '1') then rx_in_reg <= rx_in; end if; end process IN_SYNC_REGISTER; -- STRATIXII bitslip logic STRATIXII_BITSLIP : process (rx_fastclk, rx_cda_reset) variable start_corrupt_bits : CHANNEL_BOOL := (others => false); variable num_corrupt_bits : CHANNEL_CNT := (others => 0); variable bitslip_count : CHANNEL_CNT := (others => 0); variable shift_reg_chain : BITSLIP_REG_CHAIN := (others => (others => '0')); begin for i in 0 to number_of_channels-1 loop if (rx_cda_reset(i) = '1') then bitslip_count(i) := 0; for j in MUX_WIDTH-1 downto 0 loop shift_reg_chain(i)(j) := '0'; end loop; bitslip_mux_out(i) <= shift_reg_chain(i)(bitslip_count(i)); elsif (rx_fastclk'event and (rx_fastclk = '1')) then if (((rx_channel_data_align(i) = '1') and (rx_channel_data_align_pre(i) = '0')) or ((start_corrupt_bits(i) = true) and (num_corrupt_bits(i) < 4))) then bitslip_mux_out(i) <= 'X'; else bitslip_mux_out(i) <= shift_reg_chain(i)(bitslip_count(i)); end if; for j in MUX_WIDTH-2 downto 0 loop shift_reg_chain(i)(j + 1) := shift_reg_chain(i)(j); end loop; shift_reg_chain(i)(0) := rx_in_mux(i); if ((rx_channel_data_align(i) = '1') and (rx_channel_data_align_pre(i) = '0'))then bitslip_count(i) := (bitslip_count(i) + 1) rem (data_align_rollover + 1); if (bitslip_count(i) = data_align_rollover) then rx_cda_max(i) <= '1'; else rx_cda_max(i) <= '0'; end if; start_corrupt_bits(i) := true; num_corrupt_bits(i) := 1; elsif ((rx_channel_data_align(i) = '0') and (rx_channel_data_align_pre(i) = '1'))then start_corrupt_bits(i) := false; num_corrupt_bits(i) := 0; end if; if (start_corrupt_bits(i) = true) then if (num_corrupt_bits(i) = 3) then start_corrupt_bits(i) := false; else num_corrupt_bits(i) := num_corrupt_bits(i) + 1; end if; end if; rx_channel_data_align_pre(i) <= rx_channel_data_align(i); end if; end loop; end process STRATIXII_BITSLIP; -- STRATIXII Phase Compensation FIFO STRATIXII_DPA_FIFO : process (fifo_write_clk, fifo_read_clk) variable wrPtr : CHANNEL_CNT := (others => 0); variable rdPtr : CHANNEL_CNT := (others => 3); variable fifo_in_sync_reg : std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); begin if (fifo_write_clk'event and (fifo_write_clk = '1')) then for i in 0 to number_of_channels-1 loop if ((rx_fifo_reset(i) = '1') or ((reset_fifo_at_first_lock = "ON") and (dpll_first_lock(i) = '0'))) then wrPtr(i) := 0; ram_array(i) <= (others => '0'); fifo_in_sync_reg(i) := '0'; else wrPtr(i) := (wrPtr(i) + 1) rem 6; ram_array(i)(wrPtr(i)) <= fifo_in_sync_reg(i); fifo_in_sync_reg(i) := dpa_fifo_in(i); end if; end loop; end if; if (fifo_read_clk'event and (fifo_read_clk = '1')) then for i in 0 to number_of_channels-1 loop if ((rx_fifo_reset(i) = '1') or ((reset_fifo_at_first_lock = "ON") and (dpll_first_lock(i) = '0'))) then rdPtr(i) := 3; ram_array(i) <= (others =>'0'); fifo_out_sync_reg(i) <= '0'; else rdPtr(i) := (rdPtr(i) + 1) rem 6; fifo_out_sync_reg(i) <= ram_array(i)(rdPtr(i)); end if; end loop; end if; end process STRATIXII_DPA_FIFO; -- STRATIXII DPA Block STRATIXII_DPA_BLOCK : process (rx_fastclk) variable dpll_clk_count : CHANNEL_CNT := (others => 0); begin if (rx_fastclk'event and (rx_fastclk = '1')) then for i in 0 to number_of_channels-1 loop dpa_in(i) <= rx_in(i); retime_data(i) <= dpa_in(i); if (rx_reset(i) = '1') then dpll_clk_count(i) := 0; dpll_lock(i) <= '0'; else dpll_clk_count(i) := dpll_clk_count(i) + 1; if (dpll_clk_count(i) = 2) then dpll_lock(i) <= '1'; dpll_first_lock(i) <= '1'; end if; end if; end loop; end if; end process STRATIXII_DPA_BLOCK; end behavior; -- END OF ARCHITECTURE -- START ENTITY HEADER --------------------------------------------------------- -- -- Entity Name : altlvds_rx -- -- Description : Low Voltage Differential Signaling (LVDS) receiver -- megafunction. The altlvds_rx megafunction implements a -- deserialization receiver. LVDS is a high speed IO interface -- that uses inputs without a reference voltage. LVDS uses -- two wires carrying differential values to create a single -- channel. These wires are connected to two pins on -- supported device to create a single LVDS channel -- -- Limitations : Only available for APEX20KE, APEXII, MERCURY, STRATIX, -- STRATIX GX and Stratix II families. -- --Results expected : output clock, deserialized output data and pll locked -- signal. -- -- END ENTITY HEADER ----------------------------------------------------------- -- LIBRARY USED----------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use work.ALTERA_DEVICE_FAMILIES.all; -- ENTITY DECLARATION entity altlvds_rx is -- GENERIC DECLARATION generic ( number_of_channels : natural; -- Required parameter deserialization_factor : natural; -- Required parameter registered_output : string := "ON"; inclock_period : natural := 10000; -- Required parameter inclock_boost : natural := 0; cds_mode : string := "UNUSED"; intended_device_family : string := "APEX20KE"; input_data_rate : natural := 0; inclock_data_alignment : string := "EDGE_ALIGNED"; registered_data_align_input : string := "ON"; common_rx_tx_pll : string := "ON"; enable_dpa_mode : string := "OFF"; enable_dpa_fifo : string := "ON"; use_dpll_rawperror : string := "OFF"; use_coreclock_input : string := "OFF"; dpll_lock_count : natural := 0; dpll_lock_window : natural := 0; outclock_resource : string := "AUTO"; data_align_rollover : natural := 10; lose_lock_on_one_change : string := "OFF"; reset_fifo_at_first_lock : string := "ON"; use_external_pll : string := "OFF"; lpm_hint : string := "UNUSED"; lpm_type : string := "altlvds_rx"; -- Specifies whether the source of the input clock is from the PLL clk_src_is_pll : string := "off" ); -- PORT DECLARATION port ( --INPUT PORT DECLARATION rx_in : in std_logic_vector(number_of_channels-1 downto 0); --Required port rx_inclock : in std_logic; --Required port rx_enable : in std_logic := '0'; rx_deskew : in std_logic := '0'; rx_pll_enable : in std_logic := '1'; rx_data_align : in std_logic := 'Z'; rx_reset : in std_logic_vector(number_of_channels-1 downto 0):= (others => '0'); rx_dpll_reset : in std_logic_vector(number_of_channels-1 downto 0):= (others => '0'); rx_dpll_hold : in std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); rx_dpll_enable : in std_logic_vector(number_of_channels-1 downto 0) := (others => '1'); rx_fifo_reset : in std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); rx_channel_data_align : in std_logic_vector(number_of_channels-1 downto 0) := (others => 'Z'); rx_cda_reset : in std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); rx_coreclk : in std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); pll_areset : in std_logic := '0'; -- OUTPUT PORT DECLARATION rx_out : out std_logic_vector(deserialization_factor*number_of_channels -1 downto 0); rx_outclock : out std_logic; rx_locked : out std_logic; rx_dpa_locked : out std_logic_vector(number_of_channels-1 downto 0); rx_cda_max : out std_logic_vector(number_of_channels-1 downto 0) ); end altlvds_rx; -- END OF ENTITY -- BEGINNING OF ARCHITECTURE -- ARCHITECTURE DECLARATION architecture behavior of altlvds_rx is -- FUNCTION DECLARATION --- Convert integer to string --- function int_to_str( constant value : integer ) return string is variable ivalue : integer := 0; variable index : integer := 0; variable strlen : integer := 0; variable digit : integer := 0; variable temp : string(1 to 8) := "00000000"; begin ivalue := value; strlen := 0; while (ivalue > 0) loop ivalue := ivalue/10; strlen := strlen + 1; end loop; if (strlen = 0) then strlen := 1; end if; ivalue := value; index := strlen; while (ivalue > 0) loop digit := ivalue mod 10; ivalue := ivalue/10; case digit is when 0 => temp(index) := '0'; when 1 => temp(index) := '1'; when 2 => temp(index) := '2'; when 3 => temp(index) := '3'; when 4 => temp(index) := '4'; when 5 => temp(index) := '5'; when 6 => temp(index) := '6'; when 7 => temp(index) := '7'; when 8 => temp(index) := '8'; when 9 => temp(index) := '9'; when others => ASSERT FALSE REPORT "Illegal number!" SEVERITY ERROR; end case; index := index - 1; end loop; return temp(1 to strlen); end int_to_str; --- calculate clock boost value need by the pll --- function clock_boost_calc (constant i_input_data_rate, i_inclock_period, i_deserialization_factor, i_inclock_boost : in natural) return natural is variable i_input_clock_boost : natural; begin if ((i_input_data_rate /= 0) and (i_inclock_period /= 0)) then i_input_clock_boost := (((i_input_data_rate * i_inclock_period) + (5* 100000)) / 1000000); else if (inclock_boost = 0) then i_input_clock_boost := i_deserialization_factor; else i_input_clock_boost := i_inclock_boost; end if; end if; return i_input_clock_boost; end clock_boost_calc; --- get phase delay in ps for stratix pll --- function get_phase_delay (constant i_phase_delay : in string) return string is variable my_phase : integer := 0; variable x, int_delay : integer := 0; begin -- get delay in ps ( * inclock period / 360 degress ) if (i_phase_delay = "EDGE_ALIGNED") then my_phase := 0; elsif (i_phase_delay = "CENTER_ALIGNED") then -- CENTER_ALIGNED means 180 degrees my_phase := (180 * inclock_period) / 360; elsif (i_phase_delay = "45_DEGREES") then my_phase := (45 * inclock_period) / 360; elsif (i_phase_delay = "90_DEGREES") then my_phase := (90 * inclock_period) / 360; elsif (i_phase_delay = "135_DEGREES") then my_phase := (135 * inclock_period) / 360; elsif (i_phase_delay = "180_DEGREES") then my_phase := (180 * inclock_period) / 360; elsif (i_phase_delay = "225_DEGREES") then my_phase := (225 * inclock_period) / 360; elsif (i_phase_delay = "270_DEGREES") then my_phase := (270 * inclock_period) / 360; elsif (i_phase_delay = "315_DEGREES") then my_phase := (315 * inclock_period) / 360; else ASSERT FALSE REPORT "Invalid clock data alignment. Using 'EDGE_ALIGNED' instead" SEVERITY WARNING; my_phase :=0; end if; -- Add 1 to "round up" calculation result my_phase := my_phase + 1; -- phase shift in ps = ( * inclock_period / 360 ) / fast clock multiply_by factor -- in other words, the phase shift is a percentage of the fast clock period int_delay := my_phase / clock_boost_calc(input_data_rate, inclock_period, deserialization_factor, inclock_boost); -- Add 1 to "round up" calculation result int_delay := int_delay + 1; return int_to_str (int_delay); end get_phase_delay; -- CONSTANT DECLARATION -- these constants are PLL parameters calculated from the altlvds_rx parameters given constant PHASE_INCLOCK : string := get_phase_delay(inclock_data_alignment); constant INT_CLOCK_BOOST : natural := clock_boost_calc(input_data_rate, inclock_period, deserialization_factor, inclock_boost); constant REGISTER_WIDTH : natural := deserialization_factor * number_of_channels; constant APEX20KE_RX_STYLE : boolean := IS_FAMILY_APEX20KE(intended_device_family); constant APEXII_RX_STYLE : boolean := IS_FAMILY_APEXII(intended_device_family); constant MERCURY_RX_STYLE : boolean := IS_FAMILY_MERCURY(intended_device_family); constant STRATIX_RX_STYLE : boolean := (IS_FAMILY_STRATIX(intended_device_family) or (IS_FAMILY_STRATIXGX(intended_device_family) and (enable_dpa_mode = "OFF"))); constant STRATIXGX_DPA_RX_STYLE : boolean := (IS_FAMILY_STRATIXGX(intended_device_family) and (enable_dpa_mode = "ON")); constant STRATIXII_RX_STYLE : boolean := IS_FAMILY_STRATIXII(intended_device_family); -- TYPE DECLARATION type CHANNEL_CNT is array (number_of_channels-1 downto 0) of integer; type DPA_FIFO_RAM is array (3 downto 0) of std_logic_vector(REGISTER_WIDTH -1 downto 0); -- SIGNAL DECLARATION signal rxpdat1 : std_logic_vector(REGISTER_WIDTH -1 downto 0) := (others => '0'); signal rxpdat2 : std_logic_vector(REGISTER_WIDTH -1 downto 0) := (others => '0'); signal rxpdat3 : std_logic_vector(REGISTER_WIDTH -1 downto 0) := (others => '0'); signal rxpdatout : std_logic_vector(REGISTER_WIDTH -1 downto 0) := (others => '0'); signal rx_out_rgd : std_logic_vector(REGISTER_WIDTH -1 downto 0) := (others => '0'); signal rx_out_apex : std_logic_vector(REGISTER_WIDTH -1 downto 0) := (others => '0'); signal rx_out_extra_yeager_reg : std_logic_vector(REGISTER_WIDTH -1 downto 0) := (others => '0'); signal rx_hold_rgd : std_logic_vector(REGISTER_WIDTH -1 downto 0) := (others => '0'); signal rx_out_int : std_logic_vector(REGISTER_WIDTH -1 downto 0) := (others => '0'); signal data_out : std_logic_vector(REGISTER_WIDTH -1 downto 0) := (others => '0'); signal serdes_data_out : std_logic_vector(REGISTER_WIDTH -1 downto 0) := (others => '0'); signal write_data : std_logic_vector(REGISTER_WIDTH -1 downto 0) := (others => '0'); signal read_data : std_logic_vector(REGISTER_WIDTH -1 downto 0) := (others => '0'); signal rx_ddio_in : std_logic_vector(REGISTER_WIDTH -1 downto 0) := (others => '0'); signal stratixii_dataout : std_logic_vector(REGISTER_WIDTH -1 downto 0) := (others => '0'); -- calibration signals signal deskew_done : std_logic_vector(number_of_channels-1 downto 0) := (others => '1'); signal calibrate : std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); -- to store previous port values signal rx_coreclk_pre : std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); signal rx_channel_data_align_wire : std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); signal rx_channel_data_align_pre : std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); signal pclk_pre : std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); -- constant signals signal temp_high : std_logic_vector (5 downto 0):= (others => '1'); signal temp_clk : std_logic_vector (4 downto 1):= (others => '0'); signal temp_z : std_logic_vector (number_of_channels-1 downto 0):= (others => 'Z'); -- FIFO ram for Stratix GX signal ram_array : DPA_FIFO_RAM := (others => (others => '0')); -- PLL ports signal rx_clock0_int : std_logic := '0'; -- fast clock signal rx_clock1_int : std_logic := '0'; -- slow clock signal rx_pll_clk0 : std_logic := '0'; signal rx_pll_clk1 : std_logic := '0'; signal yeager_locked_int : std_logic := '0'; signal aurora_locked_int : std_logic := '0'; signal stratixii_locked_int : std_logic := '0'; signal apex20ke_locked_int : std_logic := '0'; signal apex20ke_pll_clk0 : std_logic := '0'; signal apex20ke_pll_clk1 : std_logic := '0'; signal apexii_locked_int : std_logic := '0'; signal apexii_pll_clk0 : std_logic := '0'; signal apexii_pll_clk1 : std_logic := '0'; signal mercury_locked_int_deser : std_logic := '0'; signal mercury_pll_clk0_deser : std_logic := '0'; signal mercury_pll_clk1_deser : std_logic := '0'; signal mercury_locked_int_boost : std_logic := '0'; signal mercury_pll_clk0_boost : std_logic := '0'; signal mercury_pll_clk1_boost : std_logic := '0'; signal mercury_locked_int : std_logic := '0'; signal mercury_pll_clk0 : std_logic := '0'; signal mercury_pll_clk1 : std_logic := '0'; signal rx_mercury_slow_clock : std_logic := '0'; signal rx_locked_int : std_logic := '0'; signal temp_zero : std_logic := '0'; -- Stratix, Stratix II and Stratix GX specific signals signal rx_data_align_reg : std_logic := '0'; signal rx_data_align_int : std_logic := '0'; signal rx_data_align_wire : std_logic := '0'; signal rx_data_align_clk : std_logic := '0'; signal enable0_reg : std_logic; signal enable0_pipe : std_logic; signal enable0_neg : std_logic; signal enable1_reg : std_logic; signal sampling : std_logic := '0'; signal yeager_clock : std_logic_vector (5 downto 0) := (others => '0'); signal aurora_clock : std_logic_vector (5 downto 0) := (others => '0'); signal stratixii_clock : std_logic_vector (5 downto 0) := (others => '0'); signal pclk : std_logic_vector (number_of_channels-1 downto 0) := (others => '0'); signal clkout_tmp : std_logic_vector (number_of_channels-1 downto 0) := (others => '0'); signal sync_reset : std_logic_vector (number_of_channels-1 downto 0) := (others => '0'); signal stratixii_dpa_locked : std_logic_vector (number_of_channels-1 downto 0) := (others => '0'); signal rx_pll_sclkout0 : std_logic := '0'; signal rx_pll_sclkout1 : std_logic := '0'; signal stratixii_sclkout0 : std_logic := '0'; signal stratixii_fastclk : std_logic := '0'; signal stratixii_enable : std_logic := '0'; signal rx_pll_enable0 : std_logic := '0'; signal rx_pll_enable1 : std_logic := '0'; signal rx_pll_sclkout0_dly : std_logic := '0'; -- COMPONENT DECLARATION -- pll definition component altclklock generic ( inclock_period : natural := 10000; clock0_boost : natural := 1; clock1_boost : natural := 1; clock1_divide : natural := 1; valid_lock_cycles : natural := 5; intended_device_family : string := "APEX20KE"; outclock_phase_shift : natural :=0 ); port ( inclock : in std_logic; inclocken : in std_logic := '1'; clock0 : out std_logic; clock1 : out std_logic; locked : out std_logic ); end component; -- altclklock component MF_stratix_pll generic ( pll_type : string := "lvds"; inclk0_input_frequency : positive ; inclk1_input_frequency : positive ; valid_lock_multiplier : integer := 1; simulation_type : string := "functional"; clk0_multiply_by : positive := 1; clk0_divide_by : positive := 1; clk0_phase_shift : string := "0"; clk2_multiply_by : positive := 1; clk2_divide_by : positive := 1; clk2_phase_shift : string := "0"; enable0_counter : string := "l0"; enable1_counter : string := "l1"; m : integer := 0); port ( inclk : in std_logic_vector(1 downto 0) := (others => '0'); fbin : in std_logic := '1'; ena : in std_logic := '1'; clkswitch : in std_logic := '0'; areset : in std_logic := '0'; pfdena : in std_logic := '1'; clkena : in std_logic_vector(5 downto 0) := (others => '1'); extclkena : in std_logic_vector(3 downto 0) := (OTHERS=>'1'); scanaclr : in std_logic := '0'; scandata : in std_logic := '0'; scanclk : in std_logic := '0'; comparator : in std_logic := '0'; clk : out std_logic_vector(5 downto 0); locked : out std_logic; enable0 : out std_logic; enable1 : out std_logic); end component; -- MF_stratix_pll component MF_stratixii_pll generic ( pll_type : string := "lvds"; vco_multiply_by : integer := 0; vco_divide_by : integer := 0; inclk0_input_frequency : positive ; inclk1_input_frequency : positive ; simulation_type : string := "functional"; clk0_multiply_by : positive := 1; clk0_divide_by : positive := 1; clk0_phase_shift : string := "0"; clk2_multiply_by : positive := 1; clk2_divide_by : positive := 1; clk2_phase_shift : string := "0"; sclkout0_phase_shift : string := "0"; enable0_counter : string := "c0"; enable1_counter : string := "c1"; m : integer := 0); port ( inclk : in std_logic_vector(1 downto 0) := (others => '0'); fbin : in std_logic := '1'; ena : in std_logic := '1'; clkswitch : in std_logic := '0'; areset : in std_logic := '0'; pfdena : in std_logic := '1'; scanread : in std_logic := '0'; scanwrite : in std_logic := '0'; scandata : in std_logic := '0'; scanclk : in std_logic := '0'; clk : out std_logic_vector(5 downto 0); locked : out std_logic; enable0 : out std_logic; enable1 : out std_logic; sclkout : out std_logic_vector(1 downto 0)); end component; -- MF_stratixii_pll component stratixii_lvds_rx generic ( number_of_channels : natural; -- Required parameter deserialization_factor : natural; -- Required parameter enable_dpa_mode : string := "OFF"; data_align_rollover : natural := 10; lose_lock_on_one_change : string := "OFF"; reset_fifo_at_first_lock : string := "ON" ); port ( rx_in : in std_logic_vector(number_of_channels-1 downto 0); --Required port rx_fastclk : in std_logic; --Required port rx_enable : in std_logic := '1'; rx_locked : in std_logic; rx_reset : in std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); rx_dpll_hold : in std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); rx_dpll_enable : in std_logic_vector(number_of_channels-1 downto 0) := (others => '1'); rx_fifo_reset : in std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); rx_channel_data_align : in std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); rx_cda_reset : in std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); rx_out : out std_logic_vector(deserialization_factor*number_of_channels -1 downto 0); rx_dpa_locked : out std_logic_vector(number_of_channels-1 downto 0); rx_cda_max : out std_logic_vector(number_of_channels-1 downto 0) ); end component; -- stratixii_lvds_rx begin -- SIGNAL ASSIGNMENTS rx_out <= rx_out_rgd when (registered_output = "ON") else rx_out_int; rx_dpa_locked <= stratixii_dpa_locked when (STRATIXII_RX_STYLE = true) else (others => '1'); rx_out_int <= rx_in when (deserialization_factor = 1) else rx_ddio_in when (deserialization_factor = 2) else stratixii_dataout when (STRATIXII_RX_STYLE = true) else rx_hold_rgd when ((deserialization_factor = 4) and (STRATIX_RX_STYLE /= true) and (STRATIXGX_DPA_RX_STYLE /= true)) else rxpdatout when (STRATIXGX_DPA_RX_STYLE = true) else rx_out_extra_yeager_reg when (STRATIX_RX_STYLE = true) else data_out; rx_clock0_int <= rx_pll_clk0 when (deserialization_factor > 1) else rx_inclock; rx_clock1_int <= rx_pll_clk1 when (deserialization_factor > 2) else rx_inclock; rx_outclock <= rx_clock1_int; rx_locked <= rx_locked_int when (deserialization_factor > 2) else '1'; mercury_pll_clk0 <= mercury_pll_clk0_deser when ((inclock_boost = 0) and (MERCURY_RX_STYLE = true)) else mercury_pll_clk0_boost; mercury_pll_clk1 <= mercury_pll_clk1_deser when ((inclock_boost = 0) and (MERCURY_RX_STYLE = true)) else mercury_pll_clk1_boost; rx_pll_clk0 <= mercury_pll_clk0 when (MERCURY_RX_STYLE = true) else apexii_pll_clk0 when (APEXII_RX_STYLE = true) else yeager_clock(0) when (STRATIX_RX_STYLE = true) else aurora_clock(0) when (STRATIXGX_DPA_RX_STYLE = true) else stratixii_clock(0) when (STRATIXII_RX_STYLE = true) else apex20ke_pll_clk0; rx_pll_clk1 <= rx_mercury_slow_clock when (MERCURY_RX_STYLE = true) else apexii_pll_clk1 when (APEXII_RX_STYLE = true) else yeager_clock(2) when (STRATIX_RX_STYLE = true) else aurora_clock(2) when (STRATIXGX_DPA_RX_STYLE = true) else stratixii_clock(2) when (STRATIXII_RX_STYLE = true) else apex20ke_pll_clk1; mercury_locked_int <= mercury_locked_int_deser when ((inclock_boost = 0) and (MERCURY_RX_STYLE = true)) else mercury_locked_int_boost; rx_locked_int <= mercury_locked_int when (MERCURY_RX_STYLE = true) else apexii_locked_int when (APEXII_RX_STYLE = true) else yeager_locked_int when (STRATIX_RX_STYLE = true) else aurora_locked_int when (STRATIXGX_DPA_RX_STYLE = true) else stratixii_locked_int when (STRATIXII_RX_STYLE = true) else apex20ke_locked_int; rxpdat1 <= read_data when ((STRATIXGX_DPA_RX_STYLE = true) and (enable_dpa_fifo = "ON")) else serdes_data_out; write_data <= serdes_data_out; pclk <= clkout_tmp; stratixii_fastclk <= '0' when (STRATIXII_RX_STYLE = false) else rx_inclock when (use_external_pll = "ON") else rx_pll_sclkout0_dly; stratixii_enable <= '0' when (STRATIXII_RX_STYLE = false) else rx_enable when (use_external_pll = "ON") else rx_pll_enable0; rx_data_align_clk <= rx_clock1_int when ((STRATIX_RX_STYLE = true) or (STRATIXII_RX_STYLE = true)) else '0'; rx_data_align_wire <= rx_data_align when (rx_data_align /= 'Z') else '0'; rx_data_align_int <= rx_data_align_reg when (registered_data_align_input = "ON") else rx_data_align_wire; rx_channel_data_align_wire <= rx_channel_data_align when (rx_channel_data_align /= temp_z) else (others => rx_data_align_int ) when (STRATIXII_RX_STYLE = true) else (others => '0'); -- COMPONENT ASSIGNMENTS -- instantiation of the PLLs used by LVDS_RX -- altclklock used for APEX and Mercury families -- MF_stratix_pll used for Stratix and Stratix GX -- MF_stratixii_pll used for Stratix II APEX_PLL: if (APEX20KE_RX_STYLE = true) generate U0: altclklock -- APEX20KE PLL generic map ( inclock_period => inclock_period, clock0_boost => deserialization_factor, clock1_boost => deserialization_factor, clock1_divide => deserialization_factor, valid_lock_cycles => 5, intended_device_family => intended_device_family) port map ( inclock => rx_inclock, inclocken => rx_pll_enable, clock0 => apex20ke_pll_clk0, clock1 => apex20ke_pll_clk1, locked => apex20ke_locked_int ); end generate APEX_PLL; APEXII_PLL: if (APEXII_RX_STYLE = true) generate U0: altclklock -- APEX II PLL generic map ( inclock_period => inclock_period, clock0_boost => INT_CLOCK_BOOST, clock1_boost => INT_CLOCK_BOOST, clock1_divide => deserialization_factor, valid_lock_cycles => 1, intended_device_family => intended_device_family) port map ( inclock => rx_inclock, inclocken => rx_pll_enable, clock0 => apexii_pll_clk0, clock1 => apexii_pll_clk1, locked => apexii_locked_int ); end generate APEXII_PLL; MERCURY_NO_BOOST_PLL: if ((MERCURY_RX_STYLE = true) and (inclock_boost = 0)) generate U1: altclklock -- MERCURY PLL without inclock boost generic map ( inclock_period => inclock_period, clock0_boost => deserialization_factor, clock1_boost => 1, valid_lock_cycles => 3, intended_device_family => intended_device_family) port map ( inclock => rx_inclock, inclocken => rx_pll_enable, clock0 => mercury_pll_clk0_deser, clock1 => mercury_pll_clk1_deser, locked => mercury_locked_int_deser ); end generate MERCURY_NO_BOOST_PLL; MERCURY_PLL: if ((MERCURY_RX_STYLE = true) and (inclock_boost /= 0)) generate U2: altclklock -- MERCURY PLL with inclock_boost generic map ( inclock_period => inclock_period, clock0_boost => inclock_boost, clock1_boost => inclock_boost, clock1_divide => deserialization_factor, valid_lock_cycles => 3, intended_device_family => intended_device_family) port map ( inclock => rx_inclock, inclocken => rx_pll_enable, clock0 => mercury_pll_clk0_boost, clock1 => mercury_pll_clk1_boost, locked => mercury_locked_int_boost ); end generate MERCURY_PLL; STRATIX_PLL: if (STRATIX_RX_STYLE = true) generate U2: MF_stratix_pll -- STRATIX PLL generic map ( inclk0_input_frequency => inclock_period, inclk1_input_frequency => inclock_period, clk0_multiply_by => INT_CLOCK_BOOST, clk2_multiply_by => INT_CLOCK_BOOST, clk2_divide_by => deserialization_factor, clk0_phase_shift => PHASE_INCLOCK, clk2_phase_shift => PHASE_INCLOCK) port map ( inclk(0) => rx_inclock, inclk(1) => rx_inclock, ena => rx_pll_enable, areset => pll_areset, clkena(5 downto 0) => temp_high, comparator => rx_data_align_int, clk => yeager_clock, enable0 => rx_pll_enable0, enable1 => rx_pll_enable1, locked => yeager_locked_int ); end generate STRATIX_PLL; STRATIXGX_DPA_PLL: if (STRATIXGX_DPA_RX_STYLE = true) generate U2: MF_stratix_pll -- Stratix GX PLL generic map ( inclk0_input_frequency => inclock_period, inclk1_input_frequency => inclock_period, clk0_multiply_by => INT_CLOCK_BOOST, clk2_multiply_by => INT_CLOCK_BOOST, clk2_divide_by => deserialization_factor, clk0_phase_shift => "0", clk2_phase_shift => "0") port map ( inclk(0) => rx_inclock, inclk(1) => temp_zero, ena => rx_pll_enable, areset => pll_areset, clkena(5 downto 0) => temp_high, clk => aurora_clock, locked => aurora_locked_int); end generate STRATIXGX_DPA_PLL; STRATIXII_PLL: if ((STRATIXII_RX_STYLE = true) and (use_external_pll /= "ON")) generate U3: MF_stratixii_pll -- Stratix II PLL generic map ( vco_multiply_by => INT_CLOCK_BOOST, vco_divide_by => 1, inclk0_input_frequency => inclock_period, inclk1_input_frequency => inclock_period, clk0_multiply_by => INT_CLOCK_BOOST, clk0_divide_by => deserialization_factor, clk2_multiply_by => INT_CLOCK_BOOST, clk2_divide_by => deserialization_factor, clk0_phase_shift => PHASE_INCLOCK, clk2_phase_shift => PHASE_INCLOCK, sclkout0_phase_shift => PHASE_INCLOCK) port map ( inclk(0) => rx_inclock, inclk(1) => temp_zero, ena => rx_pll_enable, areset => pll_areset, clk => stratixii_clock, locked => stratixii_locked_int, enable0 => rx_pll_enable0, sclkout(0) => rx_pll_sclkout0, sclkout(1) => rx_pll_sclkout1); end generate STRATIXII_PLL; STRATIXII_LVDS_RECEIVER: if (STRATIXII_RX_STYLE = true) generate U4: stratixii_lvds_rx generic map ( number_of_channels => number_of_channels, deserialization_factor => deserialization_factor, enable_dpa_mode => enable_dpa_mode, data_align_rollover => data_align_rollover, lose_lock_on_one_change => lose_lock_on_one_change, reset_fifo_at_first_lock => reset_fifo_at_first_lock) port map ( rx_in => rx_in, rx_fastclk => stratixii_fastclk, rx_enable => stratixii_enable, rx_locked => stratixii_locked_int, rx_reset => rx_reset, rx_dpll_hold => rx_dpll_hold, rx_dpll_enable => rx_dpll_enable, rx_fifo_reset => rx_fifo_reset, rx_channel_data_align => rx_channel_data_align_wire, rx_cda_reset => rx_cda_reset, rx_out => stratixii_dataout, rx_dpa_locked => stratixii_dpa_locked, rx_cda_max => rx_cda_max); end generate STRATIXII_LVDS_RECEIVER; -- PROCESS DECLARATION STRATIXII_FCLK : process (rx_pll_sclkout0) begin rx_pll_sclkout0_dly <= rx_pll_sclkout0; end process; -- STRATIXII_FCLK process -- basic error checking for invalid deserialization factors MSG: process variable all_z : std_logic_vector(number_of_channels-1 downto 0) := (others =>'Z'); begin if (IS_VALID_FAMILY(intended_device_family) = false) then ASSERT FALSE REPORT intended_device_family & " is not a valid device family!" SEVERITY ERROR; elsif ((APEX20KE_RX_STYLE = true) and (deserialization_factor /= 4) and (deserialization_factor /= 7) and (deserialization_factor /= 8)) then ASSERT FALSE REPORT "APEX20KE does not support the specified deserialization factor!" SEVERITY ERROR; elsif ((MERCURY_RX_STYLE = true) and (((deserialization_factor > 12) and (deserialization_factor /= 14) and (deserialization_factor /= 16) and (deserialization_factor /= 18) and (deserialization_factor /= 20))or (deserialization_factor<3))) then ASSERT FALSE REPORT "MERCURY does not support the specified deserialization factor!" SEVERITY ERROR; elsif ((APEXII_RX_STYLE = true) and (deserialization_factor /= 1) and (deserialization_factor /= 2) and ((deserialization_factor > 10) or (deserialization_factor < 4))) then ASSERT FALSE REPORT "APEXII does not support the specified deserialization factor!" SEVERITY ERROR; elsif ((STRATIX_RX_STYLE = true) and ((deserialization_factor > 10) or (deserialization_factor < 4))) then ASSERT FALSE REPORT "Stratix and Stratix GX (non DPA mode) does not support the specified deserialization factor!" SEVERITY ERROR; elsif ((STRATIXGX_DPA_RX_STYLE = true) and (enable_dpa_mode = "ON") and (deserialization_factor /= 8) and (deserialization_factor /= 10)) then ASSERT FALSE REPORT "STRATIXGX in DPA mode does not support the specified deserialization factor!" SEVERITY ERROR; elsif ((STRATIXII_RX_STYLE = true) and ((deserialization_factor > 10) or (deserialization_factor < 4))) then ASSERT FALSE REPORT "STRATIXII does not support the specified deserialization factor!" SEVERITY ERROR; end if; if ((STRATIXII_RX_STYLE = true) and (rx_channel_data_align = all_z) and (rx_data_align /= 'Z')) then ASSERT FALSE REPORT "Data alignment on Stratix II devices introduces one bit of latency for each assertion of the data alignment signal. In comparison, Stratix and Stratix GX devices remove one bit of latency for each assertion." SEVERITY Warning; end if; wait; end process; -- MSG process -- For x2 mode, data input is sampled in both the rising edge and falling edge -- of input clock. DDIO_IN : process (rx_inclock) variable datain_latched : std_logic_vector(number_of_channels-1 downto 0) := (others =>'0'); begin if (deserialization_factor = 2) then if (rx_inclock'event and (rx_inclock = '1')) then for i in 0 to number_of_channels -1 loop rx_ddio_in((i*2)+1) <= rx_in(i); rx_ddio_in((i*2)) <= datain_latched(i); end loop; -- falling edge of inclock elsif (rx_inclock'event and (rx_inclock = '0')) then for i in 0 to number_of_channels -1 loop datain_latched(i) := rx_in(i); end loop; end if; end if; end process; -- DDIO_IN process -- generation of Mercury's outclock MERCURY_CLKOUT: process (rx_clock0_int, mercury_pll_clk1) variable posedge_count: integer := 0; begin if (MERCURY_RX_STYLE = true) then if (deserialization_factor rem 2 = 0) then rx_mercury_slow_clock <= mercury_pll_clk1; else if (mercury_pll_clk1'event and (mercury_pll_clk1 = '1')) then posedge_count := 0; rx_mercury_slow_clock <= mercury_pll_clk1; end if; if (rx_clock0_int'event and (rx_clock0_int = '1')) then posedge_count := posedge_count+1; end if; if (rx_clock0_int'event and (rx_clock0_int = '1') and (posedge_count=(deserialization_factor+1)/2+1)) then rx_mercury_slow_clock <= NOT rx_mercury_slow_clock; end if; end if; end if; end process; -- MERCURY_CLKOUT process -- Register the load enable signal for Stratix LOAD_ENABLE_PROC: process (rx_clock0_int) begin if (rx_clock0_int'event and (rx_clock0_int ='1') and (rx_clock0_int'last_value ='0')) then enable0_pipe <= enable0_reg; enable0_reg <= rx_pll_enable0; enable1_reg <= rx_pll_enable1; elsif (rx_clock0_int'event and (rx_clock0_int = '0') and (rx_clock0_int'last_value ='1')) then enable0_neg <= enable0_pipe; elsif (rx_clock0_int'event and (rx_clock0_int = 'X')) then enable0_pipe <= 'X'; enable0_reg <= 'X'; enable1_reg <= 'X'; enable0_neg <= 'X'; end if; end process; -- LOAD_ENABLE_PROC process -- the deserializer LOAD_DATA: process(rx_clock0_int, rx_clock1_int, rx_deskew) variable negedge_count : integer := 0; variable rxin_cnt : integer := 0; variable count : CHANNEL_CNT := (others => 0); variable sample : integer; variable start_data : integer := 0; variable init_deskew_pattern : boolean := true; variable check_deskew_pattern : boolean := false; variable deskew_pattern : std_logic_vector(deserialization_factor-1 downto 0); variable pattern : std_logic_vector(REGISTER_WIDTH -1 downto 0); variable data_int : std_logic_vector(REGISTER_WIDTH -1 downto 0) := (others => '0'); variable x : integer:=0; begin if deserialization_factor > 1 then -- At start up deskew is done due to inability to detect unconnected -- rx_deskew pin. Only for APEX families if (rx_deskew'event and (rx_deskew = '1') and ((APEX20KE_RX_STYLE = true) or (APEXII_RX_STYLE = true))) then deskew_done <= (others => '0'); calibrate <= (others => '1'); end if; if (rx_clock1_int'event and (rx_clock1_int = '1')) then if (rx_deskew = '0') then calibrate <= (others => '0'); end if; if ((STRATIX_RX_STYLE /= true) and (STRATIXGX_DPA_RX_STYLE /= true)) then negedge_count := 0; end if; -- Deskewing is only for APEX20KE/APEXII LVDS mode. -- Initialise calibration pattern variables. if (init_deskew_pattern = true) then init_deskew_pattern := false; if ((APEX20KE_RX_STYLE = true) and ((deserialization_factor = 4) or (deserialization_factor = 7) or (deserialization_factor = 8))) then check_deskew_pattern := true; case deserialization_factor is when 8 => deskew_pattern := "00111100"; when 7 => deskew_pattern := "0011100"; when 4 => deskew_pattern := "1100"; when others => ASSERT FALSE REPORT "APEX20KE does not support the specified deserialization factor!" SEVERITY ERROR; end case; elsif ((APEXII_RX_STYLE = true) and (deserialization_factor <= 10) and (deserialization_factor >= 4)) then check_deskew_pattern := true; if (cds_mode = "SINGLE_BIT") then case deserialization_factor is when 10 => deskew_pattern := "0000011111"; when 9 => deskew_pattern := "000001111"; when 8 => deskew_pattern := "00001111"; when 7 => deskew_pattern := "0000111"; when 6 => deskew_pattern := "000111"; when 5 => deskew_pattern := "00011"; when 4 => deskew_pattern := "0011"; when others => ASSERT FALSE REPORT "APEXII does not support the specified deserialization factor!" SEVERITY ERROR; end case; else case deserialization_factor is when 10 => deskew_pattern := "0101010101"; when 9 => deskew_pattern := "010101010"; when 8 => deskew_pattern := "01010101"; when 7 => deskew_pattern := "0101010"; when 6 => deskew_pattern := "010101"; when 5 => deskew_pattern := "01010"; when 4 => deskew_pattern := "0101"; when others => ASSERT FALSE REPORT "APEXII does not support the specified deserialization factor!" SEVERITY ERROR; end case; end if; else check_deskew_pattern := false; end if; end if; if (check_deskew_pattern = true) then for i in 0 to number_of_channels-1 loop if (calibrate(i) = '1') then if ((pattern(((deserialization_factor*(i+1))-1) downto deserialization_factor*i ) = deskew_pattern) or ((pattern(((deserialization_factor*(i+1))-1) downto deserialization_factor*i ) = not deskew_pattern) and (APEXII_RX_STYLE = true) and (cds_mode = "MULTIPLE_BIT"))) then count(i) := count(i) + 1; else count(i) := 0; end if; if (count(i) >= 3) then deskew_done(i) <= '1' after ((inclock_period/deserialization_factor)*2 ps); end if; end if; end loop; else deskew_done <= (others => '1'); end if; end if; if (rx_clock0_int'event and (rx_clock0_int = '0')) then negedge_count := negedge_count + 1; -- For APEX and Mercury families, load data on the -- 3rd negative edge of the fast clock if (negedge_count = 3) then if ((STRATIX_RX_STYLE /= true) and (STRATIXGX_DPA_RX_STYLE /= true) and (rx_deskew = '0')) then data_out <= data_int; end if; if (start_data = 0) then start_data := 1; rxin_cnt := 0; end if; end if; -- For Stratix and Stratix GX non-DPA mode, load data -- when the registered load enable signal is high if ((enable0_neg = '1') and (STRATIX_RX_STYLE = true)) then data_out <= data_int; sampling <= not sampling; end if; -- Deserialize the incoming bits if (start_data = 1) then sample := (rxin_cnt-2) mod deserialization_factor; rxin_cnt := rxin_cnt + 1; for i in 0 to number_of_channels -1 loop if (STRATIX_RX_STYLE = true) then for x in deserialization_factor-1 downto 1 loop -- Data gets shifted into MSB first. data_int(x + (i * deserialization_factor)) := data_int (x-1 + (i * deserialization_factor)); end loop; data_int(i * deserialization_factor) := rx_in(i); else if (deskew_done(i) = '1') then data_int((i+1)*deserialization_factor -sample -1) := rx_in(i); else if (APEXII_RX_STYLE = true) then for x in deserialization_factor-1 downto 1 loop pattern (x + (i * deserialization_factor)) := pattern (x-1 + (i * deserialization_factor)); end loop; pattern(i * deserialization_factor) := rx_in(i); data_int(i * deserialization_factor) := 'X'; else pattern((i+1)*deserialization_factor -sample -1) := rx_in(i); data_int((i+1)*deserialization_factor-sample -1) := 'X'; end if; end if; end if; end loop; end if; end if; if (rx_clock0_int'event and (rx_clock0_int = '1')) then start_data := 1; end if; else -- For deserialization factor = 1, data out = data in if (rx_clock1_int'event and (rx_clock1_int = '1')) then data_out <= rx_in; end if; end if; end process; -- LOAD_DATA process -- the parallel and hold registers PARALLEL_REG: process(rx_inclock, rx_clock1_int, rx_coreclk, enable1_reg) begin if ((STRATIXGX_DPA_RX_STYLE = true) and (use_coreclock_input = "ON")) then for i in 0 to number_of_channels -1 loop if ((rx_coreclk_pre(i) = '0') and (rx_coreclk(i) = '1')) then rx_out_rgd(deserialization_factor*(i+1) -1 downto deserialization_factor*i) <= rx_out_int(deserialization_factor*(i+1) -1 downto deserialization_factor*i); end if; rx_coreclk_pre(i) <= rx_coreclk(i); end loop; elsif ((STRATIXII_RX_STYLE = true) and (use_external_pll = "ON")) then if(rx_inclock'event and (rx_inclock = '1')) then rx_out_rgd <= rx_out_int; end if; elsif (rx_clock1_int'event and (rx_clock1_int = '1')) then rx_out_rgd <= rx_out_int; elsif (enable1_reg'event and (enable1_reg = '1')) then rx_out_extra_yeager_reg <= data_out; elsif (rx_clock1_int'event and (rx_clock1_int = '0') and ((deserialization_factor > 2) and (deserialization_factor < 7))) then rx_hold_rgd <= data_out; end if; end process; --PARALLEL_REG process DATA_ALIGN_REG: process(rx_data_align_clk) begin if (rx_data_align_clk'event and (rx_data_align_clk = '1')) then rx_data_align_reg <= rx_data_align_wire; end if; end process; --DATA_ALIGN_REG -- Stratix GX DPA internal model -- deserializer logic DPA_SERDES: process(rx_clock0_int, rx_clock1_int, rx_coreclk, rx_reset, rx_dpll_reset) variable negedge_count: CHANNEL_CNT := (others => 0); variable posedge_count: CHANNEL_CNT := (others => 0); variable fast_clk_count : CHANNEL_CNT := (others => deserialization_factor); variable data_int : std_logic_vector(REGISTER_WIDTH -1 downto 0) := (others => '0'); variable rx_in_pipe : std_logic_vector(number_of_channels -1 downto 0) := (others => '0'); begin if (STRATIXGX_DPA_RX_STYLE = true) then -- count the fast clock edge after the rising edge of the global slow -- clock in order to generate the parallel unload enable signal for i in 0 to number_of_channels -1 loop if (((use_coreclock_input = "ON") and (rx_coreclk_pre(i) = '0') and (rx_coreclk(i) = '1')) or ((use_coreclock_input = "OFF") and rx_clock1_int'event and (rx_clock1_int = '1'))) then negedge_count(i) := 0; posedge_count(i) := 0; if ((rx_reset(i) = '1') or (rx_dpll_reset(i) = '1')) then sync_reset(i) <= '1'; else sync_reset(i) <= '0'; end if; end if; rx_coreclk_pre(i) <= rx_coreclk(i); end loop; if (rx_clock0_int'event and (rx_clock0_int = '1')) then for i in 0 to number_of_channels -1 loop posedge_count(i) := posedge_count(i) + 1; -- load the parallel data when parallel unload enable signal goes high if (negedge_count(i) = 2) then serdes_data_out <= data_int; end if; if (sync_reset(i) = '1') then fast_clk_count(i) := deserialization_factor; clkout_tmp(i) <= '0'; else if (fast_clk_count(i) = deserialization_factor) then fast_clk_count(i) := 0; clkout_tmp(i) <= not clkout_tmp(i); elsif (fast_clk_count(i) = (deserialization_factor+1)/2) then clkout_tmp(i) <= not clkout_tmp(i); end if; fast_clk_count(i) := fast_clk_count(i) + 1; end if; end loop; end if; -- deserialize the incoming bits if (rx_clock0_int'event and (rx_clock0_int = '0')) then for i in 0 to number_of_channels -1 loop for x in deserialization_factor-1 downto 1 loop -- Data gets shifted into MSB first. data_int(x + (i * deserialization_factor)) := data_int (x-1 + (i * deserialization_factor)); end loop; data_int(i * deserialization_factor) := rx_in_pipe(i); rx_in_pipe(i) := rx_in(i); if (((use_coreclock_input = "ON") and (posedge_count(i) > 0)) or (use_coreclock_input = "OFF")) then negedge_count(i) := negedge_count(i) + 1; end if; end loop; end if; end if; end process; -- DPA_SERDES process -- phase compensation FIFO DPA_FIFO: process(pclk, rx_clock1_int, rx_coreclk) variable rd_index : CHANNEL_CNT := (others => 2); variable wr_index : CHANNEL_CNT := (others => 0); variable enable_fifo : boolean := false; variable clk0_posedge_count : integer := 0; begin -- enable the FIFO only when PLL locks if (rx_locked_int = '1') then enable_fifo := true; end if; if ((STRATIXGX_DPA_RX_STYLE = true) and (enable_fifo = true)) then -- Update write pointer and write data into the FIFO for i in 0 to number_of_channels-1 loop if ((pclk(i) = '1') and (pclk_pre(i) = '0')) then if (sync_reset(i) = '1') then wr_index(i) := 0; else ram_array(wr_index(i)) <= write_data; wr_index(i) := (wr_index(i) + 1) rem 4; end if; end if; pclk_pre(i) <= pclk(i); end loop; -- Read data from the FIFO and update read pointer for i in 0 to number_of_channels-1 loop if (((use_coreclock_input = "ON") and (rx_coreclk_pre(i) = '0') and (rx_coreclk(i) = '1')) or ((use_coreclock_input = "OFF") and (rx_clock1_int'event) and (rx_clock1_int = '1'))) then -- reset logic if ((rx_reset(i) = '1') or (rx_dpll_reset(i) = '1') or (sync_reset(i) = '1')) then read_data(deserialization_factor*(i+1) -1 downto deserialization_factor*i) <= (others => '0'); wr_index(i) := 0; rd_index(i) := 2; for j in 0 to 3 loop ram_array(j)(deserialization_factor*(i+1) -1 downto deserialization_factor*i) <= (others => '0'); end loop; else -- read data and update read pointer read_data(deserialization_factor*(i+1) -1 downto deserialization_factor*i) <= ram_array(rd_index(i))(deserialization_factor*(i+1) -1 downto deserialization_factor*i); rd_index(i) := (rd_index(i) + 1) rem 4; end if; end if; rx_coreclk_pre(i) <= rx_coreclk(i); end loop; end if; end process; -- DPA_FIFO process -- bit-slipping logic DPA_BIT_SLIP: process(rx_coreclk, rx_clock1_int, rx_channel_data_align) variable count: CHANNEL_CNT := (others => 0); variable count2: CHANNEL_CNT := (others => 0); variable count3: CHANNEL_CNT := (others => 0); begin if (STRATIXGX_DPA_RX_STYLE = true) then for i in 0 to number_of_channels-1 loop -- increment the number-of-bits-to-slip counter once for each rising edge of the bitslip control signal if (((use_coreclock_input = "ON") and (rx_coreclk_pre(i) = '0') and (rx_coreclk(i) = '1')) or ((use_coreclock_input = "OFF") and rx_clock1_int'event and (rx_clock1_int = '1'))) then count3(i) := count2(i); count2(i) := count(i); if ((rx_channel_data_align_pre(i) = '0') and (rx_channel_data_align(i) = '1')) then count(i) := (count(i) + 1) rem deserialization_factor; end if; rx_channel_data_align_pre(i) <= rx_channel_data_align(i); -- reset logic if ((rx_reset(i) = '1') or (rx_dpll_reset(i) = '1') or (sync_reset(i) = '1')) then rxpdat2(deserialization_factor*(i+1) -1 downto deserialization_factor*i) <= (others => '0'); rxpdat3(deserialization_factor*(i+1) -1 downto deserialization_factor*i) <= (others => '0'); count(i) := 0; count2(i) := 0; count3(i) := 0; rxpdatout(deserialization_factor*(i+1) -1 downto deserialization_factor*i) <= (others => '0'); else -- register the parallel data from either the FIFO or the SERDES rxpdat2 <= rxpdat1; rxpdat3 <= rxpdat2; -- select which bits to output to core from rxpdat2 and rxpdat3 registers -- the bitslip counter determines how many bits to skip from rxpdat3, and -- how many to take from rxpdat2 -- MSB of the registers is the earliest bit to enter, hence the MSB will -- be the first bit to be skipped case count3(i) is when 0 => rxpdatout(deserialization_factor*(i+1) -1 downto deserialization_factor*i) <= rxpdat3(deserialization_factor*(i+1) -1 downto deserialization_factor*i); --(RXPDAT3[8:0],RXPDAT2[9] when 1 => rxpdatout(deserialization_factor*(i+1) -1 downto deserialization_factor*i) <= rxpdat3(deserialization_factor*(i+1) -2 downto deserialization_factor*i) & rxpdat2(deserialization_factor*(i+1) -1); --(RXPDAT3[7:0],RXPDAT2[9:8] when 2 => rxpdatout(deserialization_factor*(i+1) -1 downto deserialization_factor*i) <= rxpdat3(deserialization_factor*(i+1) -3 downto deserialization_factor*i) & rxpdat2(deserialization_factor*(i+1) -1 downto deserialization_factor*(i+1) -2); --(RXPDAT3[6:0],RXPDAT2[9:7] when 3 => rxpdatout(deserialization_factor*(i+1) -1 downto deserialization_factor*i) <= rxpdat3(deserialization_factor*(i+1) -4 downto deserialization_factor*i) & rxpdat2(deserialization_factor*(i+1) -1 downto deserialization_factor*(i+1) -3); --(RXPDAT3[5:0],RXPDAT2[9:6] when 4 => rxpdatout(deserialization_factor*(i+1) -1 downto deserialization_factor*i) <= rxpdat3(deserialization_factor*(i+1) -5 downto deserialization_factor*i) & rxpdat2(deserialization_factor*(i+1) -1 downto deserialization_factor*(i+1) -4); --(RXPDAT3[4:0],RXPDAT2[9:5] when 5 => rxpdatout(deserialization_factor*(i+1) -1 downto deserialization_factor*i) <= rxpdat3(deserialization_factor*(i+1) -6 downto deserialization_factor*i) & rxpdat2(deserialization_factor*(i+1) -1 downto deserialization_factor*(i+1) -5); --(RXPDAT3[3:0],RXPDAT2[9:4] when 6 => rxpdatout(deserialization_factor*(i+1) -1 downto deserialization_factor*i) <= rxpdat3(deserialization_factor*(i+1) -7 downto deserialization_factor*i) & rxpdat2(deserialization_factor*(i+1) -1 downto deserialization_factor*(i+1) -6); --(RXPDAT3[2:0],RXPDAT2[9:3] when 7 => rxpdatout(deserialization_factor*(i+1) -1 downto deserialization_factor*i) <= rxpdat3(deserialization_factor*(i+1) -8 downto deserialization_factor*i) & rxpdat2(deserialization_factor*(i+1) -1 downto deserialization_factor*(i+1) -7); --(RXPDAT3[1:0],RXPDAT2[9:2] when 8 => rxpdatout(deserialization_factor*(i+1) -1 downto deserialization_factor*i) <= rxpdat3(deserialization_factor*(i+1) -9 downto deserialization_factor*i) & rxpdat2(deserialization_factor*(i+1) -1 downto deserialization_factor*(i+1) -8); --(RXPDAT3[0:0],RXPDAT2[9:1] when 9 => rxpdatout(deserialization_factor*(i+1) -1 downto deserialization_factor*i) <= rxpdat3(deserialization_factor*i) & rxpdat2(deserialization_factor*(i+1) -1 downto deserialization_factor*(i+1) -9); when others => rxpdatout(deserialization_factor*(i+1) -1 downto deserialization_factor*i) <= rxpdat3(deserialization_factor*(i+1) -1 downto deserialization_factor*i); end case; end if; end if; rx_coreclk_pre(i) <= rx_coreclk(i); end loop; end if; end process; -- DPA_BIT_SLIP process end behavior; -- END OF ARCHITECTURE ---START_ENTITY_HEADER--------------------------------------------------------- -- -- Entity Name : stratix_tx_outclk -- -- Description : This module is used to generate the tx_outclock for Stratix -- and stratix GX family. -- -- Limitation : Only available to Stratix and Stratix GX family. -- -- Results Expected: Output clock. -- ---END_ENTITY_HEADER----------------------------------------------------------- -- LIBRARY USED---------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; -- ENTITY DECLARATION entity stratix_tx_outclk is -- GENERIC DECLARATION generic ( deserialization_factor : natural; -- Required parameter bypass_serializer : boolean := FALSE; use_falling_clock_edge : boolean := FALSE ); -- PORT DECLARATION port ( --INPUT PORT DECLARATION tx_in : in std_logic_vector(deserialization_factor-1 downto 0); tx_fastclk : in std_logic; tx_enable : in std_logic := '1'; -- OUTPUT PORT DECLARATION tx_out : out std_logic := '0' ); end stratix_tx_outclk; -- END OF ENTITY -- BEGINNING OF ARCHITECTURE -- ARCHITECTURE DECLARATION architecture behavior of stratix_tx_outclk is -- SIGNAL DECLARATION -- constant signals signal enable1_reg0 : std_logic; signal enable1_reg1 : std_logic; signal enable1_reg2 : std_logic; signal tx_out_neg : std_logic := '0'; signal tx_shift_reg : std_logic_vector(deserialization_factor-1 downto 0) := (others => '0'); signal tx_parallel_load_reg : std_logic_vector(deserialization_factor-1 downto 0) := (others => '0'); begin -- SIGNAL ASSIGNMENTS tx_out <= tx_fastclk when (bypass_serializer = TRUE) else tx_out_neg when (use_falling_clock_edge = TRUE) else tx_shift_reg(deserialization_factor-1); -- PROCESS DECLARATION -- Register the load enable signal LOAD_ENABLE : process (tx_fastclk) begin if (tx_fastclk'event and (tx_fastclk ='1') and (tx_fastclk'last_value ='0')) then enable1_reg0 <= tx_enable; enable1_reg1 <= enable1_reg0; elsif (tx_fastclk'event and (tx_fastclk = '0') and (tx_fastclk'last_value ='1')) then enable1_reg2 <= enable1_reg1; elsif (tx_fastclk'event and (tx_fastclk = 'X')) then enable1_reg0 <= 'X'; enable1_reg1 <= 'X'; enable1_reg2 <= 'X'; end if; end process LOAD_ENABLE; -- LOAD_ENABLE process -- the deserializer FAST_CLOCK : process(tx_fastclk) begin if (tx_fastclk'event and (tx_fastclk = '0')) then -- Shift data from shift register to tx_out on negative edge of -- fast clock tx_out_neg <= tx_shift_reg(deserialization_factor-1); elsif (tx_fastclk'event and (tx_fastclk = '1')) then if (enable1_reg2 = '1') then tx_shift_reg <= tx_parallel_load_reg; else -- Shift data from shift register to tx_out on positive edge -- of fast clock for x in deserialization_factor-1 downto 1 loop tx_shift_reg(x) <= tx_shift_reg (x-1); end loop; end if; end if; tx_parallel_load_reg <= tx_in; end process FAST_CLOCK; end behavior; -- END OF ARCHITECTURE ---START_ENTITY_HEADER--------------------------------------------------------- -- -- Entity Name : stratixii_tx_outclk -- -- Description : This module is used to generate the tx_outclock for StratixII -- family. -- -- Limitation : Only available to Stratix II family. -- -- Results Expected: Output clock. -- ---END_ENTITY_HEADER----------------------------------------------------------- -- LIBRARY USED---------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; -- ENTITY DECLARATION entity stratixii_tx_outclk is -- GENERIC DECLARATION generic ( deserialization_factor : natural; -- Required parameter bypass_serializer : boolean := FALSE; use_falling_clock_edge : boolean := FALSE ); -- PORT DECLARATION port ( --INPUT PORT DECLARATION tx_in : in std_logic_vector(deserialization_factor-1 downto 0); tx_fastclk : in std_logic; tx_enable : in std_logic := '1'; -- OUTPUT PORT DECLARATION tx_out : out std_logic := '0' ); end stratixii_tx_outclk; -- END OF ENTITY -- BEGINNING OF ARCHITECTURE -- ARCHITECTURE DECLARATION architecture behavior of stratixii_tx_outclk is -- SIGNAL DECLARATION -- constant signals signal enable1_reg : std_logic := '0'; signal tx_out_neg : std_logic := '0'; signal tx_shift_reg : std_logic_vector(deserialization_factor-1 downto 0) := (others => '0'); signal tx_parallel_load_reg : std_logic_vector(deserialization_factor-1 downto 0) := (others => '0'); begin -- SIGNAL ASSIGNMENTS tx_out <= tx_fastclk when (bypass_serializer = TRUE) else tx_out_neg when (use_falling_clock_edge = TRUE) else tx_shift_reg(deserialization_factor-1); -- PROCESS DECLARATION -- the deserializer FAST_CLOCK : process(tx_fastclk) begin if (tx_fastclk'event and (tx_fastclk = '0')) then tx_out_neg <= tx_shift_reg(deserialization_factor-1); elsif (tx_fastclk'event and (tx_fastclk = '1')) then -- registering enable1 signal enable1_reg <= tx_enable; if (enable1_reg = '1') then tx_shift_reg <= tx_parallel_load_reg; else -- Shift data from shift register to tx_out for x in deserialization_factor-1 downto 1 loop tx_shift_reg(x) <= tx_shift_reg (x-1); end loop; end if; end if; tx_parallel_load_reg <= tx_in; end process FAST_CLOCK; end behavior; -- END OF ARCHITECTURE -- START ENTITY HEADER --------------------------------------------------------- -- -- Entity Name : altlvds_tx -- -- Description : Low Voltage Differential Signaling (LVDS) transmitter -- megafunction. The altlvds_tx megafunction implements a -- serialization transmitter. LVDS is a high speed IO interface -- that uses inputs without a reference voltage. LVDS uses two -- wires carrying differential values to create a single -- channel. These wires are connected to two pins on supported -- device to create a single LVDS channel. -- -- Limitations : Only available for APEX20KE, APEXII, MERCURY, Stratix and -- Stratix GX families. -- --Results expected : output clock, serialized output data and pll locked signal. -- END ENTITY HEADER ----------------------------------------------------------- -- LIBRARY USED----------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use work.ALTERA_DEVICE_FAMILIES.all; -- ENTITY DECLARATION entity altlvds_tx is generic ( -- Specifies the number of LVDS channels (required) number_of_channels : natural; -- Specifies the number of bits per channel (required) deserialization_factor : natural := 4; -- Indicates whether the tx_in[] and tx_outclock ports should be -- registered. Choices for STRATIX are ON, OFF, TX_CLKIN or TX_CORECLK registered_input : string := "ON"; -- "ON" means that sync_inclock is also used -- (not used for Stratix and Stratix GX.) multi_clock : string := "OFF"; -- Specifies the period of the input clock in ps (Required) inclock_period : natural := 10000; -- Specifies the period of the tx_outclock port as -- [INCLOCK_PERIOD * OUTCLOCK_DIVIDE_BY] outclock_divide_by : positive := 1; -- The effective clock period used to sample output data inclock_boost : natural := 0; -- Aligns the Most Significant Bit(MSB) to the falling edge of the -- clock instead of the rising edge (only for APEX II devices) center_align_msb : string := "OFF"; -- Specifies the device family to be used intended_device_family : string := "APEX20KE"; -- Specifies the data rate out of the PLL. -- (required and only for Stratix and Stratix GX devices) output_data_rate : natural := 0; -- Specifies the alignment of the input data with respect to the -- tx_inclock port. (required and only available for Stratix and -- Stratix GX devices) inclock_data_alignment : string := "EDGE_ALIGNED"; -- Specifies the alignment of the output data with respect to the -- tx_outclock port. (required and only available for Stratix and -- Stratix GX devices) outclock_alignment : string := "EDGE_ALIGNED"; -- Specifies whether the compiler uses the same PLL for both the LVDS -- receiver and the LVDS transmitter common_rx_tx_pll : string := "ON"; outclock_resource : string := "AUTO"; use_external_pll : string := "OFF"; preemphasis_setting : natural := 0; vod_setting : natural := 0; differential_drive : natural := 0; lpm_type : string := "altlvds_tx"; -- Specifies whether the source of the input clock is from the PLL clk_src_is_pll : string := "off" ); -- PORT DECLARATION port ( -- INPUT PORT DECLARATION -- Input data (required) tx_in : in std_logic_vector(deserialization_factor* number_of_channels -1 downto 0); -- Input clock (required) tx_inclock : in std_logic; tx_enable : in std_logic := '1'; -- Optional clock for input registers (Required if "multi_clock" -- parameters is turned on) sync_inclock : in std_logic := '0'; -- Enable control for the LVDS PLL tx_pll_enable : in std_logic := '1'; -- Asynchronously resets all counters to initial values (only for --Stratix and Stratix GX devices) pll_areset : in std_logic := '0'; -- OUTPUT PORT DECLARATION -- Serialized data signal(required) tx_out : out std_logic_vector(number_of_channels-1 downto 0) := (others => '0'); -- External reference clock tx_outclock : out std_logic; -- Output clock used to feed non-peripheral logic. -- Only available for Mercury, Stratix, and Stratix GX devices only. tx_coreclock : out std_logic; -- Gives the status of the LVDS PLL -- (when the PLL is locked, this signal is VCC. GND otherwise) tx_locked : out std_logic ); end altlvds_tx; -- END OF ENTITY -- BEGINNING OF ARCHITECTURE -- ARCHITECTURE DECLARATION architecture behavior of altlvds_tx is -- FUNCTION DECLARATION -- clock_boost_calc calculates the multiply_by factor for the PLL clocks -- used by LVDS_TX function clock_boost_calc (constant i_input_data_rate, i_inclock_period, i_deserialization_factor, i_inclock_boost : in natural) return natural is variable i_input_clock_boost: natural := 1; begin if ((i_input_data_rate /= 0) and (i_inclock_period /= 0)) then i_input_clock_boost := ((i_input_data_rate * i_inclock_period) + (5* 100000)) / 1000000; else if (inclock_boost = 0) then i_input_clock_boost := i_deserialization_factor; else i_input_clock_boost := i_inclock_boost; end if; end if; return i_input_clock_boost; end clock_boost_calc; -- int_to_str converts an integer to a string. This is mainly used for -- converting the calculated phase shift to a string as required by altpll function int_to_str(constant value : integer ) return string is variable ivalue : integer := 0; variable index : integer := 0; variable strlen : integer := 0; variable digit : integer := 0; variable str : string(1 to 8) := "00000000"; begin ivalue := value; strlen := 0; while (ivalue > 0) loop ivalue := ivalue/10; strlen := strlen + 1; end loop; if (strlen = 0) then strlen := 1; end if; ivalue := value; index := strlen; while (ivalue > 0) loop digit := ivalue mod 10; ivalue := ivalue / 10; case digit is when 0 => str(index) := '0'; when 1 => str(index) := '1'; when 2 => str(index) := '2'; when 3 => str(index) := '3'; when 4 => str(index) := '4'; when 5 => str(index) := '5'; when 6 => str(index) := '6'; when 7 => str(index) := '7'; when 8 => str(index) := '8'; when 9 => str(index) := '9'; when others => ASSERT FALSE REPORT "Illegal number!" SEVERITY ERROR; end case; index := index - 1; end loop; return str(1 to strlen); end int_to_str; -- get_phase_delay calculates the phase shift for each PLL clock as -- determined by the INCLOCK_DATA_ALIGNMENT parameter function get_phase_delay (constant i_phase_delay : in string) return integer is variable my_phase : integer := 0; variable x : integer := 0; variable int_delay : integer := 0; begin -- returns the delay in ps -- ( * inclock period / 360 degress) if (i_phase_delay = "EDGE_ALIGNED") then my_phase := 0; -- CENTER_ALIGNED means 180 degrees elsif (i_phase_delay = "CENTER_ALIGNED") then my_phase := (180 * inclock_period) / 360; elsif (i_phase_delay = "45_DEGREES") then my_phase := (45 * inclock_period) / 360; elsif (i_phase_delay = "90_DEGREES") then my_phase := (90 * inclock_period) / 360; elsif (i_phase_delay = "135_DEGREES") then my_phase := (135 * inclock_period) / 360; elsif (i_phase_delay = "180_DEGREES") then my_phase := (180 * inclock_period) / 360; elsif (i_phase_delay = "225_DEGREES") then my_phase := (225 * inclock_period) / 360; elsif (i_phase_delay = "270_DEGREES") then my_phase := (270 * inclock_period) / 360; elsif (i_phase_delay = "315_DEGREES") then my_phase := (315 * inclock_period) / 360; else ASSERT FALSE REPORT "Invalid clock data alignment. Using 'EDGE_ALIGNED' instead" SEVERITY WARNING; my_phase := 0; end if; -- add 1 to "round up" the calculation result my_phase := my_phase + 1; -- phase shift = ( * inclock_period / 360 ) / (fast -- clock multiply_by factor) -- in other words, the data alignment phase shift is a percentage of the -- fast clock period int_delay := my_phase / clock_boost_calc(output_data_rate, inclock_period, deserialization_factor, inclock_boost); -- add 1 to "round up" the calculation result int_delay := int_delay + 1; return (int_delay); end get_phase_delay; -- get_outclock_phase_delay calculates the phase shift for the outclock port -- as determined by the OUTCLOCK_ALIGNMENT parameter function get_outclock_phase_delay (constant i_phase_delay : in string) return string is variable my_phase : integer := 0; variable x : integer := 0; variable int_delay : integer := 0; begin -- returns the delay in ps -- ( * inclock period / 360 degress ) if (i_phase_delay = "EDGE_ALIGNED") then my_phase := 0; -- CENTER_ALIGNED means 180 degrees elsif (i_phase_delay = "CENTER_ALIGNED") then my_phase := (180 * inclock_period) / 360; elsif (i_phase_delay = "45_DEGREES") then my_phase := (45 * inclock_period) / 360; elsif (i_phase_delay = "90_DEGREES") then my_phase := (90 * inclock_period) / 360; elsif (i_phase_delay = "135_DEGREES") then my_phase := (135 * inclock_period) / 360; elsif (i_phase_delay = "180_DEGREES") then my_phase := (180 * inclock_period) / 360; elsif (i_phase_delay = "225_DEGREES") then my_phase := (225 * inclock_period) / 360; elsif (i_phase_delay = "270_DEGREES") then my_phase := (270 * inclock_period) / 360; elsif (i_phase_delay = "315_DEGREES") then my_phase := (315 * inclock_period) / 360; else ASSERT FALSE REPORT "Invalid outclock alignment. Using 'EDGE_ALIGNED' instead" SEVERITY WARNING; my_phase := 0; end if; -- add 1 to "round up" calculation result my_phase := my_phase + 1; my_phase := my_phase / clock_boost_calc (output_data_rate, inclock_period, deserialization_factor, inclock_boost); -- add 1 to "round up" calculation result my_phase := my_phase + 1; int_delay := my_phase + get_phase_delay(inclock_data_alignment); return int_to_str (int_delay); end get_outclock_phase_delay; -- Calculates the phase shift of the fastclk that feeds the -- stratix_tx_outclk or stratixii_tx_outclk. function get_lvds_outclock_phase_delay (constant i_phase_delay : in string; constant i_outclock_divide_by : in positive; constant i_intended_device_family : in string) return string is variable my_phase : integer := 0; begin if ((i_outclock_divide_by = 1) or (i_phase_delay = "45_DEGREES") or (i_phase_delay = "90_DEGREES") or (i_phase_delay = "135_DEGREES")) then return get_outclock_phase_delay(i_phase_delay); elsif ((i_phase_delay = "180_DEGREES") or (i_phase_delay = "CENTER_ALIGNED")) then return int_to_str(get_phase_delay(inclock_data_alignment)); elsif (i_phase_delay = "225_DEGREES") then return get_outclock_phase_delay("45_DEGREES"); elsif (i_phase_delay = "270_DEGREES") then return get_outclock_phase_delay("90_DEGREES"); elsif (i_phase_delay = "315_DEGREES") then return get_outclock_phase_delay("135_DEGREES"); else return int_to_str(get_phase_delay(inclock_data_alignment)); end if; end get_lvds_outclock_phase_delay; -- CONSTANT DECLARATION -- these constants are PLL parameters calculated from the altlvds_tx -- parameters given constant PHASE_INCLOCK : string := int_to_str(get_phase_delay(inclock_data_alignment)); constant PHASE_OUTCLOCK : string := get_lvds_outclock_phase_delay(outclock_alignment, outclock_divide_by, intended_device_family); constant INT_CLOCK_BOOST : natural := clock_boost_calc(output_data_rate, inclock_period, deserialization_factor, inclock_boost); constant REGISTER_WIDTH : natural := deserialization_factor * number_of_channels; constant APEX20KE_TX_STYLE : boolean := IS_FAMILY_APEX20KE(intended_device_family); constant APEXII_TX_STYLE : boolean := IS_FAMILY_APEXII(intended_device_family); constant MERCURY_TX_STYLE : boolean := IS_FAMILY_MERCURY(intended_device_family); constant STRATIX_TX_STYLE : boolean := IS_FAMILY_STRATIX(intended_device_family) or IS_FAMILY_STRATIXGX(intended_device_family); constant STRATIXII_TX_STYLE : boolean := IS_FAMILY_STRATIXII(intended_device_family); constant TX_NEED_HOLD_REG : boolean := (((APEX20KE_TX_STYLE = true) and (deserialization_factor >= 7)) or ((APEXII_TX_STYLE = true) and (deserialization_factor >= 5)) or ((MERCURY_TX_STYLE = true) and (deserialization_factor >= 7))); constant BYPASS_NEEDED : boolean := (outclock_divide_by = 1); constant FALLING_CLOCK_EDGE_NEEDED : boolean := (outclock_alignment = "180_DEGREES") or (outclock_alignment = "CENTER_ALIGNED") or (outclock_alignment = "225_DEGREES") or (outclock_alignment = "270_DEGREES") or (outclock_alignment = "315_DEGREES"); -- SIGNAL DECLARATION -- registers signal tx_hold_reg : std_logic_vector(REGISTER_WIDTH -1 downto 0) := (others => '0'); signal tx_in_reg : std_logic_vector(REGISTER_WIDTH -1 downto 0) := (others => '0'); signal tx_in_int : std_logic_vector(REGISTER_WIDTH -1 downto 0) := (others => '0'); signal tx_parallel_load_reg : std_logic_vector(REGISTER_WIDTH -1 downto 0) := (others => '0'); signal dataout_l : std_logic_vector(number_of_channels -1 downto 0) := (others => '0'); signal dataout_h : std_logic_vector(number_of_channels -1 downto 0) := (others => '0'); signal tx_ddio_out : std_logic_vector(number_of_channels -1 downto 0) := (others => '0'); signal tx_out_stratix : std_logic_vector(number_of_channels -1 downto 0) := (others => '0'); signal tx_out_apex : std_logic_vector(number_of_channels -1 downto 0) := (others => '0'); signal stx_phase_shift_txdata : std_logic_vector(deserialization_factor -1 downto 0) := (others => '0'); signal phase_shift_txdata : std_logic_vector(deserialization_factor -1 downto 0) := (others => '0'); -- clock signals signal tx_fastclk : std_logic; -- fast clock signal tx_slowclk : std_logic; -- slow clock signal tx_pll_clk0 : std_logic; -- PLL clk0 output signal tx_pll_clk1 : std_logic; -- PLL clk1 output signal tx_pll_clk2 : std_logic; -- PLL clk2 output signal tx_mercury_core_clock : std_logic; signal tx_reg_clk : std_logic; -- clock for sync register signal tx_hold_clk : std_logic; -- clock for hold register signal tx_coreclk_int : std_logic; signal tx_pll_sclkout : std_logic_vector (1 downto 0) := (others => '0'); -- PLL serial clk output signal stratix_inclock : std_logic := '0'; signal stratixii_inclock : std_logic := '0'; signal stratix_outclock : std_logic := '0'; signal stratixii_outclock : std_logic := '0'; -- PLL locked signal signal tx_locked_int : std_logic; -- constant signals signal temp_zero : std_logic := '0'; signal temp_high : std_logic_vector (5 downto 0) := (others => '1'); signal temp_clk : std_logic_vector (3 downto 1) := (others => '0'); -- load enable signals for Stratix, Stratix GX and Stratix II signal tx_pll_enable0 : std_logic := '0'; signal tx_pll_enable1 : std_logic := '0'; signal enable0 : std_logic := '0'; signal enable0_reg : std_logic := '0'; signal enable0_pipe : std_logic := '0'; signal enable0_neg : std_logic := '0'; signal stratix_enable : std_logic := '0'; signal stratixii_enable : std_logic := '0'; -- COMPONENT DECLARATION -- PLL for device family other than Stratix, Stratx GX and Stratix II component altclklock generic ( inclock_period : natural := 10000; --Required clock0_boost : natural := 1; clock1_boost : natural := 1; clock1_divide : natural := 1; clock2_boost : natural := 1; clock2_divide : natural := 1; valid_lock_cycles : natural := 5; intended_device_family : string := "APEX20KE"; clock0_time_delay : string := "0"; clock1_time_delay : string := "0" ); port ( inclock : in std_logic; inclocken : in std_logic := '1'; clock0 : out std_logic; clock1 : out std_logic; clock2 : out std_logic; locked : out std_logic ); end component; -- altclklock -- PLL for Stratix and Stratix GX component MF_stratix_pll generic ( pll_type : string := "lvds"; inclk0_input_frequency : positive ; --Required valid_lock_multiplier : integer := 1; simulation_type : string := "functional"; clk0_multiply_by : positive := 1; clk0_divide_by : positive := 1; clk0_phase_shift : string := "0"; clk1_multiply_by : positive := 1; clk1_divide_by : positive := 1; clk1_phase_shift : string := "0"; clk2_multiply_by : positive := 1; clk2_divide_by : positive := 1; clk2_phase_shift : string := "0"; m : integer := 0); port ( inclk : in std_logic_vector(1 downto 0) := (others => '0'); fbin : in std_logic := '1'; ena : in std_logic := '1'; clkswitch : in std_logic := '0'; areset : in std_logic := '0'; pfdena : in std_logic := '1'; clkena : in std_logic_vector(5 downto 0) := (others => '1'); extclkena : in std_logic_vector(3 downto 0) := (OTHERS=>'1'); scanaclr : in std_logic := '0'; scandata : in std_logic := '0'; scanclk : in std_logic := '0'; comparator : in std_logic := '0'; clk : out std_logic_vector(5 downto 0); locked : out std_logic; enable0 : out std_logic; enable1 : out std_logic); end component; -- MF_stratix_pll -- PLL for Stratix II component MF_stratixii_pll generic ( pll_type : string := "lvds"; vco_multiply_by : integer := 0; vco_divide_by : integer := 0; inclk0_input_frequency : positive ; --Required simulation_type : string := "functional"; clk0_multiply_by : positive := 1; clk0_divide_by : positive := 1; clk0_phase_shift : string := "0"; clk1_multiply_by : positive := 1; clk1_divide_by : positive := 1; clk1_phase_shift : string := "0"; clk2_multiply_by : positive := 1; clk2_divide_by : positive := 1; clk2_phase_shift : string := "0"; sclkout0_phase_shift : string := "0"; sclkout1_phase_shift : string := "0"; m : integer := 0); port ( inclk : in std_logic_vector(1 downto 0) := (others => '0'); fbin : in std_logic := '1'; ena : in std_logic := '1'; clkswitch : in std_logic := '0'; areset : in std_logic := '0'; pfdena : in std_logic := '1'; scanread : in std_logic := '0'; scanwrite : in std_logic := '0'; scandata : in std_logic := '0'; scanclk : in std_logic := '0'; clk : out std_logic_vector(5 downto 0); locked : out std_logic; enable0 : out std_logic; enable1 : out std_logic; sclkout : out std_logic_vector(1 downto 0) ); end component; -- MF_stratixii_pll component stratix_tx_outclk generic ( deserialization_factor : natural; -- Required parameter bypass_serializer : boolean := FALSE; use_falling_clock_edge : boolean := FALSE ); port ( tx_in : in std_logic_vector(deserialization_factor-1 downto 0); tx_fastclk : in std_logic; tx_enable : in std_logic := '1'; tx_out : out std_logic := '0' ); end component; -- stratix_tx_outclk component stratixii_tx_outclk generic ( deserialization_factor : natural; -- Required parameter bypass_serializer : boolean := FALSE; use_falling_clock_edge : boolean := FALSE ); port ( tx_in : in std_logic_vector(deserialization_factor-1 downto 0); tx_fastclk : in std_logic; tx_enable : in std_logic := '1'; tx_out : out std_logic := '0' ); end component; -- stratixii_tx_outclk begin -- SIGNAL ASSIGNMENTS tx_out <= tx_in_int when (deserialization_factor = 1) else tx_ddio_out when (deserialization_factor = 2) else tx_out_stratix when ((STRATIX_TX_STYLE = true) or (STRATIXII_TX_STYLE = true)) else tx_out_apex; tx_in_int <= tx_in_reg when (registered_input /= "OFF") else tx_in; tx_fastclk <= '0' when (deserialization_factor < 3) else tx_inclock when (use_external_pll = "ON") else tx_pll_sclkout(0) when (STRATIXII_TX_STYLE = true) else tx_pll_clk0; tx_slowclk <= '0' when ((use_external_pll = "ON") or (deserialization_factor < 3)) else tx_pll_clk2 when ((STRATIX_TX_STYLE = true) or (STRATIXII_TX_STYLE = true)) else tx_pll_clk1; tx_outclock <= stratixii_outclock when (STRATIXII_TX_STYLE = true) else tx_pll_clk2 when (MERCURY_TX_STYLE = true) else stratix_outclock when (STRATIX_TX_STYLE = true) else tx_inclock when (APEXII_TX_STYLE = true) else tx_slowclk; tx_coreclk_int <= tx_mercury_core_clock when (((deserialization_factor rem 2)/=0) and (MERCURY_TX_STYLE = true)) else tx_slowclk; tx_coreclock <= tx_coreclk_int; tx_reg_clk <= tx_inclock when (use_external_pll = "ON") else sync_inclock when (registered_input = "ON") and (multi_clock = "ON") and (STRATIX_TX_STYLE = false) and (STRATIXII_TX_STYLE = false) else tx_coreclk_int when (registered_input = "TX_CORECLK") and ((STRATIX_TX_STYLE = true) or (STRATIXII_TX_STYLE = true)) else tx_inclock; tx_hold_clk <= sync_inclock when (multi_clock = "ON") else tx_coreclk_int when (MERCURY_TX_STYLE = true) else tx_inclock; tx_locked <= tx_locked_int when (deserialization_factor > 2) else '1'; enable0 <= tx_enable when (use_external_pll = "ON") else tx_pll_enable0; stratix_inclock <= '0' when (STRATIX_TX_STYLE = false) else tx_pll_clk1; stratix_enable <= '0' when (STRATIX_TX_STYLE = false) else tx_pll_enable1; stratixii_inclock <= '0' when (STRATIXII_TX_STYLE = false) else tx_inclock when (use_external_pll = "ON") else tx_pll_sclkout(1); stratixii_enable <= '0' when (STRATIXII_TX_STYLE = false) else tx_enable when (use_external_pll = "ON") else tx_pll_enable1; -- COMPONENT ASSIGNMENTS -- PLL instantiations -- altclklock used for APEX and Mercury families -- MF_stratix_pll used for Stratix and Stratix GX -- MF_stratixii_pll used for Stratix II APEX_PLL: if (APEX20KE_TX_STYLE = true) generate u0 : altclklock -- APEX20KE PLL generic map ( inclock_period => inclock_period, clock0_boost => deserialization_factor, clock1_boost => 1, valid_lock_cycles => 5, intended_device_family => intended_device_family) port map ( inclock => tx_inclock, inclocken => tx_pll_enable, clock0 => tx_pll_clk0, clock1 => tx_pll_clk1, locked => tx_locked_int ); end generate APEX_PLL; APEXII_PLL: if (APEXII_TX_STYLE = true) generate u0 : altclklock -- APEX II PLL generic map ( inclock_period => inclock_period, clock0_boost => INT_CLOCK_BOOST, clock1_boost => INT_CLOCK_BOOST, clock1_divide => deserialization_factor, valid_lock_cycles => 1, intended_device_family => intended_device_family) port map ( inclock => tx_inclock, inclocken => tx_pll_enable, clock0 => tx_pll_clk0, clock1 => tx_pll_clk1, locked => tx_locked_int ); end generate APEXII_PLL; MERCURY_NO_BOOST_PLL: if ((MERCURY_TX_STYLE = true) and (inclock_boost = 0)) generate u1 : altclklock -- MERCURY PLL with inclock boost = 0 generic map ( inclock_period => inclock_period, clock0_boost => deserialization_factor, clock1_boost => 1, clock2_boost => deserialization_factor, clock2_divide => outclock_divide_by, valid_lock_cycles => 3, intended_device_family => intended_device_family) port map ( inclock => tx_inclock, inclocken => tx_pll_enable, clock0 => tx_pll_clk0, clock1 => tx_pll_clk1, clock2 => tx_pll_clk2, locked => tx_locked_int ); end generate MERCURY_NO_BOOST_PLL; MERCURY_PLL: if ((MERCURY_TX_STYLE = true) and (inclock_boost /= 0)) generate u2: altclklock -- MERCURY PLL with inclock boost generic map ( inclock_period => inclock_period, clock0_boost => inclock_boost, clock1_boost => inclock_boost, clock1_divide => deserialization_factor, clock2_boost => inclock_boost, clock2_divide => outclock_divide_by, valid_lock_cycles => 3, intended_device_family => intended_device_family) port map ( inclock => tx_inclock, inclocken => tx_pll_enable, clock0 => tx_pll_clk0, clock1 => tx_pll_clk1, clock2 => tx_pll_clk2, locked => tx_locked_int ); end generate MERCURY_PLL; STRATIX_PLL: if (STRATIX_TX_STYLE = true) generate u2: MF_stratix_pll -- STRATIX PLL generic map ( inclk0_input_frequency => inclock_period, clk0_multiply_by => INT_CLOCK_BOOST, clk0_divide_by => 1, clk0_phase_shift => PHASE_INCLOCK, clk1_multiply_by => INT_CLOCK_BOOST, clk1_divide_by => 1, clk1_phase_shift => PHASE_OUTCLOCK, clk2_multiply_by => INT_CLOCK_BOOST, clk2_divide_by => deserialization_factor, clk2_phase_shift => PHASE_INCLOCK ) port map ( inclk(0) => tx_inclock, inclk(1) => temp_zero, ena => tx_pll_enable, areset => pll_areset, clkena(5 downto 0) => temp_high, clk(0) => tx_pll_clk0, clk(1) => tx_pll_clk1, clk(2) => tx_pll_clk2, clk (5 downto 3) => temp_clk, locked => tx_locked_int, enable0 => tx_pll_enable0, enable1 => tx_pll_enable1); end generate STRATIX_PLL; STRATIXII_PLL: if ((STRATIXII_TX_STYLE = true) and (use_external_pll /= "ON")) generate u2: MF_stratixii_pll -- STRATIX II PLL generic map ( vco_multiply_by => INT_CLOCK_BOOST, vco_divide_by => 1, inclk0_input_frequency => inclock_period, clk0_multiply_by => INT_CLOCK_BOOST, clk0_divide_by => deserialization_factor, clk0_phase_shift => PHASE_INCLOCK, clk1_multiply_by => INT_CLOCK_BOOST, clk1_divide_by => deserialization_factor, clk1_phase_shift => PHASE_OUTCLOCK, clk2_multiply_by => INT_CLOCK_BOOST, clk2_divide_by => deserialization_factor, clk2_phase_shift => PHASE_INCLOCK, sclkout0_phase_shift => PHASE_INCLOCK, sclkout1_phase_shift => PHASE_OUTCLOCK ) port map ( inclk(0) => tx_inclock, inclk(1) => temp_zero, ena => tx_pll_enable, areset => pll_areset, clk(0) => tx_pll_clk0, clk(1) => tx_pll_clk1, clk(2) => tx_pll_clk2, clk (5 downto 3) => temp_clk, locked => tx_locked_int, enable0 => tx_pll_enable0, enable1 => tx_pll_enable1, sclkout(0) => tx_pll_sclkout(0), sclkout(1) => tx_pll_sclkout(1)); end generate STRATIXII_PLL; STRATIX_OUTCLK : if (STRATIX_TX_STYLE = true) generate u3: stratix_tx_outclk generic map ( deserialization_factor => deserialization_factor, bypass_serializer => BYPASS_NEEDED, use_falling_clock_edge => FALLING_CLOCK_EDGE_NEEDED ) port map ( tx_in => stx_phase_shift_txdata, tx_fastclk => stratix_inclock, tx_enable => stratix_enable, tx_out => stratix_outclock); end generate STRATIX_OUTCLK; STRATIXII_OUTCLK : if (STRATIXII_TX_STYLE = true) generate u3: stratixii_tx_outclk generic map ( deserialization_factor => deserialization_factor, bypass_serializer => BYPASS_NEEDED, use_falling_clock_edge => FALLING_CLOCK_EDGE_NEEDED ) port map ( tx_in => phase_shift_txdata, tx_fastclk => stratixii_inclock, tx_enable => stratixii_enable, tx_out => stratixii_outclock); end generate STRATIXII_OUTCLK; -- PROCESS DECLARATION INITIAL : process begin -- basic error checking for invalid deserialization factors if (IS_VALID_FAMILY(intended_device_family) = false) then ASSERT FALSE REPORT intended_device_family & " is not a valid device family!" SEVERITY ERROR; elsif (APEX20KE_TX_STYLE = true) and (deserialization_factor /= 4) and (deserialization_factor /= 7) and (deserialization_factor /= 8) then ASSERT FALSE REPORT "APEX20KE does not support the specified deserialization factor!" SEVERITY ERROR; elsif (MERCURY_TX_STYLE = true) and (((deserialization_factor > 12) and (deserialization_factor /= 14) and (deserialization_factor /= 16) and (deserialization_factor /= 18) and (deserialization_factor /= 20)) or (deserialization_factor < 3)) then ASSERT FALSE REPORT "MERCURY does not support the specified deserialization factor!" SEVERITY ERROR; elsif ((APEXII_TX_STYLE = true) and (deserialization_factor /= 1) and (deserialization_factor /= 2) and ((deserialization_factor > 10) or (deserialization_factor < 4))) then ASSERT FALSE REPORT "APEXII does not support the specified deserialization factor!" SEVERITY ERROR; elsif ((STRATIX_TX_STYLE = true) and ((deserialization_factor > 10) or (deserialization_factor < 4))) then ASSERT FALSE REPORT "Stratix and Stratix GX does not support the specified deserialization factor!" SEVERITY ERROR; elsif ((STRATIXII_TX_STYLE = true) and ((deserialization_factor > 10) or (deserialization_factor < 4))) then ASSERT FALSE REPORT "Stratix II does not support the specified deserialization factor!" SEVERITY ERROR; end if; -- Input data needed by stratix_tx_outclk in order to generate the tx_outclock. if (outclock_divide_by > 1) then if (deserialization_factor = 4) then if ( outclock_divide_by = 2) then stx_phase_shift_txdata <= "1010"; elsif (outclock_divide_by = 4) then stx_phase_shift_txdata <= "0011"; end if; elsif (deserialization_factor = 8) then if (outclock_divide_by = 2) then stx_phase_shift_txdata <= "10101010"; elsif (outclock_divide_by = 4) then stx_phase_shift_txdata <= "00110011"; elsif (outclock_divide_by = 8) then stx_phase_shift_txdata <= "11000011"; end if; elsif (deserialization_factor = 10) then if (outclock_divide_by = 2) then stx_phase_shift_txdata <= "1010101010"; elsif (outclock_divide_by = 10) then stx_phase_shift_txdata <= "1110000011"; end if; elsif (deserialization_factor = 7) then if (outclock_divide_by = 7) then stx_phase_shift_txdata <= "1100011"; end if; end if; end if; -- Input data needed by stratixii_tx_outclk in order to generate the tx_outclock. if (outclock_divide_by > 1) then if (deserialization_factor = 4) then if ( outclock_divide_by = 2) then phase_shift_txdata <= "1010"; elsif (outclock_divide_by = 4) then phase_shift_txdata <= "1100"; end if; elsif (deserialization_factor = 6) then if ( outclock_divide_by = 2) then phase_shift_txdata <= "101010"; elsif (outclock_divide_by = 6) then phase_shift_txdata <= "111000"; end if; elsif (deserialization_factor = 8) then if (outclock_divide_by = 2) then phase_shift_txdata <= "10101010"; elsif (outclock_divide_by = 4) then phase_shift_txdata <= "11001100"; elsif (outclock_divide_by = 8) then phase_shift_txdata <= "11110000"; end if; elsif (deserialization_factor = 10) then if (outclock_divide_by = 2) then phase_shift_txdata <= "1010101010"; elsif (outclock_divide_by = 10) then phase_shift_txdata <= "1111100000"; end if; elsif (deserialization_factor = 7) then if (outclock_divide_by = 7) then phase_shift_txdata <= "1111000"; end if; end if; end if; wait; end process; -- INITIAL process DDIO_OUT_RECEIVE : process (tx_inclock) begin if (deserialization_factor = 2) then if (tx_inclock = '1') then for i in 0 to (number_of_channels-1) loop dataout_l(i) <= tx_in_int(i*2); dataout_h(i) <= tx_in_int((i*2)+1); end loop; end if; end if; end process; -- DDIO_OUT_RECEIVE process DDIO_OUT_TRANSMIT : process(tx_inclock, dataout_h, dataout_l) begin if (deserialization_factor = 2) then if (tx_inclock = '1') then for i in 0 to (number_of_channels-1) loop tx_ddio_out(i) <= dataout_h(i); end loop; else for i in 0 to (number_of_channels-1) loop tx_ddio_out(i) <= dataout_l(i); end loop; end if; end if; end process; -- DDIO_OUT_TRANSMIT process -- Registering of the load enable signal for Stratix's registers TXLOADEN: process (tx_fastclk) begin if (tx_fastclk'event and (tx_fastclk ='1')) then enable0_pipe <= enable0_reg; enable0_reg <= enable0; elsif (tx_fastclk'event and (tx_fastclk = '0')) then enable0_neg <= enable0_pipe; end if; end process; -- TXLOADEN process -- Load and serialize the data SERIALIZE: process(tx_fastclk, tx_slowclk, enable0_reg) variable posedge_count : integer := 0; variable negedge_count : integer := 0; variable count : integer := 0; variable sample : integer; variable tx_output_delay : time := (inclock_period/(deserialization_factor*2) * 1 ps); variable shift_data : std_logic := '0'; variable tx_shift_reg : std_logic_vector(REGISTER_WIDTH -1 downto 0) := (others => '0'); begin if (deserialization_factor > 2) then if (tx_slowclk'event and (tx_slowclk = '1')) then negedge_count := 0; end if; -- For APEX and Mercury families -- Load data on 3rd negative edge of the fast clock if (tx_fastclk'event and (tx_fastclk = '0')) then negedge_count := negedge_count + 1; if ((negedge_count = 3) and (STRATIX_TX_STYLE = false) and (STRATIXII_TX_STYLE = false)) then if (TX_NEED_HOLD_REG = true) then tx_parallel_load_reg <= tx_hold_reg; else tx_parallel_load_reg <= tx_in_int; end if; end if; end if; -- For APEX and Mercury families -- Serialize the data if ((STRATIX_TX_STYLE = false) and (STRATIXII_TX_STYLE = false)) then if (tx_fastclk'event and (tx_fastclk = '1')) then posedge_count := (posedge_count+1) rem deserialization_factor; if (posedge_count = 3) then -- register the incoming data on the third falling edge tx_shift_reg := tx_parallel_load_reg; count := 0; shift_data := '1'; -- third rising edge end if; if (shift_data = '1') then count := count + 1; for i in 0 to (number_of_channels-1) loop -- Data in MSB gets shifted out first. -- NB: This happens 1/2 clk cycle later for APEXII -- (MSB only) when center_align_msb is ON. if ((i = number_of_channels-1) and ((APEXII_TX_STYLE = true)) and (center_align_msb = "ON")) then tx_out_apex(i) <= tx_shift_reg(((i+1)*deserialization_factor) - count) after tx_output_delay; else tx_out_apex(i) <= tx_shift_reg(((i+1)*deserialization_factor) - count); end if; end loop; end if; end if; -- Update asymmetrical outclock for MERCURY for odd -- deserialization_factor. if ((deserialization_factor rem 2) /= 0) then if (tx_slowclk'event and (tx_slowclk = '1')) then tx_mercury_core_clock <= tx_slowclk; end if; if (tx_fastclk'event and (tx_fastclk = '1') and (posedge_count=((deserialization_factor+1) / 2)+1)) then tx_mercury_core_clock <= not tx_mercury_core_clock; end if; end if; else -- For Stratix -- Load data when registered load enable signal goes high if (((STRATIX_TX_STYLE = true) and (enable0_reg = '1') and enable0_reg'event) or ((STRATIXII_TX_STYLE = true) and tx_fastclk'event and (tx_fastclk = '1'))) then if (registered_input /= "OFF") then tx_parallel_load_reg <= tx_in_reg; else tx_parallel_load_reg <= tx_in; end if; end if; -- Serialize the data, MSB is the first bit to be shifted out if (tx_fastclk'event and (tx_fastclk = '1')) then if (((STRATIX_TX_STYLE = true) and (enable0_neg = '1')) or ((STRATIXII_TX_STYLE = true) and (enable0_reg = '1'))) then tx_shift_reg := tx_parallel_load_reg; count := 0; shift_data := '1'; end if; if (shift_data = '1') then count := (count rem deserialization_factor) + 1; for i in 0 to number_of_channels-1 loop tx_out_stratix(i) <= tx_shift_reg((i+1)*deserialization_factor - count); end loop; end if; end if; end if; end if; end process; -- SERIALIZE process -- synchronization register -- registers the data_in before passing on to the parallel load register or -- holding register SYNC_REG: process(tx_reg_clk) begin if (tx_reg_clk = '1') then tx_in_reg <= tx_in after 5 ps; end if; end process; -- SYNC_REG process -- holding register HOLD_REG: process(tx_hold_clk) begin if (deserialization_factor > 1) then if (tx_hold_clk = '0') then tx_hold_reg <= tx_in_int; end if; end if; end process; -- HOLD_REG process end behavior; --END OF ARCHITECTURE ---START_ENTITY_HEADER------------------------------------------------- -- -- Entity Name : altcam -- -- Description : Content-addressable memory (CAM) Megafunction. The -- data contained in a CAM is a set of patterns that can be searched in a -- single-clock cycle. The altcam megafunction allows each stored pattern -- bit to be specified as a binary "1" bit, binary "0" bit, or a don't care bit. -- Comparing a stored pattern bit that is specified as don't care with its -- corresponding input pattern bit will always result in a match. -- -- Limitation : Input patterns cannot contain don't care bits. -- -- Results expected: If the input pattern given to the CAM matches one -- of the patterns stored in the CAM, the address of the matching stored -- pattern is generated. -- ---END_ENTITY_HEADER------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use std.textio.all; use work.ALTERA_COMMON_CONVERSION.all; entity altcam is generic ( width: natural := 1; widthad: natural := 1; numwords: natural := 1; lpm_file: string := "UNUSED"; lpm_filex: string := "UNUSED"; match_mode: string := "MULTIPLE"; output_reg: string := "UNREGISTERED"; output_aclr: string := "OFF"; pattern_reg: string := "INCLOCK"; pattern_aclr: string := "ON"; wraddress_aclr: string := "ON"; wrx_reg: string := "UNUSED"; wrx_aclr: string := "UNUSED"; wrcontrol_aclr: string := "OFF"; use_eab: string := "ON" ; lpm_type: string := "altcam" ); port ( pattern: in std_logic_vector(width-1 downto 0); -- Required port wrx: in std_logic_vector(width-1 downto 0) := (others => '0'); wrxused: in std_logic := '1'; wrdelete: in std_logic := '0'; wraddress: in std_logic_vector(widthad-1 downto 0); wren: in std_logic; inclock: in std_logic; -- Required port inclocken: in std_logic := '1'; inaclr: in std_logic := '0'; outclock: in std_logic := '0'; outclocken: in std_logic := '1'; outaclr: in std_logic := '0'; mstart: in std_logic := 'X'; mnext: in std_logic := '0'; maddress: out std_logic_vector(widthad-1 downto 0); mbits: out std_logic_vector(numwords-1 downto 0); mfound: out std_logic; mcount: out std_logic_vector(widthad-1 downto 0); rdbusy: out std_logic; wrbusy: out std_logic ); type lpm_memory is array (numwords-1 downto 0) of std_logic_vector(width-1 downto 0); function hex_to_stdlogicarray (s: string) return lpm_memory is variable mem_data : lpm_memory; variable mem_data_word : std_logic_vector(width-1 downto 0); variable i : integer := 0; variable j : integer := 0; variable k : integer := 0; variable n : integer := 0; variable m : integer := 0; variable lineno : integer := 0; variable buf: line; variable booval: boolean; FILE mem_data_file: TEXT; variable base : string(2 downto 1); variable byte : string(2 downto 1); variable rec_type : string(2 downto 1); variable datain : string(2 downto 1); variable checksum : string(2 downto 1); variable startadd: string(4 downto 1); variable ibase: integer := 0; variable ibyte: integer := 0; variable istartadd: integer := 0; variable check_sum_vec: std_logic_vector(7 downto 0); variable check_sum_vec_tmp: std_logic_vector(7 downto 0); begin FILE_OPEN(mem_data_file, S,READ_MODE); while not ENDFILE(mem_data_file) loop booval := true; READLINE(mem_data_file, buf); lineno := lineno + 1; check_sum_vec := (others => '0'); if (buf(buf'LOW) = ':') then -- check for start of record char ':' i := 1; SHRINK_LINE(buf, i); READ(L=>buf, VALUE=>byte, good=>booval); -- read length of record (2 hex chars) if not (booval) then ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format!" SEVERITY ERROR; end if; ibyte := HEX_STR_TO_INT(byte); check_sum_vec := unsigned(check_sum_vec) + unsigned(CONV_STD_LOGIC_VECTOR(ibyte, 8)); READ(L=>buf, VALUE=>startadd, good=>booval); -- read start/load address (4 hex chars) if not (booval) then ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format! " SEVERITY ERROR; end if; istartadd := HEX_STR_TO_INT(startadd); byte(2) := startadd(4); byte(1) := startadd(3); check_sum_vec := unsigned(check_sum_vec) + unsigned(CONV_STD_LOGIC_VECTOR(HEX_STR_TO_INT(byte), 8)); byte(2) := startadd(2); byte(1) := startadd(1); check_sum_vec := unsigned(check_sum_vec) + unsigned(CONV_STD_LOGIC_VECTOR(HEX_STR_TO_INT(byte), 8)); READ(L=>buf, VALUE=>rec_type, good=>booval); -- read record type (2 hex chars) if not (booval) then ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format! " SEVERITY ERROR; end if; check_sum_vec := unsigned(check_sum_vec) + unsigned(CONV_STD_LOGIC_VECTOR(HEX_STR_TO_INT(rec_type), 8)); else ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format! " SEVERITY ERROR; end if; case rec_type is when "00"=> -- Data record i := 0; k := width/8; if ( (width mod 8) /= 0 ) then k := k + 1; end if; -- k = no. of bytes per CAM entry. while( i < ibyte ) loop mem_data_word := (others => '0'); n := (k - 1)*8; m := width - 1; for j in 1 to k loop READ(L=>buf, VALUE=>datain,good=>booval); -- read in data a byte (2 hex chars) at a time. if not (booval) then ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format! " SEVERITY ERROR; end if; check_sum_vec := unsigned(check_sum_vec) + unsigned(CONV_STD_LOGIC_VECTOR(HEX_STR_TO_INT(datain), 8)); mem_data_word(m downto n) := CONV_STD_LOGIC_VECTOR(HEX_STR_TO_INT(datain), m-n+1); m := n - 1; n := n - 8; end loop; i := i + k; mem_data(ibase + istartadd) := mem_data_word; istartadd := istartadd + 1; end loop; when "01"=> exit; when "02"=> ibase := 0; if (ibyte /= 2) then ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format for record type 02! " SEVERITY ERROR; end if; for i in 0 to (ibyte-1) loop READ(L=>buf, VALUE=>base,good=>booval); if not (booval) then ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format! " SEVERITY ERROR; end if; ibase := (ibase * 256) + HEX_STR_TO_INT(base); check_sum_vec := unsigned(check_sum_vec) + unsigned(CONV_STD_LOGIC_VECTOR(HEX_STR_TO_INT(base), 8)); end loop; ibase := ibase * 16; -- because std load addr is 2 bytes. when others => ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal record type in Intel Hex File! " SEVERITY ERROR; end case; READ(L=>buf, VALUE=>checksum,good=>booval); if not (booval) then ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Checksum is missing! " SEVERITY ERROR; end if; check_sum_vec := unsigned(not (check_sum_vec)) + 1; check_sum_vec_tmp := CONV_STD_LOGIC_VECTOR(HEX_STR_TO_INT(checksum),8); if (check_sum_vec /= check_sum_vec_tmp) then ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Incorrect checksum!" SEVERITY ERROR; end if; end loop; FILE_CLOSE(mem_data_file); return mem_data; end; -- end of hex_to_stdlogicarray end altcam; architecture behave of altcam is signal pattern_rgd: std_logic_vector(width-1 downto 0) := (others => '0'); -- registered input signal pattern_int: std_logic_vector(width-1 downto 0) := (others => '0'); -- internal input signal wrx_rgd: std_logic_vector(width-1 downto 0) := (others => '0'); -- registered input signal wrx_int: std_logic_vector(width-1 downto 0) := (others => '0'); -- internal input signal wrxused_rgd : std_logic := '0'; -- registered input signal wrxused_int : std_logic := '0'; -- internal input signal wraddress_rgd: std_logic_vector(widthad-1 downto 0) := (others => '0'); -- registered input signal wren_rgd: std_logic := '0'; -- registered input signal wrdelete_rgd: std_logic := '0'; -- internally registered input signal maddress_rgd: std_logic_vector(widthad-1 downto 0) := (others => '0'); -- registered output signal maddress_int: std_logic_vector(widthad-1 downto 0) := (others => '0'); -- internal output signal mbits_rgd: std_logic_vector(numwords-1 downto 0) := (others => '0'); -- registered output signal mbits_int: std_logic_vector(numwords-1 downto 0) := (others => '0'); -- internal output signal mfound_rgd: std_logic := '0'; -- registered output signal mfound_int: std_logic := '0'; -- internal output signal mcount_rgd: std_logic_vector(widthad-1 downto 0) := (others => '0'); -- registered output signal mcount_int: std_logic_vector(widthad-1 downto 0) := (others => '0'); -- internal output signal wrbusy_int : std_logic := '0'; -- internal output signal rdbusy_int : std_logic := '0'; -- internal output signal outclock_int: std_logic; -- internal outclock signal outaclr_int: std_logic; -- internal outaclr -- CAM signals signal cam_init: integer := 1; signal cam_array: lpm_memory; signal x_array: lpm_memory; -- Read control signals signal get_first_match : boolean := false; signal get_next_match : boolean := false; signal first_read_clock : boolean := false; signal mstart_rgd1: std_logic := '0'; signal mstart_rgd2: std_logic := '0'; signal rdbusy_delayed : std_logic; signal first_read_in_write: boolean := false; signal mstart_used: boolean := false; -- Write control signals signal write_start : std_logic; signal write_start_rgd: std_logic := '0'; signal write_start_1: std_logic := '0'; signal write0: boolean := true; signal write1: boolean := false; signal writex: boolean := false; signal write0_done: boolean := false; signal write1_done: boolean := false; signal writex_done: boolean := false; signal write_incomplete: std_logic := '0'; begin -- Evaluate parameters pattern_int <= pattern when pattern_reg = "UNREGISTERED" else pattern_rgd; wrx_int <= wrx when wrx_reg = "UNREGISTERED" else wrx_rgd; wrxused_int <= wrxused when wrx_reg = "UNREGISTERED" else wrxused_rgd; maddress <= maddress_int when output_reg = "UNREGISTERED" else maddress_rgd; mbits <= mbits_int when output_reg = "UNREGISTERED" else mbits_rgd; mcount <= mcount_int when output_reg = "UNREGISTERED" else mcount_rgd; mfound <= mfound_int when output_reg = "UNREGISTERED" else mfound_rgd; wrbusy <= wrbusy_int; rdbusy <= rdbusy_int; outclock_int <= outclock when output_reg = "OUTCLOCK" else inclock; outaclr_int <= outaclr when output_aclr = "ON" else inaclr; rdbusy_delayed <= rdbusy_int after 2 ns; PRAM_MSG: process begin if ( width <= 0 ) then ASSERT FALSE REPORT "Error! Value of width parameter must be greater than 0." SEVERITY ERROR; end if; if( widthad <= 0 ) then ASSERT FALSE REPORT "Error! Value of widthad parameter must be greater than 0." SEVERITY ERROR; end if; if( (match_mode /= "SINGLE") and (match_mode /= "MULTIPLE") and (match_mode /= "FAST_MULTIPLE") ) then ASSERT FALSE REPORT "Error! Illegal value for match_mode parameter. The value must be SINGLE, MULTIPLE (the default), or FAST_MULTIPLE." SEVERITY ERROR; end if; wait; end process PRAM_MSG; MSG: process (wraddress_rgd, wrdelete_rgd, wren_rgd, wrxused_int, pattern_int, mstart_rgd1) begin if (wren_rgd'event and (wren_rgd = '0') and (write_incomplete = '1')) then ASSERT FALSE REPORT "Insufficient write cycle time, write maybe invalid! " SEVERITY WARNING; elsif (pattern_int'event and (write_incomplete = '1')) then ASSERT FALSE REPORT "Insufficient pattern hold time, write maybe invalid! " SEVERITY WARNING; elsif (wraddress_rgd'event and (write_incomplete = '1')) then ASSERT FALSE REPORT "Insufficient address hold time, write maybe invalid! " SEVERITY WARNING; elsif (wrdelete_rgd'event and (wrdelete_rgd = '0') and write_incomplete = '1') then ASSERT FALSE REPORT "Insufficient delete cycle time, delete failed! " SEVERITY WARNING; elsif (wrdelete_rgd'event and (wrdelete_rgd = '1') and (write_incomplete = '1')) then ASSERT FALSE REPORT "Insufficient write cycle time, write maybe invalid! " SEVERITY WARNING; elsif (wrxused_int'event and (write_incomplete = '1') and (wrdelete_rgd = '0')) then ASSERT FALSE REPORT "wrxused signal changed during write! " SEVERITY WARNING; elsif (mstart_rgd1'event and (write_incomplete = '1') and (mstart_rgd1 = '1')) then ASSERT FALSE REPORT "Incorrect read attempt during write! " SEVERITY WARNING; end if; if (pattern_int'event) then if (rdbusy_delayed = '1') then ASSERT FALSE REPORT "Insufficient read time, read failed! " SEVERITY WARNING; elsif ((rdbusy_delayed = '0') and (mnext = '1')) then ASSERT FALSE REPORT "Illegal pattern change during read, read failed! " SEVERITY WARNING; end if; end if; end process MSG; MSTART_UPDATE: process (mstart) begin if (mstart /= 'X') then mstart_used <= true; end if; end process MSTART_UPDATE; ----------------------------------------- -- Evaluate ALTCAM reading and writing -- ----------------------------------------- READ_WRITE: process (inaclr, inclock, pattern) variable count : natural := 0; variable index : natural :=0; variable addr : natural :=0; variable next_search : natural := 0; variable restart_read : boolean := false; variable reset_read : boolean := true; variable ipattern: std_logic_vector(width-1 downto 0); variable iwraddress: std_logic_vector(widthad-1 downto 0); variable iwrx: std_logic_vector(width-1 downto 0); variable iwren: std_logic; variable iwrxused : std_logic; variable mbits_tmp: std_logic_vector(numwords-1 downto 0); variable cam_array_tmp: lpm_memory; variable x_array_tmp: lpm_memory; begin -- Initialise the CAM at startup. if (cam_init = 1) then if (lpm_file = "UNUSED") then for i in 0 to numwords-1 loop cam_array(i) <= (others => '1'); x_array(i) <= (others => '1'); end loop; elsif (lpm_filex = "UNUSED") then cam_array <= hex_to_stdlogicarray(lpm_file); for i in 0 to numwords-1 loop x_array(i) <= (others => '0'); end loop; else cam_array <= hex_to_stdlogicarray(lpm_file); x_array <= hex_to_stdlogicarray(lpm_filex); end if; if (match_mode /= "SINGLE") then maddress_int <= (others => '1'); end if; end if; cam_init <= 0; ipattern := pattern; iwrx := wrx; iwraddress := wraddress; iwren := wren; if (wrx_reg = "UNUSED") or (wrx_aclr = "UNUSED") then iwrxused := '0'; -- must be unconnected else iwrxused := wrxused; end if; if (inaclr = '1') then if (mstart_used = true) then reset_read := true; end if; first_read_clock <= false; get_first_match <= false; if (pattern_aclr = "ON") then pattern_rgd <= (others => '0'); ipattern := (others => '0'); end if; if (wrx_aclr = "ON") then wrx_rgd <= (others => '0'); iwrx := (others => '0'); wrxused_rgd <= '0'; iwrxused := '0'; end if; if (wraddress_aclr = "ON") then wraddress_rgd <= (others => '0'); iwraddress := (others => '0'); end if; if (wrcontrol_aclr = "ON") then wren_rgd <= '0'; iwren := '0'; write0_done <= false; write1_done <= false; writex_done <= false; end if; if (pattern_aclr = "ON") then mbits_int <= (others => '0'); mcount_int <= (others => '0'); mfound_int <= '0'; if (match_mode = "SINGLE") then maddress_int <= (others => '0'); else maddress_int <= (others => '1'); end if; end if; end if; if (inclock'event and (inclocken = '1')) then if (inclock = '1') then pattern_rgd <= ipattern; wrx_rgd <= iwrx; wrxused_rgd <= iwrxused; wraddress_rgd <= iwraddress; wren_rgd <= iwren; write_start_rgd <= write_start; write_incomplete <= wrbusy_int; mstart_rgd1 <= mstart; mstart_rgd2 <= mstart_rgd1; wrdelete_rgd <= wrdelete; if (iwren = '0') then write0_done <= false; write1_done <= false; writex_done <= false; -------------------- -- CAM READ MODES -- -------------------- -- If pattern changed or mstart asserted again then restart -- read cycle. if (match_mode = "FAST_MULTIPLE" and mstart_used = false and reset_read = true) or (mstart = '1' and mstart_rgd1 = '0') or ((ipattern /= pattern_rgd) and (reset_read=false)) then restart_read := true; reset_read := false; get_first_match <= false; else restart_read := false; end if; ------------------------- -- FAST MULTIPLE: READ -- ------------------------- if (match_mode = "FAST_MULTIPLE") then if (get_first_match = true and restart_read = false) then if (get_next_match = true) then -- start of next read cycle index := next_search; MADDR_FM0: for i in index to numwords-1 loop MWORD_FM0: for j in 0 to width-1 loop if (((x_array(i)(j) = '0') and (cam_array(i)(j) = ipattern(j))) or ((x_array(i)(j) = '1') and (cam_array(i)(j) = '0'))) then if j = width-1 then next_search := i+1; exit MADDR_FM0; end if; else exit MWORD_FM0; end if; end loop MWORD_FM0; end loop MADDR_FM0; if (index = next_search) then -- no more matches mfound_int <= '0'; maddress_int <= (others => '1'); else maddress_int <= ieee.std_logic_arith.conv_std_logic_vector(next_search-1, widthad); end if; end if; else -- start of new read cycle count := 0; mbits_tmp := (others => '0'); MADDR_FM1: for i in 0 to numwords -1 loop MWORD_FM1: for j in 0 to width-1 loop if (((x_array(i)(j) = '0') and (cam_array(i)(j) = ipattern(j))) or ((x_array(i)(j) = '1') and (cam_array(i)(j) = '0'))) then if (j = width-1) then if ((count = 0) and (reset_read = false) and (restart_read = true)) then mfound_int <= '1'; maddress_int <= ieee.std_logic_arith.conv_std_logic_vector(i, widthad); get_first_match <= true; next_search := i+1; end if; mbits_tmp(i) := '1'; count := count + 1; end if; else exit MWORD_FM1; end if; end loop MWORD_FM1; end loop MADDR_FM1; mcount_int <= ieee.std_logic_arith.conv_std_logic_vector(count, widthad); mbits_int <= mbits_tmp; if ((count = 0) or (reset_read = true)) then -- no matches mfound_int <= '0'; maddress_int <= (others => '1'); end if; end if; -- end of initial read cycle end if; -- end of FAST MULTIPLE -------------------- -- MULTIPLE: READ -- -------------------- if (match_mode = "MULTIPLE") then if (get_first_match = true and restart_read = false) then if (get_next_match = true) then -- start of next read cycle index := next_search; MADDR_MM0: for i in index to numwords-1 loop MWORD_MM0: for j in 0 to width-1 loop if (((x_array(i)(j) = '0') and (cam_array(i)(j) = ipattern(j))) or ((x_array(i)(j) = '1') and (cam_array(i)(j) = '0'))) then if (j = width-1) then next_search := i+1; exit MADDR_MM0; end if; else exit MWORD_MM0; end if; end loop MWORD_MM0; end loop MADDR_MM0; if (index = next_search) then mfound_int <= '0'; maddress_int <= (others => '1'); else maddress_int <= ieee.std_logic_arith.conv_std_logic_vector(next_search-1, widthad); end if; end if; else -- start of 1st match count := 0; if (reset_read=false) then -- Not in reset state if (first_read_clock = false) then -- 1st cycle: match with even and write to even first_read_clock <= true; maddress_int <= (others => '1'); mfound_int <= '0'; mbits_tmp := mbits_int; MADDR_MM1: for i in 0 to numwords-1 loop if ((i mod 2)=0) then if (mbits_int(i) = '1') then count := count + 1; end if; MWORD_MM1: for j in 0 to width-1 loop if (((x_array(i)(j) = '0') and (cam_array(i)(j) = ipattern(j))) or ((x_array(i)(j) = '1') and (cam_array(i)(j) = '0'))) then if (j = width-1) then mbits_tmp(i+1) := '1'; count := count + 1; end if; else mbits_tmp(i+1) := '0'; exit MWORD_MM1; end if; end loop MWORD_MM1; end if; end loop MADDR_MM1; else -- 2nd read cycle -- 2nd cycle: do match first_read_clock <= false; mbits_tmp := (others => '0'); MADDR_MM2: for i in 0 to numwords-1 loop MWORD_MM2: for j in 0 to width-1 loop if (((x_array(i)(j) = '0') and (cam_array(i)(j) = ipattern(j))) or ((x_array(i)(j) = '1') and (cam_array(i)(j) = '0'))) then if (j = width-1) then if (count = 0) then next_search := i+1; end if; mbits_tmp(i) := '1'; count := count + 1; end if; else exit MWORD_MM2; end if; end loop MWORD_MM2; end loop MADDR_MM2; if (count = 0) then -- no matches maddress_int <= (others => '1'); mfound_int <= '0'; else get_first_match <= true; mfound_int <= '1'; maddress_int <= ieee.std_logic_arith.conv_std_logic_vector(next_search-1, widthad); end if; end if; else -- In reset state -- Match with even but write to odd maddress_int <= (others => '1'); mfound_int <= '0'; mbits_tmp := (others => '0'); MADDR_MM3: for i in 0 to numwords-1 loop if ((i mod 2)=0) then MWORD_MM3: for j in 0 to width-1 loop if (((x_array(i)(j) = '0') and (cam_array(i)(j) = ipattern(j))) or ((x_array(i)(j) = '1') and (cam_array(i)(j) = '0'))) then if (j = width-1) then mbits_tmp(i+1) := '1'; count := count + 1; end if; else exit MWORD_MM3; end if; end loop MWORD_MM3; end if; end loop MADDR_MM3; end if; -- end of 1st match mcount_int <= ieee.std_logic_arith.conv_std_logic_vector(count, widthad); mbits_int <= mbits_tmp; end if; -- end of initial read cycle end if; -- end of MULTIPLE ------------------ -- SINGLE: READ -- ------------------ if (match_mode = "SINGLE") then mbits_tmp := (others => '0'); index := 0; count := 0; MADDR_SM0: for i in 0 to numwords-1 loop MWORD_SM0: for j in 0 to width-1 loop if (((x_array(i)(j) = '0') and (cam_array(i)(j) = ipattern(j))) or ((x_array(i)(j) = '1') and (cam_array(i)(j) = '0'))) then if (j = width-1) then mbits_tmp(i) := '1'; index := i; count := 1; exit MADDR_SM0; end if; else exit MWORD_SM0; end if; end loop MWORD_SM0; end loop MADDR_SM0; mcount_int <= ieee.std_logic_arith.conv_std_logic_vector(count, widthad); mbits_int <= mbits_tmp; if (count = 0) then maddress_int <= (others => '0'); mfound_int <= '0'; else mfound_int <= '1'; maddress_int <= ieee.std_logic_arith.conv_std_logic_vector(index, widthad); end if; end if; -- end of SINGLE else -- if wren = '1' ---------------------- -- READ AFTER WRITE -- ---------------------- -- Writing to CAM so reset read cycle. get_first_match <= false; first_read_clock <= false; restart_read := false; if (mstart_used = true) then reset_read := true; end if; ------------------------------------- -- FAST MULTIPLE: READ AFTER WRITE -- ------------------------------------- if (match_mode = "FAST_MULTIPLE") then mfound_int <= '0'; maddress_int <= (others => '1'); count := 0; mbits_tmp := (others => '0'); if ((writex = true) and (iwrxused = '1')) then WADDR_FM0: for i in 0 to numwords-1 loop WWORD_FM0: for j in 0 to width-1 loop if (((x_array(i)(j) = '0') and (cam_array(i)(j) = (ipattern(j) xor iwrx(j)))) or ((x_array(i)(j) = '1') and (cam_array(i)(j) = '0'))) then if (j = width-1) then mbits_tmp(i) := '1'; count := count + 1; end if; else exit WWORD_FM0; end if; end loop WWORD_FM0; end loop WADDR_FM0; else WADDR_FM1: for i in 0 to numwords-1 loop WWORD_FM1: for j in 0 to width-1 loop if (((x_array(i)(j) = '0') and (cam_array(i)(j) = ipattern(j))) or ((x_array(i)(j) = '1') and (cam_array(i)(j) = '0'))) then if (j = width-1) then mbits_tmp(i) := '1'; count := count + 1; end if; else exit WWORD_FM1; end if; end loop WWORD_FM1; end loop WADDR_FM1; end if; mcount_int <= ieee.std_logic_arith.conv_std_logic_vector(count, widthad); mbits_int <= mbits_tmp; end if; -- end of FAST MULTIPLE -------------------------------- -- MULTIPLE: READ AFTER WRITE -- -------------------------------- if (match_mode = "MULTIPLE") then mfound_int <= '0'; maddress_int <= (others => '1'); mbits_tmp := (others => '0'); if ((writex = true) and (iwrxused = '1')) then mcount_int <= (others => '0'); else if (first_read_in_write = false) then -- Read even addresses but they appear on the odd locations -- of mbits. count := 0; WADDR_MM0: for i in 0 to numwords-1 loop if ( (i mod 2) = 0 ) then if (mbits_int(i) = '1') then -- counting previous even address matches count := count + 1; end if; WWORD_MM0: for j in 0 to width-1 loop if (((x_array(i)(j) = '0') and (cam_array(i)(j) = ipattern(j))) or ((x_array(i)(j) = '1') and (cam_array(i)(j) = '0'))) then if (j = width-1) then mbits_tmp(i+1) := '1'; count := count + 1; end if; else exit WWORD_MM0; end if; end loop WWORD_MM0; end if; end loop WADDR_MM0; else -- Read odd addresses. count := 0; WADDR_MM1: for i in numwords-1 downto 0 loop if ((i mod 2) = 1) then mbits_tmp(i-1) := mbits_tmp(i); else WWORD_MM1: for j in 0 to width-1 loop if (((x_array(i)(j) = '0') and (cam_array(i)(j) = ipattern(j))) or ((x_array(i)(j) = '1') and (cam_array(i)(j) = '0'))) then if (j = width-1) then mbits_tmp(i) := '1'; count := count + 1; end if; else exit WWORD_MM1; end if; end loop WWORD_MM1; end if; end loop WADDR_MM1; end if; mcount_int <= ieee.std_logic_arith.conv_std_logic_vector(count, widthad); mbits_int <= mbits_tmp; end if; end if; -- end of MULTIPLE ------------------------------ -- SINGLE: READ AFTER WRITE -- ------------------------------ if (match_mode = "SINGLE") then mbits_tmp := (others => '0'); index := 0; count := 0; if ((writex = true) and (iwrxused = '1')) then WADDR_SM0: for i in 0 to numwords-1 loop WWORD_SM0: for j in 0 to width-1 loop if (((x_array(i)(j) = '0') and (cam_array(i)(j) = (ipattern(j) xor iwrx(j)))) or ((x_array(i)(j) = '1') and (cam_array(i)(j) = '0'))) then if (j = width-1) then mbits_tmp(i) := '1'; index := i; count := 1; exit WADDR_SM0; end if; else exit WWORD_SM0; end if; end loop WWORD_SM0; end loop WADDR_SM0; else WADDR_SM1: for i in 0 to numwords-1 loop WWORD_SM1: for j in 0 to width-1 loop if (((x_array(i)(j) = '0') and (cam_array(i)(j) = ipattern(j))) or ((x_array(i)(j) = '1') and (cam_array(i)(j) = '0'))) then if (j = width-1) then mbits_tmp(i) := '1'; index := i; count := 1; exit WADDR_SM1; end if; else exit WWORD_SM1; end if; end loop WWORD_SM1; end loop WADDR_SM1; end if; mcount_int <= ieee.std_logic_arith.conv_std_logic_vector(count, widthad); mbits_int <= mbits_tmp; if (count = 0) then mfound_int <= '0'; maddress_int <= (others => '0'); else mfound_int <= '1'; maddress_int <= ieee.std_logic_arith.conv_std_logic_vector(index, widthad); end if; end if; -- end of SINGLE end if; else -- if inclock negedge -- We write to the CAM on the low cycle of inclock -- when wren_rgd='1'. if ((wren_rgd='1') and (inclock='0')) then if (pattern_reg = "UNREGISTERED") then ipattern := pattern; else ipattern := pattern_rgd; end if; addr := ieee.std_logic_unsigned.conv_integer(wraddress_rgd); cam_array_tmp := cam_array; x_array_tmp := x_array; --------------------- -- CAM WRITE MODES -- --------------------- if (wrdelete_rgd = '0') then if ((wrxused_int = '1') and (wrx_reg /= "UNUSED") and (wrx_aclr /= "UNUSED")) then ------------------- -- 3 CYCLE WRITE -- ------------------- ----------------- -- WRITE_ZEROS -- ----------------- if (write0 = true) then for i in 0 to width-1 loop if (ipattern(i) = '0') then -- "0" => "0" if (cam_array(addr)(i)='0' and x_array(addr)(i)='0') then -- "0" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '0'; -- "1" => "X" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='0') then -- "1" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '1'; -- "X" => "X" elsif (cam_array(addr)(i)='0' and x_array(addr)(i)='1') then -- "X" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '1'; -- "U" => "0" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='1') then -- "U" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '0'; end if; elsif (ipattern(i) = '1') then -- "0" => "X" if (cam_array(addr)(i)='0' and x_array(addr)(i)='0') then -- "0" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '1'; -- "1" => "1" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='0') then -- "1" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '0'; -- "X" => "X" elsif (cam_array(addr)(i)='0' and x_array(addr)(i)='1') then -- "X" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '1'; -- "U" => "1" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='1') then -- "U" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '0'; end if; end if; end loop; write0_done <= true; write1_done <= false; writex_done <= false; end if; ---------------- -- WRITE_ONES -- ---------------- if (write1 = true) then for i in 0 to width-1 loop if (ipattern(i) = '0') then -- "0" => "0" if (cam_array(addr)(i)='0' and x_array(addr)(i)='0') then -- "0" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '0'; -- "1" => "U" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='0') then -- "1" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '1'; -- "X" => "0" elsif (cam_array(addr)(i)='0' and x_array(addr)(i)='1') then -- "X" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '0'; -- "U" => "U" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='1') then -- "U" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '1'; end if; elsif (ipattern(i) = '1') then -- "0" => "U" if (cam_array(addr)(i)='0' and x_array(addr)(i)='0') then -- "0" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '1'; -- "1" => "1" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='0') then -- "1" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '0'; -- "X" => "1" elsif (cam_array(addr)(i)='0' and x_array(addr)(i)='1') then -- "X" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '0'; -- "U" => "U" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='1') then -- "U" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '1'; end if; end if; end loop; write0_done <= false; write1_done <= true; writex_done <= false; end if; ------------- -- WRITE_X -- ------------- if (writex = true) then for i in 0 to width-1 loop if ((ipattern(i) xor wrx_int(i)) = '0') then -- "0" => "0" if (cam_array(addr)(i)='0' and x_array(addr)(i)='0') then -- "0" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '0'; -- "1" => "X" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='0') then -- "1" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '1'; -- "X" => "X" elsif (cam_array(addr)(i)='0' and x_array(addr)(i)='1') then -- "X" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '1'; -- "U" => "0" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='1') then -- "U" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '0'; end if; elsif ((ipattern(i) xor wrx_int(i)) = '1') then -- "0" => "X" if (cam_array(addr)(i)='0' and x_array(addr)(i)='0') then -- "0" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '1'; -- "1" => "1" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='0') then -- "1" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '0'; -- "X" => "X" elsif (cam_array(addr)(i)='0' and x_array(addr)(i)='1') then -- "X" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '1'; -- "U" => "1" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='1') then -- "U" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '0'; end if; end if; end loop; writex_done <= true; write0_done <= false; write1_done <= false; end if; if (wrbusy_int = '1') then write_start_1 <= '1'; write_start <= write_start_1; else write_start_1 <= '0'; write_start <= '0'; end if; else -- 2 Cycle write ------------------- -- 2 CYCLE WRITE -- ------------------- ----------------- -- WRITE_ZEROS -- ----------------- if (write0 = true) then for i in 0 to width-1 loop if (ipattern(i) = '0') then -- "0" => "0" if (cam_array(addr)(i)='0' and x_array(addr)(i)='0') then -- "0" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '0'; -- "1" => "X" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='0') then -- "1" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '1'; -- "X" => "X" elsif (cam_array(addr)(i)='0' and x_array(addr)(i)='1') then -- "X" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '1'; -- "U" => "0" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='1') then -- "U" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '0'; end if; elsif (ipattern(i) = '1') then -- "0" => "X" if (cam_array(addr)(i)='0' and x_array(addr)(i)='0') then -- "0" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '1'; -- "1" => "1" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='0') then -- "1" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '0'; -- "X" => "X" elsif (cam_array(addr)(i)='0' and x_array(addr)(i)='1') then -- "X" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '1'; -- "U" => "1" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='1') then -- "U" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '0'; end if; end if; end loop; write0_done <= true; write1_done <= false; writex_done <= false; end if; ---------------- -- WRITE_ONES -- ---------------- if (write1 = true) then for i in 0 to width-1 loop if (ipattern(i) = '0') then -- "0" => "0" if (cam_array(addr)(i)='0' and x_array(addr)(i)='0') then -- "0" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '0'; -- "1" => "U" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='0') then -- "1" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '1'; -- "X" => "0" elsif (cam_array(addr)(i)='0' and x_array(addr)(i)='1') then -- "X" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '0'; -- "U" => "U" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='1') then -- "U" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '1'; end if; elsif (ipattern(i) = '1') then -- "0" => "U" if (cam_array(addr)(i)='0' and x_array(addr)(i)='0') then -- "0" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '1'; -- "1" => "1" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='0') then -- "1" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '0'; -- "X" => "1" elsif (cam_array(addr)(i)='0' and x_array(addr)(i)='1') then -- "X" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '0'; -- "U" => "U" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='1') then -- "U" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '1'; end if; end if; end loop; write0_done <= false; write1_done <= true; writex_done <= false; end if; if (wrbusy_int = '1') then write_start <= '1'; else write_start <= '0'; end if; end if; -- wrxused_int else -- if wrdelete = '1' then -------------------- -- 2 CYCLE DELETE -- -------------------- -- Delete is a 2-cycle write ---------------- -- WRITE_ONES -- ---------------- if (write0 = true) then for i in 0 to width-1 loop cam_array_tmp(addr)(i) := '1'; end loop; write0_done <= true; write1_done <= false; writex_done <= false; end if; ------------- -- WRITE_X -- ------------- if (write1 = true) then for i in 0 to width-1 loop x_array_tmp(addr)(i) := '1'; end loop; write1_done <= true; write0_done <= false; writex_done <= false; end if; if (wrbusy_int = '1') then write_start <= '1'; else write_start <= '0'; end if; end if; -- wrdelete cam_array <= cam_array_tmp; x_array <= x_array_tmp; -------------------------------------- -- FAST MULTIPLE: READ DURING WRITE -- -------------------------------------- -- Now we need to update mbits, mcount during the write. if (match_mode = "FAST_MULTIPLE") then mfound_int <= '0'; maddress_int <= (others => '1'); count := 0; mbits_tmp := (others => '0'); if ((writex = true) and (wrxused_int = '1')) then WADDR_FM2: for i in 0 to numwords-1 loop WWORD_FM2: for j in 0 to width-1 loop if (((x_array_tmp(i)(j) = '0') and (cam_array_tmp(i)(j) = (ipattern(j) xor wrx_int(j)))) or ((x_array_tmp(i)(j) = '1') and (cam_array_tmp(i)(j) = '0'))) then if (j = width-1) then if ((count = 0) and (mstart_used = false)) then mfound_int <= '1'; maddress_int <= ieee.std_logic_arith.conv_std_logic_vector(i, widthad); end if; mbits_tmp(i) := '1'; count := count + 1; end if; else exit WWORD_FM2; end if; end loop WWORD_FM2; end loop WADDR_FM2; else WADDR_FM3: for i in 0 to numwords-1 loop WWORD_FM3: for j in 0 to width-1 loop if (((x_array_tmp(i)(j) = '0') and (cam_array_tmp(i)(j) = ipattern(j))) or ((x_array_tmp(i)(j) = '1') and (cam_array_tmp(i)(j) = '0'))) then if (j = width-1) then if ((count = 0) and (mstart_used = false)) then mfound_int <= '1'; maddress_int <= ieee.std_logic_arith.conv_std_logic_vector(i, widthad); end if; mbits_tmp(i) := '1'; count := count + 1; end if; else exit WWORD_FM3; end if; end loop WWORD_FM3; end loop WADDR_FM3; end if; mcount_int <= ieee.std_logic_arith.conv_std_logic_vector(count, widthad); mbits_int <= mbits_tmp; end if; -- end of FAST MULTIPLE --------------------------------- -- MULTIPLE: READ DURING WRITE -- --------------------------------- if (match_mode = "MULTIPLE") then mfound_int <= '0'; maddress_int <= (others => '1'); mbits_tmp := (others => '0'); if ((writex = true) and (wrxused_int = '1')) then mcount_int <= (others => '0'); first_read_in_write <= false; else if (first_read_in_write = false) then first_read_in_write <= true; -- Read even addresses but they appear on the odd locations -- of mbits. count := 0; WADDR_MM2: for i in 0 to numwords-1 loop if ( (i mod 2) = 0 ) then if (mbits_int(i) = '1') then -- counting previous even address matches count := count + 1; end if; WWORD_MM2: for j in 0 to width-1 loop if (((x_array_tmp(i)(j) = '0') and (cam_array_tmp(i)(j) = ipattern(j))) or ((x_array_tmp(i)(j) = '1') and (cam_array_tmp(i)(j) = '0'))) then if (j = width-1) then mbits_tmp(i+1) := '1'; count := count + 1; end if; else exit WWORD_MM2; end if; end loop WWORD_MM2; end if; end loop WADDR_MM2; else first_read_in_write <= false; -- Read odd addresses. count := 0; WADDR_MM3: for i in numwords-1 downto 0 loop if ((i mod 2) = 1) then mbits_tmp(i-1) := mbits_tmp(i); else WWORD_MM3: for j in 0 to width-1 loop if (((x_array_tmp(i)(j) = '0') and (cam_array_tmp(i)(j) = ipattern(j))) or ((x_array_tmp(i)(j) = '1') and (cam_array_tmp(i)(j) = '0'))) then if (j = width-1) then mbits_tmp(i) := '1'; count := count + 1; end if; else exit WWORD_MM3; end if; end loop WWORD_MM3; end if; end loop WADDR_MM3; end if; mcount_int <= ieee.std_logic_arith.conv_std_logic_vector(count, widthad); mbits_int <= mbits_tmp; end if; end if; -- end of MULTIPLE ------------------------------ -- SINGLE: READ DURING WRITE -- ------------------------------ if (match_mode = "SINGLE") then mbits_tmp := (others => '0'); index := 0; count := 0; if ((writex = true) and (wrxused_int = '1')) then WADDR_SM2: for i in 0 to numwords-1 loop WWORD_SM2: for j in 0 to width-1 loop if (((x_array_tmp(i)(j) = '0') and (cam_array_tmp(i)(j) = (ipattern(j) xor wrx_int(j)))) or ((x_array_tmp(i)(j) = '1') and (cam_array_tmp(i)(j) = '0'))) then if (j = width-1) then mbits_tmp(i) := '1'; index := i; count := 1; exit WADDR_SM2; end if; else exit WWORD_SM2; end if; end loop WWORD_SM2; end loop WADDR_SM2; else WADDR_SM3: for i in 0 to numwords-1 loop WWORD_SM3: for j in 0 to width-1 loop if (((x_array_tmp(i)(j) = '0') and (cam_array_tmp(i)(j) = ipattern(j))) or ((x_array_tmp(i)(j) = '1') and (cam_array_tmp(i)(j) = '0'))) then if (j = width-1) then mbits_tmp(i) := '1'; index := i; count := 1; exit WADDR_SM3; end if; else exit WWORD_SM3; end if; end loop WWORD_SM3; end loop WADDR_SM3; end if; mcount_int <= ieee.std_logic_arith.conv_std_logic_vector(count, widthad); mbits_int <= mbits_tmp; if (count = 0) then mfound_int <= '0'; maddress_int <= (others => '0'); else mfound_int <= '1'; maddress_int <= ieee.std_logic_arith.conv_std_logic_vector(index, widthad); end if; end if; -- end of SINGLE else -- end of Write if write_start = '1' then -- this should be a second write cycle but due to write violation, -- we have to reset write_start write_start <= '0'; end if; end if; -- end of Write end if; -- end of inclock edges else -- if the pattern changes -- Only updating mbits, mcount, mfound and maddress if -- the pattern input in unregistered, wren_rgd='0' and the pattern -- patterb changes. if (pattern'event and (pattern_reg="UNREGISTERED")) then if (wren_rgd='0') then ---------------------------------------- -- FAST MULTIPLE: READ ON NEW PATTERN -- ---------------------------------------- if (match_mode = "FAST_MULTIPLE") then count := 0; mbits_tmp := (others => '0'); MADDR_FM2: for i in 0 to numwords-1 loop MWORD_FM2: for j in 0 to width-1 loop if (((x_array(i)(j) = '0') and (cam_array(i)(j) = pattern(j))) or ((x_array(i)(j) = '1') and (cam_array(i)(j) = '0'))) then if (j = width-1) then if ((count = 0) and (reset_read = false)) then mfound_int <= '1'; maddress_int <= ieee.std_logic_arith.conv_std_logic_vector(i, widthad); end if; mbits_tmp(i) := '1'; count := count + 1; end if; else exit MWORD_FM2; end if; end loop MWORD_FM2; end loop MADDR_FM2; mcount_int <= ieee.std_logic_arith.conv_std_logic_vector(count, widthad); mbits_int <= mbits_tmp; if ((count = 0) or (reset_read = true)) then mfound_int <= '0'; maddress_int <= (others => '1'); end if; end if; -- end of FAST MULTIPLE ----------------------------------- -- MULTIPLE: READ ON NEW PATTERN -- ----------------------------------- if (match_mode = "MULTIPLE") then count := 0; mbits_tmp := mbits_int; if (reset_read = true) then MADDR_MM4: for i in 0 to numwords-1 loop if ((i mod 2)=0) then MWORD_MM4: for j in 0 to width-1 loop if (((x_array(i)(j) = '0') and (cam_array(i)(j) = pattern(j))) or ((x_array(i)(j) = '1') and (cam_array(i)(j) = '0'))) then if (j = width-1) then mbits_tmp(i+1) := '1'; count := count + 1; end if; else mbits_tmp(i+1) := '0'; exit MWORD_MM4; end if; end loop MWORD_MM4; end if; end loop MADDR_MM4; else -- Match odd addresses and write to odd MADDR_MM5: for i in 0 to numwords-1 loop if ((i mod 2)=1) then MWORD_MM5: for j in 0 to width-1 loop if (((x_array(i)(j) = '0') and (cam_array(i)(j) = pattern(j))) or ((x_array(i)(j) = '1') and (cam_array(i)(j) = '0'))) then if (j = width-1) then mbits_tmp(i) := '1'; if (count = 0) then maddress_int <= ieee.std_logic_arith.conv_std_logic_vector(i, widthad); end if; count := count + 1; end if; else mbits_tmp(i) := '0'; exit MWORD_MM5; end if; end loop MWORD_MM5; else if (mbits_tmp(i) = '1') then if (count = 0) then maddress_int <= ieee.std_logic_arith.conv_std_logic_vector(i, widthad); end if; count := count + 1; end if; end if; end loop MADDR_MM5; if (count > 0) then mfound_int <= '1'; else mfound_int <= '0'; maddress_int <= (others => '1'); end if; end if; mcount_int <= ieee.std_logic_arith.conv_std_logic_vector(count, widthad); mbits_int <= mbits_tmp; end if; --------------------------------- -- SINGLE: READ ON NEW PATTERN -- --------------------------------- if (match_mode = "SINGLE") then mbits_tmp := (others => '0'); index := 0; count := 0; MADDR_SM1: for i in 0 to numwords-1 loop MWORD_SM1: for j in 0 to width-1 loop if (((x_array(i)(j) = '0') and (cam_array(i)(j) = pattern(j))) or ((x_array(i)(j) = '1') and (cam_array(i)(j) = '0'))) then if (j = width-1) then mbits_tmp(i) := '1'; count := 1; index := i; exit MADDR_SM1; end if; else exit MWORD_SM1; end if; end loop MWORD_SM1; end loop MADDR_SM1; mcount_int <= ieee.std_logic_arith.conv_std_logic_vector(count, widthad); mbits_int <= mbits_tmp; if (count = 0) then maddress_int <= (others => '0'); mfound_int <= '0'; else mfound_int <= '1'; maddress_int <= ieee.std_logic_arith.conv_std_logic_vector(index, widthad); end if; end if; -- end of SINGLE else -- We write to the CAM on the low cycle of inclock -- when wren_rgd='1' and pattern changes. if ((wren_rgd='1') and (inclock='0')) then addr := ieee.std_logic_unsigned.conv_integer(wraddress_rgd); cam_array_tmp := cam_array; x_array_tmp := x_array; --------------------- -- CAM WRITE MODES -- --------------------- if (wrdelete_rgd = '0') then if ((wrxused_int = '1') and (wrx_reg /= "UNUSED") and (wrx_aclr /= "UNUSED")) then ------------------- -- 3 CYCLE WRITE -- ------------------- ----------------- -- WRITE_ZEROS -- ----------------- if (write0_done = true) then for i in 0 to width-1 loop if (pattern(i) = '0') then -- "0" => "0" if (cam_array(addr)(i)='0' and x_array(addr)(i)='0') then -- "0" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '0'; -- "1" => "X" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='0') then -- "1" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '1'; -- "X" => "X" elsif (cam_array(addr)(i)='0' and x_array(addr)(i)='1') then -- "X" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '1'; -- "U" => "0" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='1') then -- "U" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '0'; end if; elsif (pattern(i) = '1') then -- "0" => "X" if (cam_array(addr)(i)='0' and x_array(addr)(i)='0') then -- "0" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '1'; -- "1" => "1" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='0') then -- "1" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '0'; -- "X" => "X" elsif (cam_array(addr)(i)='0' and x_array(addr)(i)='1') then -- "X" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '1'; -- "U" => "1" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='1') then -- "U" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '0'; end if; end if; end loop; end if; ---------------- -- WRITE_ONES -- ---------------- if (write1_done = true) then for i in 0 to width-1 loop if (pattern(i) = '0') then -- "0" => "0" if (cam_array(addr)(i)='0' and x_array(addr)(i)='0') then -- "0" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '0'; -- "1" => "U" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='0') then -- "1" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '1'; -- "X" => "0" elsif (cam_array(addr)(i)='0' and x_array(addr)(i)='1') then -- "X" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '0'; -- "U" => "U" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='1') then -- "U" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '1'; end if; elsif (pattern(i) = '1') then -- "0" => "U" if (cam_array(addr)(i)='0' and x_array(addr)(i)='0') then -- "0" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '1'; -- "1" => "1" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='0') then -- "1" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '0'; -- "X" => "1" elsif (cam_array(addr)(i)='0' and x_array(addr)(i)='1') then -- "X" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '0'; -- "U" => "U" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='1') then -- "U" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '1'; end if; end if; end loop; end if; ------------- -- WRITE_X -- ------------- if (writex_done = true) then for i in 0 to width-1 loop if ((pattern(i) xor wrx_int(i)) = '0') then -- "0" => "0" if (cam_array(addr)(i)='0' and x_array(addr)(i)='0') then -- "0" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '0'; -- "1" => "X" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='0') then -- "1" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '1'; -- "X" => "X" elsif (cam_array(addr)(i)='0' and x_array(addr)(i)='1') then -- "X" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '1'; -- "U" => "0" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='1') then -- "U" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '0'; end if; elsif ((pattern(i) xor wrx_int(i)) = '1') then -- "0" => "X" if (cam_array(addr)(i)='0' and x_array(addr)(i)='0') then -- "0" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '1'; -- "1" => "1" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='0') then -- "1" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '0'; -- "X" => "X" elsif (cam_array(addr)(i)='0' and x_array(addr)(i)='1') then -- "X" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '1'; -- "U" => "1" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='1') then -- "U" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '0'; end if; end if; end loop; end if; else -- 2 Cycle write ------------------- -- 2 CYCLE WRITE -- ------------------- ----------------- -- WRITE_ZEROS -- ----------------- if (write0_done = true) then for i in 0 to width-1 loop if (pattern(i) = '0') then -- "0" => "0" if (cam_array(addr)(i)='0' and x_array(addr)(i)='0') then -- "0" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '0'; -- "1" => "X" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='0') then -- "1" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '1'; -- "X" => "X" elsif (cam_array(addr)(i)='0' and x_array(addr)(i)='1') then -- "X" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '1'; -- "U" => "0" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='1') then -- "U" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '0'; end if; elsif (pattern(i) = '1') then -- "0" => "X" if (cam_array(addr)(i)='0' and x_array(addr)(i)='0') then -- "0" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '1'; -- "1" => "1" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='0') then -- "1" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '0'; -- "X" => "X" elsif (cam_array(addr)(i)='0' and x_array(addr)(i)='1') then -- "X" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '1'; -- "U" => "1" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='1') then -- "U" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '0'; end if; end if; end loop; end if; ---------------- -- WRITE_ONES -- ---------------- if (write1_done = true) then for i in 0 to width-1 loop if (pattern(i) = '0') then -- "0" => "0" if (cam_array(addr)(i)='0' and x_array(addr)(i)='0') then -- "0" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '0'; -- "1" => "U" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='0') then -- "1" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '1'; -- "X" => "0" elsif (cam_array(addr)(i)='0' and x_array(addr)(i)='1') then -- "X" cam_array_tmp(addr)(i) := '0'; x_array_tmp(addr)(i) := '0'; -- "U" => "U" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='1') then -- "U" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '1'; end if; elsif (pattern(i) = '1') then -- "0" => "U" if (cam_array(addr)(i)='0' and x_array(addr)(i)='0') then -- "0" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '1'; -- "1" => "1" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='0') then -- "1" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '0'; -- "X" => "1" elsif (cam_array(addr)(i)='0' and x_array(addr)(i)='1') then -- "X" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '0'; -- "U" => "U" elsif (cam_array(addr)(i)='1' and x_array(addr)(i)='1') then -- "U" cam_array_tmp(addr)(i) := '1'; x_array_tmp(addr)(i) := '1'; end if; end if; end loop; end if; end if; -- wrxused_int else -- if wrdelete = '1' then -------------------- -- 2 CYCLE DELETE -- -------------------- -- Delete is a 2-cycle write ---------------- -- WRITE_ONES -- ---------------- if (write0_done = true) then for i in 0 to width-1 loop cam_array_tmp(addr)(i) := '1'; end loop; end if; ------------- -- WRITE_X -- ------------- if (write1_done = true) then for i in 0 to width-1 loop x_array_tmp(addr)(i) := '1'; end loop; end if; end if; -- wrdelete cam_array <= cam_array_tmp; x_array <= x_array_tmp; -------------------------------------- -- FAST MULTIPLE: READ DURING WRITE -- -------------------------------------- -- Now we need to update mbits, mcount during the write. if (match_mode = "FAST_MULTIPLE") then mfound_int <= '0'; maddress_int <= (others => '1'); count := 0; mbits_tmp := (others => '0'); if ((writex_done = true) and (wrxused_int = '1')) then WADDR_FM_2: for i in 0 to numwords-1 loop WWORD_FM_2: for j in 0 to width-1 loop if (((x_array_tmp(i)(j) = '0') and (cam_array_tmp(i)(j) = (pattern(j) xor wrx_int(j)))) or ((x_array_tmp(i)(j) = '1') and (cam_array_tmp(i)(j) = '0'))) then if (j = width-1) then if ((count = 0) and (mstart_used = false)) then mfound_int <= '1'; maddress_int <= ieee.std_logic_arith.conv_std_logic_vector(i, widthad); end if; mbits_tmp(i) := '1'; count := count + 1; end if; else exit WWORD_FM_2; end if; end loop WWORD_FM_2; end loop WADDR_FM_2; else WADDR_FM_3: for i in 0 to numwords-1 loop WWORD_FM_3: for j in 0 to width-1 loop if (((x_array_tmp(i)(j) = '0') and (cam_array_tmp(i)(j) = pattern(j))) or ((x_array_tmp(i)(j) = '1') and (cam_array_tmp(i)(j) = '0'))) then if (j = width-1) then if ((count = 0) and (mstart_used = false)) then mfound_int <= '1'; maddress_int <= ieee.std_logic_arith.conv_std_logic_vector(i, widthad); end if; mbits_tmp(i) := '1'; count := count + 1; end if; else exit WWORD_FM_3; end if; end loop WWORD_FM_3; end loop WADDR_FM_3; end if; mcount_int <= ieee.std_logic_arith.conv_std_logic_vector(count, widthad); mbits_int <= mbits_tmp; end if; -- end of FAST MULTIPLE --------------------------------- -- MULTIPLE: READ DURING WRITE -- --------------------------------- if (match_mode = "MULTIPLE") then mfound_int <= '0'; maddress_int <= (others => '1'); mbits_tmp := (others => '0'); if ((writex_done = true) and (wrxused_int = '1')) then mcount_int <= (others => '0'); first_read_in_write <= false; else if (first_read_in_write = false) then first_read_in_write <= true; -- Read even addresses but they appear on the odd locations -- of mbits. count := 0; WADDR_MM_2: for i in 0 to numwords-1 loop if ( (i mod 2) = 0 ) then if (mbits_int(i) = '1') then -- counting previous even address matches count := count + 1; end if; WWORD_MM_2: for j in 0 to width-1 loop if (((x_array_tmp(i)(j) = '0') and (cam_array_tmp(i)(j) = pattern(j))) or ((x_array_tmp(i)(j) = '1') and (cam_array_tmp(i)(j) = '0'))) then if (j = width-1) then mbits_tmp(i+1) := '1'; count := count + 1; end if; else exit WWORD_MM_2; end if; end loop WWORD_MM_2; end if; end loop WADDR_MM_2; else first_read_in_write <= false; -- Read odd addresses. count := 0; WADDR_MM_3: for i in numwords-1 downto 0 loop if ((i mod 2) = 1) then mbits_tmp(i-1) := mbits_tmp(i); else WWORD_MM_3: for j in 0 to width-1 loop if (((x_array_tmp(i)(j) = '0') and (cam_array_tmp(i)(j) = pattern(j))) or ((x_array_tmp(i)(j) = '1') and (cam_array_tmp(i)(j) = '0'))) then if (j = width-1) then mbits_tmp(i) := '1'; count := count + 1; end if; else exit WWORD_MM_3; end if; end loop WWORD_MM_3; end if; end loop WADDR_MM_3; end if; mcount_int <= ieee.std_logic_arith.conv_std_logic_vector(count, widthad); mbits_int <= mbits_tmp; end if; end if; -- end of MULTIPLE ------------------------------ -- SINGLE: READ DURING WRITE -- ------------------------------ if (match_mode = "SINGLE") then mbits_tmp := (others => '0'); index := 0; count := 0; if ((writex_done = true) and (wrxused_int = '1')) then WADDR_SM_2: for i in 0 to numwords-1 loop WWORD_SM_2: for j in 0 to width-1 loop if (((x_array_tmp(i)(j) = '0') and (cam_array_tmp(i)(j) = (pattern(j) xor wrx_int(j)))) or ((x_array_tmp(i)(j) = '1') and (cam_array_tmp(i)(j) = '0'))) then if (j = width-1) then mbits_tmp(i) := '1'; index := i; count := 1; exit WADDR_SM_2; end if; else exit WWORD_SM_2; end if; end loop WWORD_SM_2; end loop WADDR_SM_2; else WADDR_SM_3: for i in 0 to numwords-1 loop WWORD_SM_3: for j in 0 to width-1 loop if (((x_array_tmp(i)(j) = '0') and (cam_array_tmp(i)(j) = pattern(j))) or ((x_array_tmp(i)(j) = '1') and (cam_array_tmp(i)(j) = '0'))) then if (j = width-1) then mbits_tmp(i) := '1'; index := i; count := 1; exit WADDR_SM_3; end if; else exit WWORD_SM_3; end if; end loop WWORD_SM_3; end loop WADDR_SM_3; end if; mcount_int <= ieee.std_logic_arith.conv_std_logic_vector(count, widthad); mbits_int <= mbits_tmp; if (count = 0) then mfound_int <= '0'; maddress_int <= (others => '0'); else mfound_int <= '1'; maddress_int <= ieee.std_logic_arith.conv_std_logic_vector(index, widthad); end if; end if; -- end of SINGLE end if; -- end of Write end if; -- end of wren_rgd check end if; -- end of pattern change end if; -- end of inclock event end process READ_WRITE; OUTPUTREG: process (outaclr_int, outclock, inclock) begin if (output_reg = "OUTCLOCK" or output_reg = "INCLOCK") then if (outaclr_int = '1') and ((output_aclr = "ON") or (output_aclr = "OFF" and output_reg = "INCLOCK")) then maddress_rgd <= (others => '0'); mbits_rgd <= (others => '0'); mfound_rgd <= '0'; mcount_rgd <= (others => '0'); else if (outclock'event and outclock = '1' and outclocken = '1' and output_reg = "OUTCLOCK") or (inclock'event and inclock = '1' and inclocken = '1' and output_reg = "INCLOCK") then mbits_rgd <= mbits_int; mcount_rgd <= mcount_int; mfound_rgd <= mfound_int; maddress_rgd <= maddress_int; end if; end if; end if; end process OUTPUTREG; WRITE_BUSY_CONTROL: process(wren_rgd, wraddress_rgd, write_start_rgd) begin if (wren_rgd'event and wren_rgd = '0') then wrbusy_int <= '0'; elsif (wren_rgd'event and wren_rgd = '1') then wrbusy_int <= '1'; elsif (wraddress_rgd'event and wren_rgd = '1') then wrbusy_int <= '1'; elsif (write_start_rgd'event and write_start_rgd = '1') then wrbusy_int <= '0'; elsif (write_start_rgd'event and write_start_rgd = '0' and wren_rgd = '1') then wrbusy_int <= '1'; end if; end process WRITE_BUSY_CONTROL; WRITE_CONTROL: process(write0_done, write1_done, writex_done, wrbusy_int) begin if (wrbusy_int'event and wrbusy_int = '0') then write0 <= false; end if; if (wrbusy_int'event and wrbusy_int = '1') then write0 <= true; write1 <= false; writex <= false; else if (write0_done'event and write0_done = true) then write1 <= true; if ((wrxused_int = '1') and (wrx_reg /= "UNUSED") and (wrx_aclr /= "UNUSED")) then write0 <= false; end if; else if (write1_done'event and write1_done = true) then if ((wrxused_int = '1') and (wrx_reg /= "UNUSED") and (wrx_aclr /= "UNUSED")) then writex <= true; else writex <= false; end if; write1 <= false; else if (writex_done'event and writex_done = true) then write0 <= false; write1 <= false; writex <= false; end if; end if; end if; end if; end process WRITE_CONTROL; READ_CONTROL: process(mstart_rgd1, mstart_rgd2, mnext, mstart_used) begin if (mstart_used'event) then -- 1st toggle of mstart get_next_match <= false; else if (mstart_rgd1'event and mstart_rgd1 = '1') then if (match_mode = "SINGLE" or match_mode = "FAST_MULTIPLE") then rdbusy_int <= '0'; else rdbusy_int <= '1'; -- must be "MULTIPLE" mode end if; elsif (mstart_rgd2'event and mstart_rgd2 = '1') then rdbusy_int <= '0'; end if; if (mnext'event and mnext = '1' and get_first_match = true) then get_next_match <= true; elsif (mnext'event and mnext = '0') then get_next_match <= false; end if; end if; end process READ_CONTROL; end; ---------------------------------------------------------------------------- -- Module Name : altdpram -- -- Description : Parameterized Dual Port RAM megafunction -- -- Limitation : This megafunction is provided only for backward -- compatibility in Cyclone, Stratix, and Stratix GX -- designs. -- -- Results expected : RAM having dual ports behaviour -- ---------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use std.textio.all; use work.ALTERA_DEVICE_FAMILIES.all; use work.ALTERA_COMMON_CONVERSION.all; -- ENTITY DECLARATION entity altdpram is generic ( width : natural; widthad : natural; numwords : natural := 0; lpm_file : string := "UNUSED"; lpm_hint : string := "USE_EAB=ON"; use_eab : string := "ON"; indata_reg : string := "INCLOCK"; indata_aclr : string := "ON"; wraddress_reg : string := "INCLOCK"; wraddress_aclr : string := "ON"; wrcontrol_reg : string := "INCLOCK"; wrcontrol_aclr : string := "ON"; rdaddress_reg : string := "OUTCLOCK"; rdaddress_aclr : string := "ON"; rdcontrol_reg : string := "OUTCLOCK"; rdcontrol_aclr : string := "ON"; outdata_reg : string := "UNREGISTERED"; outdata_aclr : string := "ON"; maximum_depth : natural := 2048; intended_device_family : string := "APEX20KE"; lpm_type : string := "altdpram"); port ( wren : in std_logic := '0'; data : in std_logic_vector(width-1 downto 0); wraddress : in std_logic_vector(widthad-1 downto 0); inclock : in std_logic := '0'; inclocken : in std_logic := '1'; rden : in std_logic := '1'; rdaddress : in std_logic_vector(widthad-1 downto 0); outclock : in std_logic := '0'; outclocken : in std_logic := '1'; aclr : in std_logic := '0'; q : out std_logic_vector(width-1 downto 0) ); end altdpram; -- ARCHITECTURE DECLARATION architecture behavior of altdpram is -- TYPE DECLARATION type alt_memory is array((2**WIDTHAD)-1 downto 0) of std_logic_vector(WIDTH-1 downto 0); -- SIGNAL DECLARATION signal idata_tmp: std_logic_vector(WIDTH-1 downto 0) := (OTHERS => '0'); signal idata_reg: std_logic_vector(WIDTH-1 downto 0) := (OTHERS => '0'); signal idata_hi : std_logic_vector(WIDTH-1 downto 0) := (OTHERS => '0'); signal idata_lo : std_logic_vector(WIDTH-1 downto 0) := (OTHERS => '0'); signal iq_tmp : std_logic_vector(WIDTH-1 downto 0) := (OTHERS => '0'); signal iq_reg : std_logic_vector(WIDTH-1 downto 0) := (OTHERS => '0'); signal irdaddress_tmp : std_logic_vector(WIDTHAD-1 downto 0) := (OTHERS => '0'); signal irdaddress_reg : std_logic_vector(WIDTHAD-1 downto 0) := (OTHERS => '0'); signal iwraddress_tmp : std_logic_vector(WIDTHAD-1 downto 0) := (OTHERS => '0'); signal iwraddress_reg : std_logic_vector(WIDTHAD-1 downto 0) := (OTHERS => '0'); signal iwraddress_hi : std_logic_vector(WIDTHAD-1 downto 0) := (OTHERS => '0'); signal iwraddress_lo : std_logic_vector(WIDTHAD-1 downto 0) := (OTHERS => '0'); signal iwren_tmp : std_logic := '0'; signal iwren_reg : std_logic := '0'; signal iwren_hi : std_logic := '0'; signal iwren_lo : std_logic := '0'; signal irden_tmp : std_logic := '0'; signal irden_reg : std_logic := '0'; signal write_at_low_clock : boolean := false; signal rden_low_output_0 : boolean := false; begin -- PROCESS BLOCKS INITIAL: process (inclock, outclock) variable init : boolean := false; begin if (not init) then if ((lpm_hint = "USE_EAB=ON") and (use_eab = "ON")) then if (wrcontrol_reg = "INCLOCK") then write_at_low_clock <= true; end if; if (IS_FAMILY_APEX20K(intended_device_family)) then rden_low_output_0 <= true; end if; end if; init := true; end if; end process; -- initial SYNC: process(data, idata_reg, rden, irden_reg, rdaddress, irdaddress_reg, wren, iwren_reg, wraddress, iwraddress_reg, iq_tmp, iq_reg, aclr) begin if ((rdaddress_reg = "INCLOCK") or (rdaddress_reg = "OUTCLOCK")) then irdaddress_tmp <= irdaddress_reg; else irdaddress_tmp <= rdaddress; end if; if ((rdcontrol_reg = "INCLOCK") or (rdcontrol_reg = "OUTCLOCK")) then irden_tmp <= irden_reg; else irden_tmp <= rden; end if; if (wraddress_reg = "INCLOCK") then iwraddress_tmp <= iwraddress_reg; else iwraddress_tmp <= wraddress; end if; if (wrcontrol_reg = "INCLOCK") then iwren_tmp <= iwren_reg; else iwren_tmp <= wren; end if; if (indata_reg = "INCLOCK") then idata_tmp <= idata_reg; else idata_tmp <= data; end if; if (outdata_reg = "OUTCLOCK") then q <= iq_reg; else q <= iq_tmp; end if; if (aclr = '1') then if( (indata_aclr = "ON") and ( indata_reg /= "UNREGISTERED") ) then idata_tmp <= (OTHERS => '0'); end if; if( (wraddress_aclr = "ON") and ( wraddress_reg /= "UNREGISTERED") )then iwraddress_tmp <= (OTHERS => '0'); end if; if( (wrcontrol_aclr = "ON") and ( wrcontrol_reg /= "UNREGISTERED") )then iwren_tmp <= '0'; end if; if( (rdaddress_aclr = "ON") and ( rdaddress_reg /= "UNREGISTERED") )then irdaddress_tmp <= (OTHERS => '0'); end if; if( (rdcontrol_aclr = "ON") and ( rdcontrol_reg /= "UNREGISTERED") )then irden_tmp <= '0'; end if; if( (outdata_aclr = "ON") and (outdata_reg /= "UNREGISTERED") ) then q <= (OTHERS => '0'); end if; end if; end process; -- sync SYNC2: process(idata_hi, idata_lo, iwraddress_hi, iwraddress_lo, iwren_hi, iwren_lo) begin if (write_at_low_clock) then idata_reg <= idata_lo; iwren_reg <= iwren_lo; iwraddress_reg <= iwraddress_lo; else idata_reg <= idata_hi; iwren_reg <= iwren_hi; iwraddress_reg <= iwraddress_hi; end if; end process; -- sync2 REGISTERS: process (inclock, outclock) begin -- WRITE REGS -- if ((aclr = '1') and (indata_aclr = "ON") and (indata_reg /= "UNREGISTERED") ) then idata_hi <= (OTHERS => '0'); idata_lo <= (OTHERS => '0'); elsif ((inclock'event) and (inclock = '1') and (inclocken = '1')) then idata_hi <= data; elsif ((inclock'event) and (inclock = '0')) then idata_lo <= idata_hi; end if; if ((aclr = '1') and (wraddress_aclr = "ON") and (wraddress_reg /= "UNREGISTERED") ) then iwraddress_hi <= (OTHERS => '0'); iwraddress_lo <= (OTHERS => '0'); elsif ((inclock'event) and (inclock = '1') and (inclocken = '1')) then iwraddress_hi <= wraddress; elsif ((inclock'event) and (inclock = '0')) then iwraddress_lo <= iwraddress_hi; end if; if ((aclr = '1') and (wrcontrol_aclr = "ON") and (wrcontrol_reg /= "UNREGISTERED") ) then iwren_hi <= '0'; iwren_lo <= '0'; elsif ((inclock'event) and (inclock = '1') and (inclocken = '1')) then iwren_hi <= wren; elsif ((inclock'event) and (inclock = '0')) then iwren_lo <= iwren_hi; end if; -- READ REGS -- if ((aclr = '1') and (outdata_aclr = "ON") and ( outdata_reg /= "UNREGISTERED") ) then iq_reg <= (OTHERS => '0'); elsif ((outclock'event) and (outclock = '1') and (outclocken = '1')) then iq_reg <= iq_tmp; end if; if (rdaddress_reg = "INCLOCK") then if ((aclr = '1') and (rdaddress_aclr = "ON") and (rdaddress_reg /= "UNREGISTERED") ) then irdaddress_reg <= (OTHERS => '0'); elsif ((inclock'event) and (inclock = '1') and (inclocken = '1')) then irdaddress_reg <= rdaddress; end if; end if; if (rdcontrol_reg = "INCLOCK") then if ((aclr = '1') and (rdcontrol_aclr = "ON") and (rdcontrol_reg /= "UNREGISTERED") ) then irden_reg <= '0'; elsif ((inclock'event) and (inclock = '1') and (inclocken = '1')) then irden_reg <= rden; end if; end if; if (rdaddress_reg = "OUTCLOCK") then if ((aclr = '1') and (rdaddress_aclr = "ON") and (rdaddress_reg /= "UNREGISTERED") ) then irdaddress_reg <= (OTHERS => '0'); elsif ((outclock'event) and (outclock = '1') and (outclocken = '1')) then irdaddress_reg <= rdaddress; end if; end if; if (rdcontrol_reg = "OUTCLOCK") then if ((aclr = '1') and (rdcontrol_aclr = "ON") and (rdcontrol_reg /= "UNREGISTERED") ) then irden_reg <= '0'; elsif ((outclock'event) and (outclock = '1') and (outclocken = '1')) then irden_reg <= rden; end if; end if; end process; -- registers MEMORY: process(idata_tmp, iwren_tmp, irden_tmp, irdaddress_tmp, iwraddress_tmp) variable mem_data : alt_memory; variable mem_data_word : std_logic_vector(width-1 downto 0); variable mem_init : boolean := false; variable i : integer := 0; variable j : integer := 0; variable k : integer := 0; variable n : integer := 0; variable m : integer := 0; variable lineno : integer := 0; variable buf : line; variable booval : boolean; FILE mem_data_file : TEXT; variable base : string(2 downto 1); variable byte : string(2 downto 1); variable rec_type : string(2 downto 1); variable datain : string(2 downto 1); variable addr : string(2 downto 1); variable checksum : string(2 downto 1); variable startadd: string(4 downto 1); variable ibase : integer := 0; variable ibyte : integer := 0; variable istartadd : integer := 0; variable check_sum_vec : std_logic_vector(7 downto 0); variable check_sum_vec_tmp : std_logic_vector(7 downto 0); begin -- INITIALIZE -- if NOT(mem_init) then -- INITIALIZE TO 0 -- for i in mem_data'LOW to mem_data'HIGH loop mem_data(i) := (OTHERS => '0'); end loop; if (lpm_file /= "UNUSED") then FILE_OPEN(mem_data_file, LPM_FILE, READ_MODE); WHILE NOT ENDFILE(mem_data_file) loop booval := true; READLINE(mem_data_file, buf); lineno := lineno + 1; check_sum_vec := (OTHERS => '0'); if (buf(buf'LOW) = ':') then i := 1; SHRINK_LINE(buf, i); READ(L=>buf, VALUE=>byte, good=>booval); if (not booval) then ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format!" SEVERITY ERROR; end if; ibyte := HEX_STR_TO_INT(byte); check_sum_vec := unsigned(check_sum_vec) + unsigned(CONV_STD_LOGIC_VECTOR(ibyte, 8)); READ(L=>buf, VALUE=>startadd, good=>booval); if (not booval) then ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format! " SEVERITY ERROR; end if; istartadd := HEX_STR_TO_INT(startadd); addr(2) := startadd(4); addr(1) := startadd(3); check_sum_vec := unsigned(check_sum_vec) + unsigned(CONV_STD_LOGIC_VECTOR(HEX_STR_TO_INT(addr), 8)); addr(2) := startadd(2); addr(1) := startadd(1); check_sum_vec := unsigned(check_sum_vec) + unsigned(CONV_STD_LOGIC_VECTOR(HEX_STR_TO_INT(addr), 8)); READ(L=>buf, VALUE=>rec_type, good=>booval); if not (booval) then ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format! " SEVERITY ERROR; end if; check_sum_vec := unsigned(check_sum_vec) + unsigned(CONV_STD_LOGIC_VECTOR(HEX_STR_TO_INT(rec_type), 8)); else ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format! " SEVERITY ERROR; end if; case rec_type is when "00"=> -- Data record i := 0; k := (WIDTH + 7) / 8; -- # of bytes per entry while (i < ibyte) loop mem_data_word := (others => '0'); n := (k - 1)*8; m := width - 1; for j in 1 to k loop READ(L=>buf, VALUE=>datain,good=>booval); -- read in data a byte (2 hex chars) at a time. if not (booval) then ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format! " SEVERITY ERROR; end if; check_sum_vec := unsigned(check_sum_vec) + unsigned(CONV_STD_LOGIC_VECTOR(HEX_STR_TO_INT(datain), 8)); mem_data_word(m downto n) := CONV_STD_LOGIC_VECTOR(HEX_STR_TO_INT(datain), m-n+1); m := n - 1; n := n - 8; end loop; i := i + k; mem_data(ibase + istartadd) := mem_data_word; istartadd := istartadd + 1; end loop; when "01"=> exit; when "02"=> ibase := 0; if (ibyte /= 2) then ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format for record type 02! " SEVERITY ERROR; end if; for i in 0 to (ibyte-1) loop READ(L=>buf, VALUE=>base,good=>booval); ibase := (ibase * 256) + HEX_STR_TO_INT(base); if not (booval) then ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format! " SEVERITY ERROR; end if; check_sum_vec := unsigned(check_sum_vec) + unsigned(CONV_STD_LOGIC_VECTOR(HEX_STR_TO_INT(base), 8)); end loop; ibase := ibase * 16; when OTHERS => ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal record type in Intel Hex File! " SEVERITY ERROR; end case; READ(L=>buf, VALUE=>checksum,good=>booval); if (not booval) then ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Checksum is missing! " SEVERITY ERROR; end if; check_sum_vec := unsigned(not (check_sum_vec)) + 1 ; check_sum_vec_tmp := CONV_STD_LOGIC_VECTOR(HEX_STR_TO_INT(checksum),8); if (unsigned(check_sum_vec) /= unsigned(check_sum_vec_tmp)) then ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Incorrect checksum!" SEVERITY ERROR; end if; end loop; FILE_CLOSE(mem_data_file); end if; mem_init := TRUE; else -- already initialized -- MEMORY FUNCTION -- -- Write and read data to and from the memory. -- If write and read are at the same address, whatever wrote into -- the memory will immediately reflected at the read results. if (iwren_tmp = '1') then mem_data (ieee.std_logic_unsigned.conv_integer(iwraddress_tmp)) := idata_tmp; end if; if (irden_tmp = '1') then iq_tmp <= mem_data(ieee.std_logic_unsigned.conv_integer(irdaddress_tmp)); elsif (rden_low_output_0) then iq_tmp <= (OTHERS => '0'); end if; end if; -- if NOT(mem_init) end process; -- memory end behavior; -- altdpram ---START_ENTITY_HEADER---------------------------------------------------------- -- -- Entity Name : ALTSYNCRAM -- -- Description : Synchronous ram model for Stratix series family -- -- Limitation : -- ---END_ENTITY_HEADER------------------------------------------------------------ library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use std.textio.all; use work.ALTERA_COMMON_CONVERSION.all; use work.ALTERA_DEVICE_FAMILIES.all; -- BEGINNING OF ENTITY -- ENTITY DECLARATION entity altsyncram is -- GENERIC DECLARATION generic ( -- PORT A PARAMETERS width_a : integer := 1; widthad_a : integer := 1; numwords_a : integer := 0; outdata_reg_a : string := "UNREGISTERED"; address_aclr_a : string := "NONE"; outdata_aclr_a : string := "NONE"; indata_aclr_a : string := "NONE"; wrcontrol_aclr_a : string := "NONE"; byteena_aclr_a : string := "NONE"; width_byteena_a : integer := 1; clock_enable_input_a : string := "NORMAL"; clock_enable_output_a : string := "NORMAL"; -- PORT B PARAMETERS width_b : integer := 1; widthad_b : integer := 1; numwords_b : integer := 0; rdcontrol_reg_b : string := "CLOCK1"; address_reg_b : string := "CLOCK1"; outdata_reg_b : string := "UNREGISTERED"; outdata_aclr_b : string := "NONE"; rdcontrol_aclr_b : string := "NONE"; indata_reg_b : string := "CLOCK1"; wrcontrol_wraddress_reg_b : string := "CLOCK1"; byteena_reg_b : string := "CLOCK1"; indata_aclr_b : string := "NONE"; wrcontrol_aclr_b : string := "NONE"; address_aclr_b : string := "NONE"; byteena_aclr_b : string := "NONE"; width_byteena_b : integer := 1; clock_enable_input_b : string := "NORMAL"; clock_enable_output_b : string := "NORMAL"; -- GLOBAL PARAMETERS operation_mode : string := "BIDIR_DUAL_PORT"; byte_size : integer := 8; read_during_write_mode_mixed_ports : string := "DONT_CARE"; ram_block_type : string := "AUTO"; init_file : string := "UNUSED"; init_file_layout : string := "UNUSED"; maximum_depth : integer := 0; intended_device_family : string := "Stratix"; lpm_hint : string := "UNUSED"; lpm_type : string := "altsyncram" ); -- PORT DECLARATION port ( -- INPUT PORT DECLARATION wren_a : in std_logic := '0'; -- Port A write/read enable input wren_b : in std_logic := '0'; -- Port B write enable input rden_b : in std_logic := 'Z'; -- Port B read enable input data_a : in std_logic_vector(width_a - 1 downto 0) := (others => '0'); -- Port A data input data_b : in std_logic_vector(width_b - 1 downto 0) := (others => '0'); -- Port B data input address_a : in std_logic_vector(widthad_a - 1 downto 0) := (others => '0'); -- Port A address input address_b : in std_logic_vector(widthad_b - 1 downto 0) := (others => '0'); -- Port B address input -- clock inputs on both ports and here are their usages: -- Port A -- 1. all input registers must be clocked by clock0. -- 2. output register can be clocked by either by clock0, clock1 or none. -- Port B -- 1. all input registers must be clocked by either clock0 or clock1. -- 2. output register can be clocked by either clock0, clock1 or none. clock0 : in std_logic := '1'; clock1 : in std_logic := '1'; -- clock enable inputs and here are their usages: -- clocken0 -- can only be used for enabling clock0. -- clocken1 -- can only be used for enabling clock1. clocken0 : in std_logic := '1'; clocken1 : in std_logic := '1'; -- clear inputs on both ports and here are their usages: -- Port A -- 1. all input registers can only be cleared by clear0 or none. -- 2. output register can be cleared by either clear0, clear1 or none. -- Port B -- 1. all input registers can be cleared by either clear0, clear1 or none. -- 2. output register can be cleared by either clear0, clear1 or none. aclr0 : in std_logic := '0'; aclr1 : in std_logic := '0'; addressstall_a : in std_logic := '0'; addressstall_b : in std_logic := '0'; byteena_a : in std_logic_vector( (width_byteena_a) - 1 downto 0) := (others => 'Z'); -- Port A byte enable input byteena_b : in std_logic_vector( (width_byteena_b) - 1 downto 0) := (others => 'Z'); -- Port B byte enable input -- OUTPUT PORT DECLARATION q_a : out std_logic_vector(width_a - 1 downto 0); -- Port A output q_b : out std_logic_vector(width_b - 1 downto 0) -- Port B output ); -- TYPE DECLARATION type width_a_array is array (2 ** widthad_a - 1 downto 0) of std_logic_vector(width_a - 1 downto 0); type width_b_array is array (2 ** widthad_b - 1 downto 0) of std_logic_vector(width_b - 1 downto 0); -- FUNCTION DEFINITION -- This procedure read the hex file into the memory content procedure read_my_memory ( constant use_a : in boolean; variable mem_data_a : out width_a_array; variable mem_data_b : out width_b_array ) is variable m_mem_data_word_a : std_logic_vector(width_a-1 downto 0); variable m_mem_data_word_b : std_logic_vector(width_b-1 downto 0); variable i : integer := 0; variable n : integer := 0; variable m : integer := 0; variable m_num_of_bytes : integer := 0; variable m_line_no : integer := 0; variable m_line_buf : line ; variable m_err_check : boolean := true; variable m_base : string(2 downto 1); variable m_ibase : integer := 0; variable m_byte_str : string(2 downto 1); variable m_rec_type : string(2 downto 1); variable m_datain : string(2 downto 1); variable m_addr : string(2 downto 1); variable m_checksum : string(2 downto 1); variable m_startadd : string(4 downto 1); variable m_istartadd : integer := 0; variable m_byte_int : integer := 0; variable m_check_sum_vec : std_logic_vector(7 downto 0); variable m_check_sum_vec_tmp : std_logic_vector(7 downto 0); file m_mem_data_file : text; begin -- Initialize memory content if (use_a) then for i in mem_data_a'low to mem_data_a'high loop mem_data_a(i) := (others => '0'); end loop; else for i in mem_data_b'low to mem_data_b'high loop mem_data_b(i) := (others => '0'); end loop; end if; file_open(m_mem_data_file, init_file, read_mode); while not endfile(m_mem_data_file) loop m_err_check := true; readline(m_mem_data_file, m_line_buf); m_line_no := m_line_no + 1; m_check_sum_vec := (others=> '0'); if (m_line_buf(m_line_buf'low) = ':') then i := 1; SHRINK_LINE(m_line_buf, i); read(l=>m_line_buf, value=>m_byte_str, good=>m_err_check); if not (m_err_check) then assert false report "[Line "& INT_TO_STR_RAM(m_line_no) & "]:Illegal Intel Hex Format!" severity error; end if; m_byte_int := HEX_STR_TO_INT(m_byte_str); m_check_sum_vec := unsigned(m_check_sum_vec) + unsigned(conv_std_logic_vector(m_byte_int, 8)); read(l=>m_line_buf, value=>m_startadd, good=>m_err_check); if not (m_err_check) then assert false report "[Line "& INT_TO_STR_RAM(m_line_no) & "]:Illegal Intel Hex Format! " severity error; end if; m_istartadd := HEX_STR_TO_INT(m_startadd); m_addr(2) := m_startadd(4); m_addr(1) := m_startadd(3); m_check_sum_vec := unsigned(m_check_sum_vec) + unsigned(conv_std_logic_vector(HEX_STR_TO_INT(m_addr), 8)); m_addr(2) := m_startadd(2); m_addr(1) := m_startadd(1); m_check_sum_vec := unsigned(m_check_sum_vec) + unsigned(conv_std_logic_vector(HEX_STR_TO_INT(m_addr), 8)); read(l=>m_line_buf, value=>m_rec_type, good=>m_err_check); if not (m_err_check) then assert false report "[Line "& INT_TO_STR_RAM(m_line_no) & "]:Illegal Intel Hex Format! " severity error; end if; m_check_sum_vec := unsigned(m_check_sum_vec) + unsigned(conv_std_logic_vector(HEX_STR_TO_INT(m_rec_type), 8)); else assert false report "[Line "& INT_TO_STR_RAM(m_line_no) & "]:Illegal Intel Hex Format! " severity error; end if; case m_rec_type is when "00"=> -- Data record i := 0; if (use_a) then m_num_of_bytes := (width_a + 7) / 8; else m_num_of_bytes := (width_b + 7) / 8; end if; while (i < m_byte_int) loop n := (m_num_of_bytes - 1)*8; if (use_a) then m_mem_data_word_a := (others => '0'); m := width_a - 1; else m_mem_data_word_b := (others => '0'); m := width_b - 1; end if; for j in 1 to m_num_of_bytes loop read(l => m_line_buf, value => m_datain, good => m_err_check); if not (m_err_check) then assert false report "[Line "& INT_TO_STR_RAM(m_line_no) & "]:Illegal Intel Hex Format! " severity error; end if; m_check_sum_vec := unsigned(m_check_sum_vec) + unsigned(conv_std_logic_vector(HEX_STR_TO_INT(m_datain), 8)); if (use_a) then m_mem_data_word_a(m downto n) := conv_std_logic_vector(HEX_STR_TO_INT(m_datain), m-n+1); else m_mem_data_word_b(m downto n) := conv_std_logic_vector(HEX_STR_TO_INT(m_datain), m-n+1); end if; m := n - 1; n := n - 8; end loop; i := i + m_num_of_bytes; if (use_a) then mem_data_a(m_ibase + m_istartadd) := m_mem_data_word_a; else mem_data_b(m_ibase + m_istartadd) := m_mem_data_word_b; end if; m_istartadd := m_istartadd + 1; end loop; when "01"=> exit; when "02"=> m_ibase := 0; if (m_byte_int /= 2) then assert false report "[Line "& INT_TO_STR_RAM(m_line_no) & "]:Illegal Intel Hex Format for record type 02! " severity error; end if; for i in 0 to (m_byte_int-1) loop read(l=>m_line_buf, value=>m_base,good=>m_err_check); m_ibase := m_ibase * 256 + HEX_STR_TO_INT(m_base); if not (m_err_check) then assert false report "[Line "& INT_TO_STR_RAM(m_line_no) & "]:Illegal Intel Hex Format! " severity error; end if; m_check_sum_vec := unsigned(m_check_sum_vec) + unsigned(conv_std_logic_vector(HEX_STR_TO_INT(m_base), 8)); end loop; m_ibase := m_ibase * 16; when others=> assert false report "[Line "& INT_TO_STR_RAM(m_line_no) & "]:Illegal record type in Intel Hex File! " severity error; end case; read(l=>m_line_buf, value=>m_checksum, good=>m_err_check); if not (m_err_check) then assert false report"[Line "& INT_TO_STR_RAM(m_line_no) & "]:Checksum is missing! " severity error; end if; m_check_sum_vec := unsigned(not (m_check_sum_vec)) + 1; m_check_sum_vec_tmp := conv_std_logic_vector(HEX_STR_TO_INT(m_checksum),8); if (unsigned(m_check_sum_vec) /= unsigned(m_check_sum_vec_tmp)) then assert false report "[Line "& INT_TO_STR_RAM(m_line_no) & "]:Incorrect checksum!" severity error; end if; end loop; file_close(m_mem_data_file); end read_my_memory; end altsyncram; -- END OF ENTITY -- BEGINNING OF ARCHITECTURE architecture translated of altsyncram is function get_write_mode(read_during_write_mode_mixed_ports : string) return string is begin if (read_during_write_mode_mixed_ports = "UNUSED") or (read_during_write_mode_mixed_ports = "DONT_CARE") then return "DONT_CARE"; end if; return read_during_write_mode_mixed_ports; end get_write_mode; -- CONSTANT DECLARATION constant cread_during_write_mode_mixed_ports : string := get_write_mode(read_during_write_mode_mixed_ports); -- SIGNAL DECLARATION signal i_data_reg_a : std_logic_vector(width_a - 1 downto 0) := (others => '1'); signal i_data_reg_b : std_logic_vector(width_b - 1 downto 0) := (others => '1'); signal i_q_reg_a : std_logic_vector(width_a - 1 downto 0) := (others => '0'); signal i_q_tmp_a : std_logic_vector(width_a - 1 downto 0) := (others => '0'); signal i_q_tmp2_a : std_logic_vector(width_a - 1 downto 0) := (others => '0'); signal i_q_tmp_wren_a : std_logic_vector(width_a - 1 downto 0) := (others => '0'); signal i_q_tmp2_wren_a : std_logic_vector(width_a - 1 downto 0) := (others => '0'); signal i_q_tmp_wren_b : std_logic_vector(width_b - 1 downto 0) := (others => '0'); signal i_q_reg_b : std_logic_vector(width_b - 1 downto 0) := (others => '0'); signal i_q_tmp_b : std_logic_vector(width_b - 1 downto 0) := (others => '0'); signal i_q_tmp2_b : std_logic_vector(width_b - 1 downto 0) := (others => '0'); signal i_byteena_mask_reg_a : std_logic_vector(width_a - 1 downto 0) := (others => '1'); signal i_byteena_mask_reg_b : std_logic_vector(width_b - 1 downto 0) := (others => '1'); signal i_address_reg_a : std_logic_vector(widthad_a - 1 downto 0) := (others => '0'); signal i_address_reg_b : std_logic_vector(widthad_b - 1 downto 0) := (others => '0'); signal i_wren_reg_a : std_logic:= '0'; signal i_wren_reg_b : std_logic:= '0'; signal i_rden_reg_b : std_logic:= '1'; signal i_read_flag_a : std_logic:= '0'; signal i_read_flag_b : std_logic:= '0'; signal i_write_flag_a : std_logic:= '0'; signal i_write_flag_b : std_logic:= '0'; signal i_nmram_write_a : std_logic:= '0'; signal i_nmram_write_b : std_logic:= '0'; signal i_indata_aclr_a : std_logic:= '0'; signal i_address_aclr_a : std_logic:= '0'; signal i_wrcontrol_aclr_a : std_logic:= '0'; signal i_indata_aclr_b : std_logic:= '0'; signal i_address_aclr_b : std_logic:= '0'; signal i_wrcontrol_aclr_b : std_logic:= '0'; signal i_outdata_aclr_a : std_logic:= '0'; signal i_rdcontrol_aclr_b : std_logic:= '0'; signal i_byteena_aclr_a : std_logic:= '0'; signal i_byteena_aclr_b : std_logic:= '0'; signal write_by_a_reg_b : integer := 0; signal write_by_b_reg_a : integer := 0; signal good_to_go_a : std_logic:= '0'; signal good_to_go_b : std_logic:= '0'; signal i_indata_clken_b : std_logic:= '0'; signal i_outdata_clken_b : std_logic:= '0'; signal i_outdata_clken_a : std_logic:= '0'; signal i_wrcontrol_wraddress_clken_b : std_logic:= '0'; signal i_rdcontrol_clken_b : std_logic:= '0'; signal i_address_clken_b : std_logic:= '0'; signal byteena_a_unconnected : std_logic:= '0'; signal byteena_b_unconnected : std_logic:= '0'; signal need_init : boolean := true; signal default_val : std_logic := '0'; signal i_numwords_a : integer := numwords_a; signal i_numwords_b : integer := numwords_b; signal i_data_zero_a : std_logic_vector (width_a - 1 downto 0) := (others => '0'); signal i_data_zero_b : std_logic_vector (width_b - 1 downto 0) := (others => '0'); signal i_data_ones_a : std_logic_vector (width_a - 1 downto 0) := (others => '1'); signal i_data_ones_b : std_logic_vector (width_b - 1 downto 0) := (others => '1'); begin -- Parameter Checking process begin if ((operation_mode /= "BIDIR_DUAL_PORT") and (operation_mode /= "SINGLE_PORT") and (operation_mode /= "DUAL_PORT") and (operation_mode /= "ROM")) then assert false report "Error: Not a valid operation mode." severity error; end if; if ((ram_block_type /= "M4K") and (ram_block_type /= "M512") and (ram_block_type /= "LARGE") and (ram_block_type /= "MEGARAM") and (ram_block_type /= "M-RAM") and (ram_block_type /= "AUTO")) then assert false report "Error: RAM_BLOCK_TYPE HAS AN INVALID VALUE. IT CAN ONLY BE M512, M4K, M-RAM OR AUTO" severity error; end if; if ((cread_during_write_mode_mixed_ports /= "DONT_CARE") and (cread_during_write_mode_mixed_ports /= "OLD_DATA")) then assert false report "Error: INVALID VALUE FOR READ_DURING_WRITE_MODE_MIXED_PORTS PARAMETER. IT HAS TO BE OLD_DATA OR DONT_CARE" severity error; end if; if (((ram_block_type = "M-RAM") or (ram_block_type = "MEGARAM")) and (init_file /= "UNUSED")) then assert false report "Error: M-RAM block type doesn't support the use of an initialization file" severity error; end if; if ((byte_size /= 8) and (byte_size /= 9) and (not IS_FAMILY_STRATIXII(intended_device_family))) then assert false report "Error: BYTE SIZE HAS TO BE EITHER 8 or 9" severity error; end if; if ((byte_size /= 8) and (byte_size /= 9) and (byte_size /= 1) and (byte_size /= 2) and (byte_size /= 4) and (IS_FAMILY_STRATIXII(intended_device_family))) then assert false report "Error: BYTE SIZE HAS TO BE EITHER 1, 2, 4, 8 or 9" severity error; end if; if (width_a <= 0) then assert false report "Error: Invalid value for WIDTH_A parameter" severity error; end if; if ((width_b <= 0) and ((operation_mode /= "SINGLE_PORT") or (operation_mode /= "ROM"))) then assert false report "Error: Invalid value for WIDTH_B parameter" severity error; end if; if (widthad_a <= 0) then assert false report "Error: Invalid value for WIDTHAD_A parameter" severity error; end if; if ((width_b <= 0) and ((operation_mode /= "SINGLE_PORT") or (operation_mode /= "ROM"))) then assert false report "Error: Invalid value for WIDTHAD_B parameter" severity error; end if; if ((operation_mode = "ROM") and ((ram_block_type = "M-RAM") or (ram_block_type = "MEGARAM"))) then assert false report "Error: ROM mode does not support ram_block_type = M-RAM" severity error; end if; if (((wrcontrol_aclr_a /= "NONE") and (wrcontrol_aclr_a /= "UNUSED")) and (ram_block_type = "M512") and (operation_mode = "SINGLE_PORT")) then assert false report "Error: Wren_a cannot have clear in single port mode for M512 block" severity error; end if; if ((operation_mode = "DUAL_PORT") and (i_numwords_a * width_a /= i_numwords_b * width_b)) then assert false report "Error: Total number of bits of port A and port B should be the same for dual port mode" severity error; end if; if (((rdcontrol_aclr_b /= "NONE") and (rdcontrol_aclr_b /= "UNUSED")) and (ram_block_type = "M512") and (operation_mode = "DUAL_PORT")) then assert false report "Error: rden_b cannot have clear in simple dual port mode for M512 block" severity error; end if; if ((operation_mode = "BIDIR_DUAL_PORT") and (i_numwords_a * width_a /= i_numwords_b * width_b)) then assert false report "Error: Total number of bits of port A and port B should be the same for bidir dual port mode" severity error; end if; if ((operation_mode = "BIDIR_DUAL_PORT") and (ram_block_type = "M512")) then assert false report "Error: M512 block type doesn't support bidir dual mode" severity error; end if; if (((ram_block_type = "M-RAM") or (ram_block_type = "MEGARAM")) and (cread_during_write_mode_mixed_ports = "OLD_DATA")) then assert false report "Error: M-RAM doesn't support OLD_DATA value for READ_DURING_WRITE_MODE_MIXED_PORTS parameter" severity error; end if; if ((not IS_FAMILY_STRATIXII(intended_device_family)) and (clock_enable_input_a = "BYPASS")) then assert false report "Error: Non Stratix II family does not support BYPASS value for CLOCK_ENABLE_INPUT_A" severity error; end if; if ((not IS_FAMILY_STRATIXII(intended_device_family)) and (clock_enable_output_a = "BYPASS")) then assert false report "Error: Non Stratix II family does not support BYPASS value for CLOCK_ENABLE_OUTPUT_A" severity error; end if; if ((not IS_FAMILY_STRATIXII(intended_device_family)) and (clock_enable_input_b = "BYPASS")) then assert false report "Error: Non Stratix II family does not support BYPASS value for CLOCK_ENABLE_INPUT_B" severity error; end if; if ((not IS_FAMILY_STRATIXII(intended_device_family)) and (clock_enable_output_b = "BYPASS")) then assert false report "Error: Non Stratix II family does not support BYPASS value for CLOCK_ENABLE_OUTPUT_B" severity error; end if; wait; end process; -- SIGNAL ASSIGNMENTS -- Checking ram_block_type and setting default_val IFG01: if ((((ram_block_type = "AUTO") and (cread_during_write_mode_mixed_ports = "DONT_CARE")) or (ram_block_type = "MEGARAM") or (ram_block_type = "M-RAM")) and (operation_mode /= "ROM")) generate default_val <= 'X'; end generate IFG01; IFG02: if (((ram_block_type /= "AUTO") or (cread_during_write_mode_mixed_ports /= "DONT_CARE")) and (ram_block_type /= "MEGARAM") and (ram_block_type /= "M-RAM")) generate default_val <= '0'; end generate IFG02; -- Assigning the correct clock enable signals based on the input clock -- for data in b IFG05: if ((indata_reg_b = "CLOCK0") and (clock_enable_input_b = "NORMAL")) generate i_indata_clken_b <= clocken0; end generate IFG05; IFG05a: if (clock_enable_input_b = "BYPASS") generate i_indata_clken_b <= '1'; end generate IFG05a; IFG06: if ((indata_reg_b = "CLOCK1") and (clock_enable_input_b = "NORMAL")) generate i_indata_clken_b <= clocken1; end generate IFG06; IFG07: if ((indata_reg_b /= "CLOCK0") and (indata_reg_b /= "CLOCK1") and (clock_enable_input_b = "NORMAL")) generate i_indata_clken_b <= '0'; end generate IFG07; -- for wren b and address b in bidir_dual_port mode IFG08: if ((wrcontrol_wraddress_reg_b = "CLOCK0") and (clock_enable_input_b = "NORMAL")) generate i_wrcontrol_wraddress_clken_b <= clocken0; end generate IFG08; IFG08a: if (clock_enable_input_b = "BYPASS") generate i_wrcontrol_wraddress_clken_b <= '1'; end generate IFG08a; IFG09: if ((wrcontrol_wraddress_reg_b = "CLOCK1") and (clock_enable_input_b = "NORMAL")) generate i_wrcontrol_wraddress_clken_b <= clocken1; end generate IFG09; IFG10: if ((wrcontrol_wraddress_reg_b /= "CLOCK0") and (wrcontrol_wraddress_reg_b /= "CLOCK1") and (clock_enable_input_b = "NORMAL")) generate i_wrcontrol_wraddress_clken_b <= '0'; end generate IFG10; -- for rden b IFG11: if ((rdcontrol_reg_b = "CLOCK0") and (clock_enable_input_b = "NORMAL")) generate i_rdcontrol_clken_b <= clocken0; end generate IFG11; IFG11a: if (clock_enable_input_b = "BYPASS") generate i_rdcontrol_clken_b <= '1'; end generate IFG11a; IFG12: if ((rdcontrol_reg_b = "CLOCK1") and (clock_enable_input_b = "NORMAL")) generate i_rdcontrol_clken_b <= clocken1; end generate IFG12; IFG13: if ((rdcontrol_reg_b /= "CLOCK0") and (rdcontrol_reg_b /= "CLOCK1") and (clock_enable_input_b = "NORMAL")) generate i_rdcontrol_clken_b <= '0'; end generate IFG13; -- for address b for dual_port mode IFG14: if ((address_reg_b = "CLOCK0") and (clock_enable_input_b = "NORMAL")) generate i_address_clken_b <= clocken0; end generate IFG14; IFG14a: if (clock_enable_input_b = "BYPASS") generate i_address_clken_b <= '1'; end generate IFG14a; IFG15: if ((address_reg_b = "CLOCK1") and (clock_enable_input_b = "NORMAL")) generate i_address_clken_b <= clocken1; end generate IFG15; IFG16: if ((address_reg_b /= "CLOCK0") and (address_reg_b /= "CLOCK1") and (clock_enable_input_b = "NORMAL")) generate i_address_clken_b <= '0'; end generate IFG16; -- for data out b IFG17: if ((outdata_reg_b = "CLOCK0") and (clock_enable_output_b = "NORMAL")) generate i_outdata_clken_b <= clocken0; end generate IFG17; IFG17a: if (clock_enable_output_b = "BYPASS") generate i_outdata_clken_b <= '1'; end generate IFG17a; IFG18 : if ((outdata_reg_b = "CLOCK1") and (clock_enable_output_b = "NORMAL")) generate i_outdata_clken_b <= clocken1; end generate IFG18; IFG19 : if ((outdata_reg_b /= "CLOCK0") and (outdata_reg_b /= "CLOCK1") and (clock_enable_output_b = "NORMAL")) generate i_outdata_clken_b <= '0'; end generate IFG19; -- for data out a IFG171: if ((outdata_reg_a = "CLOCK0") and (clock_enable_output_a = "NORMAL")) generate i_outdata_clken_a <= clocken0; end generate IFG171; IFG172: if (clock_enable_output_a = "BYPASS") generate i_outdata_clken_a <= '1'; end generate IFG172; IFG173 : if ((outdata_reg_a = "CLOCK1") and (clock_enable_output_a = "NORMAL")) generate i_outdata_clken_a <= clocken1; end generate IFG173; IFG174 : if ((outdata_reg_a /= "CLOCK0") and (outdata_reg_a /= "CLOCK1") and (clock_enable_output_a = "NORMAL")) generate i_outdata_clken_a <= '0'; end generate IFG174; -- Assigning the correct clear signals -- for data in a IFG20: if (indata_aclr_a = "CLEAR0") generate i_indata_aclr_a <= aclr0; end generate IFG20; IFG21: if (indata_aclr_a /= "CLEAR0") generate i_indata_aclr_a <= '0'; end generate IFG21; -- for address a IFG22: if (address_aclr_a = "CLEAR0") generate i_address_aclr_a <= aclr0; end generate IFG22; IFG23: if (address_aclr_a /= "CLEAR0") generate i_address_aclr_a <= '0'; end generate IFG23; -- for wren a IFG24: if (wrcontrol_aclr_a = "CLEAR0") generate i_wrcontrol_aclr_a <= aclr0; end generate IFG24; IFG25: if (wrcontrol_aclr_a /= "CLEAR0") generate i_wrcontrol_aclr_a <= '0'; end generate IFG25; -- for byteena a IFG26: if (byteena_aclr_a = "CLEAR0") generate i_byteena_aclr_a <= aclr0; end generate IFG26; IFG27: if (byteena_aclr_a = "CLEAR1") generate i_byteena_aclr_a <= aclr1; end generate IFG27; IFG28: if ((byteena_aclr_a /= "CLEAR0") and (byteena_aclr_a /= "CLEAR1")) generate i_byteena_aclr_a <= '0'; end generate IFG28; -- for data out a IFG29: if (outdata_aclr_a = "CLEAR0") generate i_outdata_aclr_a <= aclr0; end generate IFG29; IFG30: if (outdata_aclr_a = "CLEAR1") generate i_outdata_aclr_a <= aclr1; end generate IFG30; IFG31: if ((outdata_aclr_a /= "CLEAR0") and (outdata_aclr_a /= "CLEAR1")) generate i_outdata_aclr_a <= '0'; end generate IFG31; -- for data in b IFG32: if (indata_aclr_b = "CLEAR0") generate i_indata_aclr_b <= aclr0; end generate IFG32; IFG33: if (indata_aclr_b = "CLEAR1") generate i_indata_aclr_b <= aclr1; end generate IFG33; IFG34: if ((indata_aclr_b /= "CLEAR0") and (indata_aclr_b /= "CLEAR1")) generate i_indata_aclr_b <= '0'; end generate IFG34; -- for address b IFG35: if (address_aclr_b = "CLEAR0") generate i_address_aclr_b <= aclr0; end generate IFG35; IFG36: if (address_aclr_b = "CLEAR1") generate i_address_aclr_b <= aclr1; end generate IFG36; IFG37: if ((address_aclr_b /= "CLEAR0") and (address_aclr_b /= "CLEAR1")) generate i_address_aclr_b <= '0'; end generate IFG37; -- for wren b IFG38:if (wrcontrol_aclr_b = "CLEAR0") generate i_wrcontrol_aclr_b <= aclr0; end generate IFG38; IFG39: if (wrcontrol_aclr_b = "CLEAR1") generate i_wrcontrol_aclr_b <= aclr1; end generate IFG39; IFG40: if ((wrcontrol_aclr_b /= "CLEAR0") and (wrcontrol_aclr_b /= "CLEAR1")) generate i_wrcontrol_aclr_b <= '0'; end generate IFG40; -- for rden b IFG41: if (rdcontrol_aclr_b = "CLEAR0") generate i_rdcontrol_aclr_b <= aclr0; end generate IFG41; IFG42: if (rdcontrol_aclr_b = "CLEAR1") generate i_rdcontrol_aclr_b <= aclr1; end generate IFG42; IFG43: if ((rdcontrol_aclr_b /= "CLEAR0") and (rdcontrol_aclr_b /= "CLEAR1")) generate i_rdcontrol_aclr_b <= '0'; end generate IFG43; -- for byteena b IFG44: if (byteena_aclr_b = "CLEAR0") generate i_byteena_aclr_b <= aclr0; end generate IFG44; IFG45: if (byteena_aclr_b = "CLEAR1") generate i_byteena_aclr_b <= aclr1; end generate IFG45; IFG46: if ((byteena_aclr_b /= "CLEAR0") and (byteena_aclr_b /= "CLEAR1")) generate i_byteena_aclr_b <= '0'; end generate IFG46; -- These processes check for byteena connectivity process(byteena_a) variable m_byteena_a_unconnected : std_logic := '0'; begin if (byteena_a(0) = 'Z') then m_byteena_a_unconnected := '1'; end if; byteena_a_unconnected <= m_byteena_a_unconnected; end process; process(byteena_b) variable m_byteena_b_unconnected : std_logic := '0'; begin if (byteena_b(0) = 'Z') then m_byteena_b_unconnected := '1'; end if; byteena_b_unconnected <= m_byteena_b_unconnected; end process; -- This process initializes and updates the memory content in the RAM accordingly process (i_read_flag_a, i_write_flag_a, i_read_flag_b, i_write_flag_b) variable j : integer := 0; variable m_mem_data_a : width_a_array; variable m_mem_data_b : width_b_array; variable m_temp_wa : std_logic_vector(width_a - 1 downto 0); variable m_temp_wa2 : std_logic_vector(width_a - 1 downto 0) := (others => 'U'); variable m_temp_wb : std_logic_vector(width_b - 1 downto 0); variable m_temp_wb2 : std_logic; variable m_init_file_b_port : boolean := false; variable m_address_a : integer := 0; variable m_address_b : integer := 0; variable m_q_tmp2_a : std_logic_vector(width_a - 1 downto 0); variable write_by_a : integer := 0; variable prev_write_by_a : integer := 0; variable write_by_b : integer := 0; variable prev_write_by_b : integer := 0; variable ctime : time := 0 ps; variable reread_a : boolean := false; variable reread_b : boolean := false; variable last_read_a_event : boolean := false; variable last_read_b_event : boolean := false; begin if (need_init) then -- Begin of initializations if (init_file = "UNUSED" or init_file = "") then -- No memory file used if (operation_mode /= "ROM") then for i in 0 to (2**widthad_a - 1) loop if (((ram_block_type = "AUTO") and (cread_during_write_mode_mixed_ports = "DONT_CARE")) or IS_FAMILY_STRATIXHC(intended_device_family) or (ram_block_type = "MEGARAM") or (ram_block_type = "M-RAM")) then m_mem_data_a(i) := (others => 'X'); else m_mem_data_a(i) := (others => '0'); end if; end loop; for i in 0 to (2**widthad_b - 1) loop m_mem_data_b(i) := (others => 'X'); end loop; end if; else -- Using memory file to initialize memory content if (((ram_block_type = "AUTO") and (cread_during_write_mode_mixed_ports = "DONT_CARE")) or (IS_FAMILY_STRATIXHC(intended_device_family) and operation_mode /= "ROM") or (ram_block_type = "MEGARAM") or (ram_block_type = "M-RAM")) then for i in 0 to (2 ** widthad_a - 1) loop m_mem_data_a(i) := (others => 'X'); end loop; else for i in 0 to (2 ** widthad_a - 1) loop m_mem_data_a(i) := (others => '0'); end loop; end if; m_init_file_b_port := false; if (init_file_layout = "UNUSED") then if (operation_mode = "DUAL_PORT") then m_init_file_b_port := true; else m_init_file_b_port := false; end if; else if (init_file_layout = "PORT_A") then m_init_file_b_port := false; elsif (init_file_layout = "PORT_B") then m_init_file_b_port := true; end if; end if; if (m_init_file_b_port) then read_my_memory (false, m_mem_data_a, m_mem_data_b); for i in 0 to (i_numwords_b * width_b - 1) loop m_temp_wb := m_mem_data_b(i / width_b); m_temp_wb2 := m_temp_wb((i)mod width_b); m_temp_wa := m_mem_data_a(i / width_a); m_temp_wa(i mod width_a) := m_temp_wb2; m_mem_data_a(i / width_a) := m_temp_wa; end loop; else read_my_memory (true, m_mem_data_a, m_mem_data_b); end if; end if; need_init <= FALSE; -- End of initializations else -- Write/update memory content if (i_write_flag_a'event) then if ((operation_mode = "DUAL_PORT") or (operation_mode = "SINGLE_PORT") or (operation_mode = "BIDIR_DUAL_PORT")) then if (i_wren_reg_a = '1') then if ((i_address_aclr_a = '1') and (conv_integer(unsigned(i_address_reg_a)) /= 0)) then for i in 0 to (i_numwords_a - 1) loop m_mem_data_a(i) := (others => 'X'); end loop; elsif (((i_indata_aclr_a = '1') and (i_data_reg_a /= i_data_zero_a)) or ((i_byteena_aclr_a = '1') and (i_byteena_mask_reg_a /= i_data_ones_a)) or ((i_wrcontrol_aclr_a = '1') and (i_wren_reg_a /= '0'))) then m_mem_data_a (conv_integer(unsigned(i_address_reg_a))) := (others => 'X'); else m_mem_data_a (conv_integer(unsigned(i_address_reg_a))) := (i_data_reg_a and i_byteena_mask_reg_a) or (m_mem_data_a(conv_integer(unsigned(i_address_reg_a))) and not i_byteena_mask_reg_a); write_by_a := write_by_a + 1; end if; end if; end if; end if; if (i_write_flag_b'event) then if (operation_mode = "BIDIR_DUAL_PORT") then if (i_wren_reg_b = '1') then if ((i_wrcontrol_aclr_b = '1') and (conv_integer(unsigned(i_address_reg_b)) /= 0)) then for i in 0 to (i_numwords_a - 1) loop m_mem_data_a(i) := (others => 'X'); end loop; elsif (((i_byteena_aclr_b = '1') and (i_byteena_mask_reg_b /= i_data_ones_b)) or ((i_indata_aclr_b = '1') and (i_data_reg_b /= i_data_zero_b)) or ((i_wrcontrol_aclr_b = '1') and (i_wren_reg_b /= '0'))) then j := conv_integer(unsigned(i_address_reg_b)) * width_b; for i in 0 to (width_b - 1) loop m_temp_wa2 := m_mem_data_a((j + i) / width_a); m_temp_wa2((j + i) mod width_a) := 'X'; m_mem_data_a((j + i) / width_a) := m_temp_wa2; end loop; else j := (conv_integer(unsigned(i_address_reg_b)) * width_b); for i in 0 to (width_b - 1) loop m_temp_wa2 := m_mem_data_a((j + i) / width_a); m_temp_wa2((j + i) mod width_a) := ((i_data_reg_b(i) and i_byteena_mask_reg_b(i)) or (m_temp_wa2((j + i) mod width_a) and not i_byteena_mask_reg_b(i))); m_mem_data_a((j + i) / width_a) := m_temp_wa2; end loop; write_by_b := write_by_b + 1; end if; end if; end if; end if; end if; -- To ensure that the model will reread port if two event (read & write) event triggered -- at the different time quantum reread_a := false; reread_b := false; if (ctime /= 0 ps) and (ctime = now) and ((i_write_flag_a'event) or (i_write_flag_b'event)) then if last_read_a_event then reread_a := true; assert false report "Reread the port A" severity note; end if; if last_read_b_event then reread_b := true; assert false report "Reread the port B" severity note; end if; end if; last_read_a_event := i_read_flag_a'event; last_read_b_event := i_read_flag_b'event; ctime := now; -- Port A reading if (i_read_flag_a'event) or (reread_a) then if (write_by_a /= prev_write_by_a) then prev_write_by_a := write_by_a; end if; if ((operation_mode = "BIDIR_DUAL_PORT") or (operation_mode = "SINGLE_PORT") or (operation_mode = "ROM")) then m_address_a := conv_integer(unsigned(i_address_reg_a)); m_q_tmp2_a := m_mem_data_a(m_address_a); -- This is to output an "X" when the other ports is writing into the same location -- when read_during_write_mode_mixed_ports = "DONT_CARE" if (operation_mode = "BIDIR_DUAL_PORT") then if ((ram_block_type = "MEGARAM") or (ram_block_type = "M-RAM") or ((cread_during_write_mode_mixed_ports = "DONT_CARE") and (ram_block_type = "AUTO"))) then if (wrcontrol_wraddress_reg_b = "CLOCK0") then if ((i_wren_reg_b = '1') and (i_wren_reg_a = '0')) then m_address_b := conv_integer(unsigned(i_address_reg_b)); if ((((m_address_a * width_a) > (m_address_b * width_b)) and ((m_address_a * width_a) < ((m_address_b * width_b) + width_b - 1))) or ((((m_address_a * width_a) + width_a - 1) > (m_address_b * width_b)) and (((m_address_a * width_a) + width_a - 1) < ((m_address_b * width_b) + width_b - 1)))) then for i in (m_address_a * width_a) to ((m_address_a * width_a) + width_a - 1) loop if ((i > (m_address_b * width_b)) and (i < ((m_address_b * width_b) + width_b - 1))) then j := i - (m_address_a * width_a); m_q_tmp2_a(j) := 'X'; end if; end loop; end if; end if; end if; end if; end if; end if; i_q_tmp2_a <= m_q_tmp2_a; end if; -- Port B reading if (i_read_flag_b'event) or (reread_b) then if (write_by_b /= prev_write_by_b) then prev_write_by_b := write_by_b; end if; if ((operation_mode = "DUAL_PORT") or (operation_mode = "BIDIR_DUAL_PORT")) then if (i_rden_reg_b = '1') then m_address_a := conv_integer(unsigned(i_address_reg_a)); m_address_b := conv_integer(unsigned(i_address_reg_b)); j := m_address_b * width_b; for i in 0 to (width_b - 1) loop m_temp_wa2 := m_mem_data_a((j + i) / width_a); m_temp_wb(i) := m_temp_wa2((j + i) mod width_a); if ((ram_block_type = "MEGARAM") or (ram_block_type = "M-RAM") or ((cread_during_write_mode_mixed_ports = "DONT_CARE") and (ram_block_type = "AUTO"))) then if ((rdcontrol_reg_b = "CLOCK0") or (wrcontrol_wraddress_reg_b = "CLOCK0")) then if ((i_wren_reg_a = '1') and (i_wren_reg_b = '0')) then if (((j + i) / width_a) = m_address_a) then m_temp_wb(i) := 'X'; end if; end if; end if; end if; end loop; i_q_tmp2_b <= m_temp_wb; end if; end if; end if; end process; -- Port A inputs registered : indata, address, byeteena, wren process (clock0) variable m_byteena_mask_reg_a : std_logic_vector(width_a - 1 downto 0); variable m_indata_reg_aclr_a : std_logic := '0'; variable m_wren_reg_aclr_a : std_logic := '0'; variable m_byteena_reg_aclr_a : std_logic := '0'; variable m_address_reg_aclr_a : std_logic := '0'; begin if (clock0'event and (clock0 = '1')) then if (clocken0 = '1') or (clock_enable_input_a = "BYPASS") then if (i_indata_aclr_a = '1') then i_data_reg_a <= (others => '0'); else i_data_reg_a <= data_a; end if; if (i_wrcontrol_aclr_a = '1') then i_wren_reg_a <= '0'; else i_wren_reg_a <= wren_a; end if; if (byteena_a_unconnected = '1') then m_byteena_mask_reg_a := (others => '1'); else if (i_byteena_aclr_a = '1') then m_byteena_mask_reg_a := (others => '1'); else for k in 0 to (width_a - 1) loop if (width_byteena_a = 1) then m_byteena_mask_reg_a(k) := byteena_a(0); else m_byteena_mask_reg_a(k) := byteena_a(k / byte_size); end if; end loop; end if; end if; i_byteena_mask_reg_a <= m_byteena_mask_reg_a; if (i_address_aclr_a = '1') then i_address_reg_a <= (others => '0'); elsif (addressstall_a /= '1') then i_address_reg_a <= address_a; end if; good_to_go_a <= '1'; write_by_b_reg_a <= write_by_b_reg_a + 1; i_read_flag_a <= not i_read_flag_a; if ((ram_block_type = "M-RAM") or (ram_block_type = "MEGARAM")) then i_write_flag_a <= not i_write_flag_a; end if; if (operation_mode /= "ROM") then i_nmram_write_a <= '1'; end if; else if (operation_mode /= "ROM") then i_nmram_write_a <= '0'; end if; end if; end if; if (clock0'event and (clock0 = '0')) then if ((ram_block_type /= "M-RAM") and (ram_block_type /= "MEGARAM")) then if (i_nmram_write_a = '1') then i_write_flag_a <= not i_write_flag_a; end if; end if; end if; end process; -- Port B indata input registered IFG47: if ((indata_reg_b = "CLOCK0") or (indata_reg_b = "CLOCK1")) generate process (clock0, clock1) begin if ((clock0'event and (clock0 = '1') and (indata_reg_b = "CLOCK0")) or (clock1'event and (clock1 = '1') and (indata_reg_b = "CLOCK1"))) then if (i_indata_clken_b = '1') then if (i_indata_aclr_b = '1') then i_data_reg_b <= (others => '0'); else i_data_reg_b <= data_b; end if; end if; end if; end process; end generate IFG47; -- Port B address input registered (for dual_port mode) IFG48: if (((address_reg_b = "CLOCK0") or (address_reg_b = "CLOCK1")) and (operation_mode = "DUAL_PORT")) generate process (clock0, clock1) begin if ((clock0'event and (clock0 = '1')) and (address_reg_b = "CLOCK0")) or (clock1'event and (clock1 = '1') and (address_reg_b = "CLOCK1")) then if (i_address_clken_b = '1') then i_read_flag_b <= not i_read_flag_b; if (i_address_aclr_b = '1') then i_address_reg_b <= (others => '0'); elsif (addressstall_b /= '1') then i_address_reg_b <= address_b; end if; end if; end if; end process; end generate IFG48; IFG48a: if ((operation_mode = "DUAL_PORT") or (operation_mode = "BIDIR_DUAL_PORT")) generate process (clock0, clock1) begin if ((clock0'event and (clock0 = '1')) and (address_reg_b = "CLOCK0")) or (clock1'event and (clock1 = '1') and (address_reg_b = "CLOCK1")) then if (i_address_clken_b = '1') then good_to_go_b <= '1'; write_by_a_reg_b <= write_by_a_reg_b + 1; end if; end if; end process; end generate IFG48a; -- Port B inputs registered : wren, address, byteena (for bidir_dual_port mode) IFG49: if (((wrcontrol_wraddress_reg_b = "CLOCK0") or (wrcontrol_wraddress_reg_b = "CLOCK1")) and (operation_mode = "BIDIR_DUAL_PORT")) generate process (clock0, clock1) variable m_byteena_mask_reg_b : std_logic_vector(width_b - 1 downto 0); begin if (((wrcontrol_wraddress_reg_b = "CLOCK0") and clock0'event and (clock0 = '1')) or ((wrcontrol_wraddress_reg_b = "CLOCK1") and clock1'event and (clock1 = '1'))) then if (i_wrcontrol_wraddress_clken_b = '1') then i_read_flag_b <= not i_read_flag_b; if (i_wrcontrol_aclr_b = '1') then i_wren_reg_b <= '0'; else i_wren_reg_b <= wren_b; end if; if (i_wrcontrol_aclr_b = '1') then i_address_reg_b <= (others => '0'); elsif (addressstall_b /= '1') then i_address_reg_b <= address_b; end if; if (byteena_b_unconnected = '1') then m_byteena_mask_reg_b := (others => '1'); else if (i_byteena_aclr_b = '1') then m_byteena_mask_reg_b := (others => '1'); else for k in 0 to (width_b - 1) loop if (width_byteena_b = 1) then m_byteena_mask_reg_b(k) := byteena_b(0); else m_byteena_mask_reg_b(k) := byteena_b(k / byte_size); end if; end loop; end if; end if; i_byteena_mask_reg_b <= m_byteena_mask_reg_b; if ((ram_block_type = "MEGARAM") or (ram_block_type = "M-RAM")) then i_write_flag_b <= not i_write_flag_b; end if; i_nmram_write_b <= '1'; else i_nmram_write_b <= '0'; end if; end if; if (((wrcontrol_wraddress_reg_b = "CLOCK0") and clock0'event and (clock0 = '0')) or ((wrcontrol_wraddress_reg_b = "CLOCK1") and clock1'event and (clock1 = '0'))) then if ((ram_block_type /= "MEGARAM") and (ram_block_type /= "M-RAM")) then if (i_nmram_write_b = '1') then i_write_flag_b <= not i_write_flag_b; end if; end if; end if; end process; end generate IFG49; -- Port B rden input registered (for dual_port mode) IFG50: if (((rdcontrol_reg_b = "CLOCK0") or (rdcontrol_reg_b = "CLOCK1")) and (operation_mode = "DUAL_PORT")) generate process (clock0, clock1) begin if (rden_b /= 'Z') then if (((address_reg_b = "CLOCK0") and clock0'event and (clock0 = '1')) or ((address_reg_b = "CLOCK1") and clock1'event and (clock1 = '1'))) then if (i_rdcontrol_clken_b = '1') then if (i_rdcontrol_aclr_b = '1') then i_rden_reg_b <= '1'; else i_rden_reg_b <= rden_b; end if; end if; end if; end if; end process; end generate IFG50; -- Port A : assigning the correct output values for i_q_tmp_a (non-registered output) i_q_tmp_wren_a <= i_q_tmp2_a when (i_wren_reg_a = '0') else (i_q_tmp2_wren_a); i_q_tmp_a <= i_q_tmp_wren_a when (good_to_go_a = '1') else (others => default_val); process (i_q_tmp2_a, i_wren_reg_a, i_data_reg_a, i_address_reg_a, i_byteena_mask_reg_a) variable t_q_tmp2_wren_a : std_logic_vector(width_a - 1 downto 0) := (others => '0'); begin if (i_wren_reg_a = '1') then for i in 0 to (width_a - 1) loop if (i_byteena_mask_reg_a(i) = '0') then t_q_tmp2_wren_a(i) := 'X'; else t_q_tmp2_wren_a(i) := ((i_data_reg_a(i) and i_byteena_mask_reg_a(i)) or (i_q_tmp2_a(i) and not i_byteena_mask_reg_a(i))) ; end if; end loop; i_q_tmp2_wren_a <= t_q_tmp2_wren_a; end if; end process; -- Port A outdata output registered process (clock0, clock1, aclr0, aclr1) begin if (((outdata_aclr_a = "CLEAR0") and (aclr0 = '1')) or ((outdata_aclr_a = "CLEAR1") and (aclr1 = '1'))) then i_q_reg_a <= (others => '0'); elsif (((outdata_reg_a = "CLOCK0") and clock0'event and (clock0 = '1')) or ((outdata_reg_a = "CLOCK1") and clock1'event and (clock1 = '1'))) then if (i_outdata_clken_a = '1') then i_q_reg_a <= i_q_tmp_a; end if; end if; end process; -- Port A : assigning the correct output values for q_a IFG52: if (((outdata_reg_a = "CLOCK0") or (outdata_reg_a = "CLOCK1")) and (operation_mode /= "DUAL_PORT")) generate q_a <= i_q_reg_a; end generate IFG52; IFG53: if (((outdata_reg_a /= "CLOCK0") and (outdata_reg_a /= "CLOCK1")) and (operation_mode /= "DUAL_PORT")) generate q_a <= i_q_tmp_a; end generate IFG53; IFG54: if (operation_mode = "DUAL_PORT") generate q_a <= (others => '0'); end generate IFG54; -- Port B : assigning the correct output values for i_q_tmp_b (non-registered output) process (i_q_tmp2_b, good_to_go_b, i_rden_reg_b, i_wren_reg_b, i_data_reg_b, i_byteena_mask_reg_b) variable t_q_tmp_b : std_logic_vector(width_b - 1 downto 0) := (others => '0'); begin if ((operation_mode = "DUAL_PORT") or (operation_mode = "BIDIR_DUAL_PORT")) then if (not good_to_go_b = '1') then i_q_tmp_b <= (others => default_val); else if (operation_mode = "DUAL_PORT") then if (i_rden_reg_b = '1') then i_q_tmp_b <= i_q_tmp2_b; end if; else if (i_wren_reg_b = '1') then for i in 0 to (width_b - 1) loop if (i_byteena_mask_reg_b(i) = '0') then t_q_tmp_b(i) := 'X'; else t_q_tmp_b(i) := ((i_data_reg_b(i) and i_byteena_mask_reg_b(i)) or (i_q_tmp2_b(i) and not i_byteena_mask_reg_b(i))) ; end if; end loop; i_q_tmp_b <= t_q_tmp_b; else i_q_tmp_b <= i_q_tmp2_b; end if; end if; end if; end if; end process; -- Port B outdata output registered process (clock0, clock1, aclr0, aclr1) begin if (((outdata_aclr_b = "CLEAR0") and (aclr0 = '1')) or ((outdata_aclr_b = "CLEAR1") and (aclr1 = '1'))) then i_q_reg_b <= (others => '0'); elsif (((outdata_reg_b = "CLOCK0") and clock0'event and (clock0 = '1')) or ((outdata_reg_b = "CLOCK1") and clock1'event and (clock1 = '1'))) then if (i_outdata_clken_b = '1') then i_q_reg_b <= i_q_tmp_b; end if; end if; end process; -- Port B : assigning the correct output values for q_b IFG55: if (((outdata_reg_b = "CLOCK0") or (outdata_reg_b = "CLOCK1")) and (operation_mode /= "SINGLE_PORT") and (operation_mode /= "ROM")) generate q_b <= i_q_reg_b; end generate IFG55; IFG56: if (((outdata_reg_b /= "CLOCK0") and (outdata_reg_b /= "CLOCK1")) and (operation_mode /= "SINGLE_PORT") and (operation_mode /= "ROM")) generate q_b <= i_q_tmp_b; end generate IFG56; IFG57: if ((operation_mode = "SINGLE_PORT") or (operation_mode = "ROM")) generate q_b <= (others => '0'); end generate IFG57; end translated; -- END OF ARCHITECTURE ALTSYNCRAM -------------------------------------------------------------------------------+ -- Module Name : alt3pram -- -- Description : Triple-Port RAM megafunction. This megafunction implements -- RAM with 1 write port and 2 read ports. -- -- Limitation : This megafunction is provided only for backward -- compatibility in Stratix™ designs; instead, Altera® -- recommends using the altsyncram megafunction -- -- For Apex Families, -- Uses one embedded cell per data output bit for -- Embedded System Block (ESB): APEX 20K, APEX II, -- ARM-based Excalibur and Mercury devices or -- Embedded Array Block (EAB): ACEX 1K and FLEX 10KE family; -- -- However, in FLEX 6000, MAX 3000, and MAX 7000 devices, -- or if the USE_EAB paramter is set to "OFF", uses one -- logic cell (LCs) per memory bit. -- -- -- Results expected : The alt3pram function represents asynchronous memory -- or memory with synchronous inputs and/or outputs. -- (note: ^ below indicates posedge) -- -- [ Synchronous Write to Memory (all inputs registered) ] -- inclock inclocken wren Function -- X L L No change. -- not ^ H H No change. -- ^ L X No change. -- ^ H H The memory location -- pointed to by wraddress[] -- is loaded with data[]. -- -- [ Synchronous Read from Memory ] -- inclock inclocken rden_a/rden_b Function -- X L L No change. -- not ^ H H No change. -- ^ L X No change. -- ^ H H The q_a[]/q_b[]port -- outputs the contents of -- the memory location. -- -- [ Asynchronous Memory Operations ] -- wren Function -- L No change. -- H The memory location pointed to by wraddress[] is -- loaded with data[] and controlled by wren. -- The output q_a[] is asynchronous and reflects -- the memory location pointed to by rdaddress_a[]. -- -------------------------------------------------------------------------------+ library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use std.textio.all; use work.ALTERA_DEVICE_FAMILIES.all; use work.ALTERA_COMMON_CONVERSION.all; --------------------- -- ENTITY DECLARATION --------------------- entity alt3pram is generic ( width : natural; -- data[], qa[] and qb[] widthad : natural; -- rdaddress_a,rdaddress_b,wraddress numwords : natural := 0; -- words stored in memory lpm_file : string := "UNUSED"; -- name of hex file lpm_hint : string := "USE_EAB=ON"; -- non-LPM parameters (Altera) indata_reg : string := "UNREGISTERED";-- clock used by data[] port indata_aclr : string := "OFF"; -- aclr affects data[]? write_reg : string := "UNREGISTERED";-- clock used by wraddress & wren write_aclr : string := "OFF"; -- aclr affects wraddress? rdaddress_reg_a : string := "UNREGISTERED";-- clock used by readdress_a rdaddress_aclr_a : string := "OFF"; -- aclr affects rdaddress_a? rdaddress_reg_b : string := "UNREGISTERED";-- clock used by readdress_b rdaddress_aclr_b : string := "OFF"; -- aclr affects rdaddress_b? rdcontrol_reg_a : string := "UNREGISTERED";-- clock used by rden_a rdcontrol_aclr_a : string := "OFF"; -- aclr affects rden_a? rdcontrol_reg_b : string := "UNREGISTERED";-- clock used by rden_b rdcontrol_aclr_b : string := "OFF"; -- aclr affects rden_b? outdata_reg_a : string := "UNREGISTERED";-- clock used by qa[] outdata_aclr_a : string := "OFF"; -- aclr affects qa[]? outdata_reg_b : string := "UNREGISTERED";-- clock used by qb[] outdata_aclr_b : string := "OFF"; -- aclr affects qb[]? intended_device_family : string := "APEX20KE"; ram_block_type : string := "AUTO"; -- ram block type to be used maximum_depth : integer := 0; -- maximum segmented value of the RAM lpm_type : string := "alt3pram" ); port ( wren : in std_logic := '0'; data : in std_logic_vector(width-1 downto 0); wraddress : in std_logic_vector(widthad-1 downto 0); inclock : in std_logic := '0'; inclocken : in std_logic := '1'; rden_a : in std_logic := '1'; rden_b : in std_logic := '1'; rdaddress_a : in std_logic_vector(widthad-1 downto 0); rdaddress_b : in std_logic_vector(widthad-1 downto 0); outclock : in std_logic := '0'; outclocken : in std_logic := '1'; aclr : in std_logic := '0'; qa : out std_logic_vector(width-1 downto 0); qb : out std_logic_vector(width-1 downto 0) ); end alt3pram; -- Entity: alt3pram --------------------------- -- ARCHITECTURE DECLARATION --------------------------- architecture behavior of alt3pram is ------------------------ -- FUNCTION DECLARATION ------------------------ -- The following functions take in parameters values used in alt3pram and convert -- to a corresponding(or suitable) parameters value that used in altsyncram. function get_num_words(i_numwords : natural; i_widthad : natural) return integer is begin if (i_numwords = 0) then return 2**i_widthad; else return i_numwords; end if; end; function get_read_during_write_mode_mixed_ports(i_ram_block_type : string) return string is begin if (i_ram_block_type = "AUTO") then return "OLD_DATA"; else return "DONT_CARE"; end if; end; function get_write_aclr_a_clk(i_write_aclr : string) return string is begin if (i_write_aclr = "ON") then return "CLEAR0"; else return "NONE"; end if; end; function get_indata_aclr_a_clk(i_indata_aclr : string) return string is begin if (i_indata_aclr = "ON") then return "CLEAR0"; else return "NONE"; end if; end; function get_rdcontrol_reg_a_clk(i_rdcontrol_reg_a : string) return string is begin if (i_rdcontrol_reg_a = "INCLOCK") then return "CLOCK0"; elsif (i_rdcontrol_reg_a = "OUTCLOCK") then return "CLOCK1"; else return "UNUSED"; end if; end; function get_rdaddress_reg_a_clk(i_rdaddress_reg_a : string) return string is begin if (i_rdaddress_reg_a = "INCLOCK") then return "CLOCK0"; elsif (i_rdaddress_reg_a = "OUTCLOCK") then return "CLOCK1"; else return "UNUSED"; end if; end; function get_outdata_reg_a_clk(i_outdata_reg_a : string) return string is begin if (i_outdata_reg_a = "INCLOCK") then return "CLOCK0"; elsif (i_outdata_reg_a = "OUTCLOCK") then return "CLOCK1"; else return "UNREGISTERED"; end if; end; function get_outdata_aclr_a_clk(i_outdata_aclr_a : string) return string is begin if (i_outdata_aclr_a = "ON") then return "CLEAR0"; else return "NONE"; end if; end; function get_rdcontrol_aclr_a_clk(i_rdcontrol_aclr_a : string) return string is begin if (i_rdcontrol_aclr_a = "ON") then return "CLEAR0"; else return "NONE"; end if; end; function get_rdaddress_aclr_a_clk(i_rdaddress_aclr_a : string) return string is begin if (i_rdaddress_aclr_a = "ON") then return "CLEAR0"; else return "NONE"; end if; end; function get_rdcontrol_reg_b_clk(i_rdcontrol_reg_b : string) return string is begin if (i_rdcontrol_reg_b = "INCLOCK") then return "CLOCK0"; elsif (i_rdcontrol_reg_b = "OUTCLOCK") then return "CLOCK1"; else return "UNUSED"; end if; end; function get_rdaddress_reg_b_clk(i_rdaddress_reg_b : string) return string is begin if (i_rdaddress_reg_b = "INCLOCK") then return "CLOCK0"; elsif (i_rdaddress_reg_b = "OUTCLOCK") then return "CLOCK1"; else return "UNUSED"; end if; end; function get_outdata_reg_b_clk(i_outdata_reg_b : string) return string is begin if (i_outdata_reg_b = "INCLOCK") then return "CLOCK0"; elsif (i_outdata_reg_b = "OUTCLOCK") then return "CLOCK1"; else return "UNREGISTERED"; end if; end; function get_outdata_aclr_b_clk(i_outdata_aclr_b : string) return string is begin if (i_outdata_aclr_b = "ON") then return "CLEAR0"; else return "NONE"; end if; end; function get_rdcontrol_aclr_b_clk(i_rdcontrol_aclr_b : string) return string is begin if (i_rdcontrol_aclr_b = "ON") then return "CLEAR0"; else return "NONE"; end if; end; function get_rdaddress_aclr_b_clk(i_rdaddress_aclr_b : string) return string is begin if (i_rdaddress_aclr_b = "ON") then return "CLEAR0"; else return "NONE"; end if; end; ------------------- -- TYPE DECLARATION ------------------- type alt_memory is array((2**WIDTHAD)-1 downto 0) of std_logic_vector(WIDTH-1 downto 0); ----------------------- -- CONSTANT DECLARATION ----------------------- constant DEV_APEX20K : string := "APEX20K"; constant IS_STRATIX : boolean := IS_FAMILY_STRATIX(intended_device_family); constant IS_STRATIXGX : boolean := IS_FAMILY_STRATIXGX(intended_device_family); constant IS_ACEX2K : boolean := IS_FAMILY_ACEX2K(intended_device_family); constant IS_STRATIXII : boolean := IS_FAMILY_STRATIXII(intended_device_family); constant NUM_WORDS : integer := get_num_words(numwords, widthad); constant READ_DURING_WRITE_MODE : string := get_read_during_write_mode_mixed_ports(ram_block_type); constant WRITE_ACLR_A_CLK : string := get_write_aclr_a_clk(write_aclr); constant INDATA_ACLR_A_CLK : string := get_indata_aclr_a_clk(indata_aclr); constant RDCONTROL_REG_A_CLK : string := get_rdcontrol_reg_a_clk(rdcontrol_reg_a); constant RDADDRESS_REG_A_CLK : string := get_rdaddress_reg_a_clk(rdaddress_reg_a); constant OUTDATA_REG_A_CLK : string := get_outdata_reg_a_clk(outdata_reg_a); constant OUTDATA_ACLR_A_CLK : string := get_outdata_aclr_a_clk(outdata_aclr_a); constant RDCONTROL_ACLR_A_CLK : string := get_rdcontrol_aclr_a_clk(rdcontrol_aclr_a); constant RDADDRESS_ACLR_A_CLK : string := get_rdaddress_aclr_a_clk(rdaddress_aclr_a); constant RDCONTROL_REG_B_CLK : string := get_rdcontrol_reg_b_clk(rdcontrol_reg_b); constant RDADDRESS_REG_B_CLK : string := get_rdaddress_reg_b_clk(rdaddress_reg_b); constant OUTDATA_REG_B_CLK : string := get_outdata_reg_b_clk(outdata_reg_b); constant OUTDATA_ACLR_B_CLK : string := get_outdata_aclr_b_clk(outdata_aclr_b); constant RDCONTROL_ACLR_B_CLK : string := get_rdcontrol_aclr_b_clk(rdcontrol_aclr_b); constant RDADDRESS_ACLR_B_CLK : string := get_rdaddress_aclr_b_clk(rdaddress_aclr_b); --------------------- -- SIGNAL DECLARATION --------------------- signal idata_tmp : std_logic_vector(WIDTH-1 downto 0) := (OTHERS => '0'); signal idata_reg : std_logic_vector(WIDTH-1 downto 0) := (OTHERS => '0'); signal idata_hi : std_logic_vector(WIDTH-1 downto 0) := (OTHERS => '0'); signal idata_lo : std_logic_vector(WIDTH-1 downto 0) := (OTHERS => '0'); signal iqa_tmp : std_logic_vector(WIDTH-1 downto 0) := (OTHERS => '0'); signal iqa_reg : std_logic_vector(WIDTH-1 downto 0) := (OTHERS => '0'); signal iqb_tmp : std_logic_vector(WIDTH-1 downto 0) := (OTHERS => '0'); signal iqb_reg : std_logic_vector(WIDTH-1 downto 0) := (OTHERS => '0'); signal iwren_tmp : std_logic := '0'; signal iwren_reg : std_logic := '0'; signal iwren_hi : std_logic := '0'; signal iwren_lo : std_logic := '0'; signal irdaddress_tmp_a : std_logic_vector(WIDTHAD-1 downto 0) := (OTHERS => '0'); signal irdaddress_reg_a : std_logic_vector(WIDTHAD-1 downto 0) := (OTHERS => '0'); signal irdaddress_tmp_b : std_logic_vector(WIDTHAD-1 downto 0) := (OTHERS => '0'); signal irdaddress_reg_b : std_logic_vector(WIDTHAD-1 downto 0) := (OTHERS => '0'); signal iwraddress_tmp : std_logic_vector(WIDTHAD-1 downto 0) := (OTHERS => '0'); signal iwraddress_reg : std_logic_vector(WIDTHAD-1 downto 0) := (OTHERS => '0'); signal iwraddress_hi : std_logic_vector(WIDTHAD-1 downto 0) := (OTHERS => '0'); signal iwraddress_lo : std_logic_vector(WIDTHAD-1 downto 0) := (OTHERS => '0'); signal irden_tmp_a : std_logic := '0'; signal irden_reg_a : std_logic := '0'; signal irden_tmp_b : std_logic := '0'; signal irden_reg_b : std_logic := '0'; signal unused_port0 : std_logic_vector(width-1 downto 0); signal unused_port1 : std_logic_vector(width-1 downto 0); signal iqa_apex : std_logic_vector(width-1 downto 0); signal iqb_apex : std_logic_vector(width-1 downto 0); signal iqa_stratix : std_logic_vector(width-1 downto 0); signal iqb_stratix : std_logic_vector(width-1 downto 0); signal iinclock_apex : std_logic; -- inclock signal for non-Stratix families signal ioutclock_apex : std_logic; -- outclock signal for non-Stratix families signal write_at_low_clock : boolean := false; signal rden_low_output_0 : boolean := false; -------------------------- -- COMPONENTS DECLARATION -------------------------- component altsyncram GENERIC ( operation_mode : string := "SINGLE_PORT"; width_a : integer := 8; widthad_a : integer := 2; numwords_a : integer := 4; address_aclr_a : string := "NONE"; indata_aclr_a : string := "CLEAR0"; wrcontrol_aclr_a : string := "NONE"; width_b : integer := 8; widthad_b : integer := 4; numwords_b : integer := 4; rdcontrol_reg_b : string := "CLOCK1"; address_reg_b : string := "CLOCK1"; outdata_reg_b : string := "UNREGISTERED"; outdata_aclr_b : string := "NONE"; rdcontrol_aclr_b : string := "NONE"; address_aclr_b : string := "NONE"; read_during_write_mode_mixed_ports: string := READ_DURING_WRITE_MODE; ram_block_type : string := "AUTO"; init_file : string := "UNUSED"; init_file_layout : string := "UNUSED"; maximum_depth : integer := 0; intended_device_family : string := "Stratix" ); PORT ( wren_a : IN std_logic := '0'; rden_b : IN std_logic := '1'; data_a : IN std_logic_vector(width_a - 1 DOWNTO 0):= (others => '0'); address_a : IN std_logic_vector(widthad_a - 1 DOWNTO 0) := (others => '0'); address_b : IN std_logic_vector(widthad_b - 1 DOWNTO 0) := (others => '0'); clock0 : IN std_logic := '1'; clock1 : IN std_logic := '1'; clocken0 : IN std_logic := '1'; clocken1 : IN std_logic := '1'; aclr0 : IN std_logic := '0'; q_a : OUT std_logic_vector(width_a - 1 DOWNTO 0); q_b : OUT std_logic_vector(width_b - 1 DOWNTO 0)); END component; begin -------------------------- -- COMPONENTS ASSIGNMENTS -------------------------- -- The alt3pram for Stratix/Stratix II/ Stratix GX and Cyclone device families -- are basically consists of 2 instances of altsyncram with write port of each -- instance been tied together. STRATIX_DUALPORT_RAM0: if ((IS_STRATIX = true) or (IS_STRATIXII = true) or (IS_STRATIXGX = true) or (IS_ACEX2K = true)) generate U0: altsyncram generic map ( operation_mode => "DUAL_PORT", width_a => width, widthad_a => widthad, numwords_a => NUM_WORDS, address_aclr_a => WRITE_ACLR_A_CLK, indata_aclr_a => INDATA_ACLR_A_CLK, wrcontrol_aclr_a => WRITE_ACLR_A_CLK, width_b => width, widthad_b => widthad, numwords_b => NUM_WORDS, rdcontrol_reg_b => RDCONTROL_REG_A_CLK, address_reg_b => RDADDRESS_REG_A_CLK, outdata_reg_b => OUTDATA_REG_A_CLK, outdata_aclr_b => OUTDATA_ACLR_A_CLK, rdcontrol_aclr_b => RDCONTROL_ACLR_A_CLK, address_aclr_b => RDADDRESS_ACLR_A_CLK, read_during_write_mode_mixed_ports => READ_DURING_WRITE_MODE, ram_block_type => ram_block_type, init_file => lpm_file, init_file_layout => "PORT_B", maximum_depth => maximum_depth, intended_device_family => intended_device_family) port map ( wren_a => wren, rden_b => rden_a, data_a => data, address_a => wraddress, address_b => rdaddress_a, clock0 => inclock, clock1 => outclock, clocken0 => inclocken, clocken1 => outclocken, aclr0 => aclr, q_a => unused_port0, q_b => iqa_stratix); end generate STRATIX_DUALPORT_RAM0; STRATIX_DUALPORT_RAM1: if ((IS_STRATIX = true) or (IS_STRATIXII = true) or (IS_STRATIXGX = true) or (IS_ACEX2K = true)) generate U1: altsyncram generic map ( operation_mode => "DUAL_PORT", width_a => width, widthad_a => widthad, numwords_a => NUM_WORDS, address_aclr_a => WRITE_ACLR_A_CLK, indata_aclr_a => INDATA_ACLR_A_CLK, wrcontrol_aclr_a => WRITE_ACLR_A_CLK, width_b => width, widthad_b => widthad, numwords_b => NUM_WORDS, rdcontrol_reg_b => RDCONTROL_REG_B_CLK, address_reg_b => RDADDRESS_REG_B_CLK, outdata_reg_b => OUTDATA_REG_B_CLK, outdata_aclr_b => OUTDATA_ACLR_B_CLK, rdcontrol_aclr_b => RDCONTROL_ACLR_B_CLK, address_aclr_b => RDADDRESS_ACLR_B_CLK, read_during_write_mode_mixed_ports => READ_DURING_WRITE_MODE, ram_block_type => ram_block_type, init_file => lpm_file, init_file_layout => "PORT_B", maximum_depth => maximum_depth, intended_device_family => intended_device_family) port map ( wren_a => wren, rden_b => rden_b, data_a => data, address_a => wraddress, address_b => rdaddress_b, clock0 => inclock, clock1 => outclock, clocken0 => inclocken, clocken1 => outclocken, aclr0 => aclr, q_a => unused_port1, q_b => iqb_stratix); end generate STRATIX_DUALPORT_RAM1; -- ****************** -- SIGNAL ASSIGNMENTS -- ****************** qa <= iqa_stratix when ((IS_STRATIX = true) or (IS_STRATIXII = true) or (IS_STRATIXGX = true) or (IS_ACEX2K = true)) else iqa_apex; qb <= iqb_stratix when ((IS_STRATIX = true) or (IS_STRATIXII = true) or (IS_STRATIXGX = true) or (IS_ACEX2K = true)) else iqb_apex; iinclock_apex <= inclock when ((IS_STRATIX = false) and (IS_STRATIXII = false) and (IS_STRATIXGX = false) and (IS_ACEX2K = false)) else '0'; ioutclock_apex <= outclock when ((IS_STRATIX = false) and (IS_STRATIXII = false) and (IS_STRATIXGX = false) and (IS_ACEX2K = false)) else '0'; -- ************* -- PROCESS BLOCK -- ************* -- The following process blocks are used to implement the alt3pram behavior for -- device families other than Stratix/Stratix II/Stratix GX and Cyclone. -- Initial Block ---------------- INITIAL: process (iinclock_apex, ioutclock_apex) variable init : boolean := false; begin if (not init) then if (lpm_hint = "USE_EAB=ON") then -- ------------------------------------------------------------------------- -- the following behaviour come in effect when RAM is implemented in EAB/ESB -- This is the flag to indicate if the memory is constructed using EAB/ESB: -- A write request requires both rising and falling edge of the clock -- to complete. First the data will be clocked in (registered) at the -- rising edge and will not be written into the ESB/EAB memory until -- the falling edge appears on the the write clock. -- No such restriction if the memory is constructed using LCs. if (write_reg = "INCLOCK") then write_at_low_clock <= true; end if; -- The read ports will not hold any value (zero) if rden is low. This -- behavior only apply to memory constructed using EAB/ESB, but not LCs. if (intended_device_family = DEV_APEX20K) then rden_low_output_0 <= true; end if; end if; init := true; end if; end process INITIAL; ------------------------- -- Syncronization Process ------------------------- SYNC: process(data, idata_reg, rden_a, rden_b, irden_reg_a, irden_reg_b, rdaddress_a, rdaddress_b, irdaddress_reg_a, irdaddress_reg_b, wren, iwren_reg, wraddress, iwraddress_reg, iqa_tmp, iqb_tmp, iqa_reg, iqb_reg, aclr) begin if ((rdaddress_reg_a = "INCLOCK") or (rdaddress_reg_a = "OUTCLOCK")) then irdaddress_tmp_a <= irdaddress_reg_a; else irdaddress_tmp_a <= rdaddress_a; end if; if ((rdcontrol_reg_a = "INCLOCK") or (rdcontrol_reg_a = "OUTCLOCK")) then irden_tmp_a <= irden_reg_a; else irden_tmp_a <= rden_a; end if; if ((rdaddress_reg_b = "INCLOCK") or (rdaddress_reg_b = "OUTCLOCK")) then irdaddress_tmp_b <= irdaddress_reg_b; else irdaddress_tmp_b <= rdaddress_b; end if; if ((rdcontrol_reg_b = "INCLOCK") or (rdcontrol_reg_b = "OUTCLOCK")) then irden_tmp_b <= irden_reg_b; else irden_tmp_b <= rden_b; end if; if (write_reg = "INCLOCK") then iwraddress_tmp <= iwraddress_reg; iwren_tmp <= iwren_reg; else iwraddress_tmp <= wraddress; iwren_tmp <= wren; end if; if (indata_reg = "INCLOCK") then idata_tmp <= idata_reg; else idata_tmp <= data; end if; if (outdata_reg_a = "OUTCLOCK") then iqa_apex <= iqa_reg; else iqa_apex <= iqa_tmp; end if; if (outdata_reg_b = "OUTCLOCK") then iqb_apex <= iqb_reg; else iqb_apex <= iqb_tmp; end if; if (aclr = '1') then if(indata_aclr = "ON") then idata_tmp <= (OTHERS => '0'); end if; if(write_aclr = "ON") then iwraddress_tmp <= (OTHERS => '0'); iwren_tmp <= '0'; end if; if(rdaddress_aclr_a = "ON") then irdaddress_tmp_a <= (OTHERS => '0'); end if; if(rdcontrol_aclr_a = "ON") then irden_tmp_a <= '0'; end if; if(rdaddress_aclr_b = "ON") then irdaddress_tmp_b <= (OTHERS => '0'); end if; if(rdcontrol_aclr_b = "ON") then irden_tmp_b <= '0'; end if; if(outdata_aclr_a = "ON") then iqa_apex <= (OTHERS => '0'); end if; if(outdata_aclr_b = "ON") then iqb_apex <= (OTHERS => '0'); end if; end if; end process SYNC; ------------------------- -- Syncronization Process ------------------------- SYNC2: process(idata_hi, idata_lo, iwraddress_hi, iwraddress_lo, iwren_hi, iwren_lo) begin if (write_at_low_clock) then idata_reg <= idata_lo; iwren_reg <= iwren_lo; iwraddress_reg <= iwraddress_lo; else idata_reg <= idata_hi; iwren_reg <= iwren_hi; iwraddress_reg <= iwraddress_hi; end if; end process SYNC2; -- At posedge of the write clock: -- All input ports values (data, address and control) are -- clocked in from physical ports to internal variables -- Write Cycle: i*_hi -- Read Cycle: i*_reg (Shared Clock Mode) -- -- At negedge of the write clock: -- Write Cycle: since internally data only completed written on memory -- at the falling edge of write clock, the "write" related -- data, address and controls need to be shift to another -- varibles (i*_hi -> i*_lo) during falling edge. PROC_INCLOCK_OUTCLOCK: process (iinclock_apex, ioutclock_apex) begin -- WRITE REGS -- if ((aclr = '1') and (indata_aclr = "ON")) then idata_hi <= (OTHERS => '0'); idata_lo <= (OTHERS => '0'); elsif (iinclock_apex'event and (iinclock_apex = '1') and (inclocken = '1')) then idata_hi <= data; elsif (iinclock_apex'event and (iinclock_apex = '0')) then idata_lo <= idata_hi; end if; if ((aclr = '1') and (write_aclr = "ON")) then iwraddress_hi <= (OTHERS => '0'); iwraddress_lo <= (OTHERS => '0'); iwren_hi <= '0'; iwren_lo <= '0'; elsif (iinclock_apex'event and (iinclock_apex = '1') and (inclocken = '1')) then iwraddress_hi <= wraddress; iwren_hi <= wren; elsif (iinclock_apex'event and (iinclock_apex = '0')) then iwraddress_lo <= iwraddress_hi; iwren_lo <= iwren_hi; end if; -- READ REGS PORT A-- if (aclr = '1' and outdata_aclr_a = "ON") then iqa_reg <= (OTHERS => '0'); elsif (ioutclock_apex'event and ioutclock_apex = '1' and outclocken = '1') then iqa_reg <= iqa_tmp; end if; ------------------------------------------------- -- Synchronous READ Operation (SHARED CLOCK MODE) ------------------------------------------------- -- READ REGS PORT A ------------------- if (rdaddress_reg_a = "INCLOCK") then if ((aclr = '1') and (rdaddress_aclr_a = "ON")) then irdaddress_reg_a <= (OTHERS => '0'); elsif (iinclock_apex'event and (iinclock_apex = '1') and (inclocken = '1')) then irdaddress_reg_a <= rdaddress_a; end if; end if; if (rdcontrol_reg_a = "INCLOCK") then if ((aclr = '1') and (rdcontrol_aclr_a = "ON")) then irden_reg_a <= '0'; elsif (iinclock_apex'event and (iinclock_apex = '1') and (inclocken = '1')) then irden_reg_a <= rden_a; end if; end if; if (rdaddress_reg_a = "OUTCLOCK") then if ((aclr = '1') and (rdaddress_aclr_a = "ON")) then irdaddress_reg_a <= (OTHERS => '0'); elsif (ioutclock_apex'event and (ioutclock_apex = '1') and (outclocken = '1')) then irdaddress_reg_a <= rdaddress_a; end if; end if; if (rdcontrol_reg_a = "OUTCLOCK") then if ((aclr = '1') and (rdcontrol_aclr_a = "ON")) then irden_reg_a <= '0'; elsif (ioutclock_apex'event and (ioutclock_apex = '1') and (outclocken = '1')) then irden_reg_a <= rden_a; end if; end if; ---------------------------------------------------- -- Synchronouse READ Operation (SEPERATE CLOCK MODE) -- At posedge of read clock: -- Read Cycle: This block is valid only if the operating mode is -- in "Seperate Clock Mode". All read data, address -- and control are clocked out from internal vars -- (i*_reg) to output port. ---------------------------------------------------- -- READ REGS PORT B ------------------- if ((aclr = '1') and (outdata_aclr_b = "ON")) then iqb_reg <= (OTHERS => '0'); elsif (ioutclock_apex'event and (ioutclock_apex = '1') and (outclocken = '1')) then iqb_reg <= iqb_tmp; end if; if (rdaddress_reg_b = "INCLOCK") then if (aclr = '1' and rdaddress_aclr_b = "ON") then irdaddress_reg_b <= (OTHERS => '0'); elsif (iinclock_apex'event and iinclock_apex = '1' and inclocken = '1') then irdaddress_reg_b <= rdaddress_b; end if; end if; if (rdcontrol_reg_b = "INCLOCK") then if (aclr = '1' and rdcontrol_aclr_b = "ON") then irden_reg_b <= '0'; elsif (iinclock_apex'event and iinclock_apex = '1' and inclocken = '1') then irden_reg_b <= rden_b; end if; end if; if (rdaddress_reg_b = "OUTCLOCK") then if ((aclr = '1') and (rdaddress_aclr_b = "ON")) then irdaddress_reg_b <= (OTHERS => '0'); elsif (ioutclock_apex'event and (ioutclock_apex = '1') and (outclocken = '1')) then irdaddress_reg_b <= rdaddress_b; end if; end if; if (rdcontrol_reg_b = "OUTCLOCK") then if ((aclr = '1') and (rdcontrol_aclr_b = "ON")) then irden_reg_b <= '0'; elsif (ioutclock_apex'event and (ioutclock_apex = '1') and (outclocken = '1')) then irden_reg_b <= rden_b; end if; end if; end process PROC_INCLOCK_OUTCLOCK; ----------------------- -- MEMORY Process Block ----------------------- MEMORY: process(idata_tmp, iwren_tmp, irden_tmp_a, irden_tmp_b, irdaddress_tmp_a, irdaddress_tmp_b, iwraddress_tmp) variable mem_data : alt_memory; variable mem_data_word : std_logic_vector(width-1 downto 0) := (OTHERS => '0'); variable mem_init : boolean := false; variable i : integer := 0; variable j : integer := 0; variable k : integer := 0; variable n : integer := 0; variable m : integer := 0; variable lineno : integer := 0; variable buf : line; variable booval : boolean := false; FILE mem_data_file : TEXT; variable base : string(2 downto 1) := " "; variable byte : string(2 downto 1) := " "; variable rec_type : string(2 downto 1) := " "; variable datain : string(2 downto 1) := " "; variable addr : string(2 downto 1) := " "; variable checksum : string(2 downto 1) := " "; variable startadd : string(4 downto 1) := " "; variable ibase : integer := 0; variable ibyte : integer := 0; variable istartadd : integer := 0; variable check_sum_vec : std_logic_vector(7 downto 0) := (OTHERS => '0'); variable check_sum_vec_tmp : std_logic_vector(7 downto 0) := (OTHERS => '0'); begin -- INITIALIZE -- if NOT(mem_init) then --INITIALIZE TO X, IF WRITE_REG IS "UNREGISTERED" if (write_reg = "UNREGISTERED") then for i in mem_data'LOW to mem_data'HIGH loop mem_data(i) := (OTHERS => 'X'); end loop; else -- INITIALIZE TO 0 -- for i in mem_data'LOW to mem_data'HIGH loop mem_data(i) := (OTHERS => '0'); end loop; end if; if (lpm_file /= "UNUSED") then -- ************************************************ -- Read in RAM intialization file (hex) -- ************************************************ FILE_OPEN(mem_data_file, lpm_file, READ_MODE); WHILE NOT ENDFILE(mem_data_file) loop booval := true; READLINE(mem_data_file, buf); lineno := lineno + 1; check_sum_vec := (OTHERS => '0'); if (buf(buf'LOW) = ':') then i := 1; shrink_line(buf, i); READ(L=>buf, VALUE=>byte, good=>booval); if not (booval) then ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format!" SEVERITY ERROR; end if; ibyte := HEX_STR_TO_INT(byte); check_sum_vec := unsigned(check_sum_vec) + unsigned(CONV_STD_LOGIC_VECTOR(ibyte, 8)); READ(L=>buf, VALUE=>startadd, good=>booval); if not (booval) then ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format! " SEVERITY ERROR; end if; istartadd := HEX_STR_TO_INT(startadd); addr(2) := startadd(4); addr(1) := startadd(3); check_sum_vec := unsigned(check_sum_vec) + unsigned(CONV_STD_LOGIC_VECTOR(HEX_STR_TO_INT(addr), 8)); addr(2) := startadd(2); addr(1) := startadd(1); check_sum_vec := unsigned(check_sum_vec) + unsigned(CONV_STD_LOGIC_VECTOR(HEX_STR_TO_INT(addr), 8)); READ(L=>buf, VALUE=>rec_type, good=>booval); if not (booval) then ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format! " SEVERITY ERROR; end if; check_sum_vec := unsigned(check_sum_vec) + unsigned(CONV_STD_LOGIC_VECTOR(HEX_STR_TO_INT(rec_type), 8)); else ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format! " SEVERITY ERROR; end if; case rec_type is when "00"=> -- Data record i := 0; k := (WIDTH + 7) / 8; -- # of bytes per entry while (i < ibyte) loop mem_data_word := (others => '0'); n := (k - 1)*8; m := width - 1; for j in 1 to k loop -- read in data a byte (2 hex chars) at a time. READ(L=>buf, VALUE=>datain,good=>booval); if not (booval) then ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format! " SEVERITY ERROR; end if; check_sum_vec := unsigned(check_sum_vec) + unsigned(CONV_STD_LOGIC_VECTOR(HEX_STR_TO_INT(datain), 8)); mem_data_word(m downto n) := CONV_STD_LOGIC_VECTOR(HEX_STR_TO_INT(datain), m-n+1); m := n - 1; n := n - 8; end loop; i := i + k; mem_data(ibase + istartadd) := mem_data_word; istartadd := istartadd + 1; end loop; when "01"=> exit; when "02"=> ibase := 0; if (ibyte /= 2) then ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format for record type 02! " SEVERITY ERROR; end if; for i in 0 to (ibyte-1) loop READ(L=>buf, VALUE=>base,good=>booval); ibase := (ibase * 256) + HEX_STR_TO_INT(base); if not (booval) then ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format! " SEVERITY ERROR; end if; check_sum_vec := unsigned(check_sum_vec) + unsigned(CONV_STD_LOGIC_VECTOR(HEX_STR_TO_INT(base), 8)); end loop; ibase := ibase * 16; when OTHERS => ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal record type in Intel Hex File! " SEVERITY ERROR; end case; READ(L=>buf, VALUE=>checksum,good=>booval); if not (booval) then ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Checksum is missing! " SEVERITY ERROR; end if; check_sum_vec := unsigned(not (check_sum_vec)) + 1 ; check_sum_vec_tmp := CONV_STD_LOGIC_VECTOR(HEX_STR_TO_INT(checksum),8); if (unsigned(check_sum_vec) /= unsigned(check_sum_vec_tmp)) then ASSERT FALSE REPORT "[Line "& INT_TO_STR_RAM(lineno) & "]:Incorrect checksum!" SEVERITY ERROR; end if; end loop; FILE_CLOSE(mem_data_file); end if; mem_init := TRUE; -- --******************************************* else -- already initialized -- MEMORY FUNCTION -- -- This is where data is being write to the internal memory: mem_data[] -- if (iwren_tmp = '1') then mem_data (ieee.std_logic_unsigned.conv_integer(iwraddress_tmp)) := idata_tmp; end if; -- Triple-Port Ram (alt3pram) has one write port and two read ports (a and b) -- Below is the operation to read data from internal memory (mem_data[]) -- to the output port (iqa_tmp or iqb_tmp) -- Note: iq*_tmp will serve as the var directly link to the physical -- output port q* if alt3pram is operate in "Shared Clock Mode", -- else data read from iq*_tmp will need to be latched to i_q*_reg -- through outclock before it is fed to the output port q* (qa or qb). if (irden_tmp_a = '1') then iqa_tmp <= mem_data(ieee.std_logic_unsigned.conv_integer(irdaddress_tmp_a)); elsif (rden_low_output_0) then iqa_tmp <= (OTHERS => '0'); end if; if (irden_tmp_b = '1') then iqb_tmp <= mem_data(ieee.std_logic_unsigned.conv_integer(irdaddress_tmp_b)); elsif (rden_low_output_0) then iqb_tmp <= (OTHERS => '0'); end if; end if; end process MEMORY; end behavior; -- architecture of alt3pram --end of alt3pram -- START_ENTITY_HEADER---------------------------------------------------------- -- -- Entity Name : ALTQPRAM -- -- Description : Asynchronous quad ports memory or memory with synchronous -- inputs and/or outputs -- -- Limitation : -- -- Results expected : [Synchronous Write to Memory (all inputs registered)] -- inclock inclocken wren Function -- X L L No change -- not H H No change -- posedge L X No change -- posedge H H Memory content updated -- -- [Synchronous Read from Memory] -- inclock inclocken rden Function -- X L L No change -- not H H No change -- posedge L X No change. -- posedge H H Memory content showed -- at the output port -- -- [Asynchronous Memory Operations] -- wren Function -- L No change -- H Memory content updated -- Memory content showed -- at the output port -- ---END_ENTITY_HEADER------------------------------------------------------------ library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use std.textio.all; use work.ALTERA_COMMON_CONVERSION.all; -- BEGINNING OF ENTITY -- ENTITY DECLARATION entity altqpram is -- GENERIC DECLARATION generic ( operation_mode : string := "QUAD_PORT"; -- PORT A WRITE PARAMETERS width_write_a : natural := 1; widthad_write_a : natural := 1; numwords_write_a : natural := 0; indata_reg_a : string := "INCLOCK_A"; indata_aclr_a : string := "INACLR_A"; wrcontrol_wraddress_reg_a : string := "INCLOCK_A"; wrcontrol_aclr_a : string := "INACLR_A"; wraddress_aclr_a : string := "INACLR_A"; -- PORT B WRITE PARAMETERS width_write_b : natural := 1; widthad_write_b : natural := 1; numwords_write_b : natural := 0; indata_reg_b : string := "INCLOCK_B"; indata_aclr_b : string := "INACLR_B"; wrcontrol_wraddress_reg_b : string := "INCLOCK_B"; wrcontrol_aclr_b : string := "INACLR_B"; wraddress_aclr_b : string := "INACLR_B"; -- PORT A READ PARAMETERS width_read_a : natural := 1; widthad_read_a : natural := 1; numwords_read_a : natural := 0; rdcontrol_reg_a : string := "OUTCLOCK_A"; rdcontrol_aclr_a : string := "OUTACLR_A"; rdaddress_reg_a : string := "OUTCLOCK_A"; rdaddress_aclr_a : string := "OUTACLR_A"; outdata_reg_a : string := "UNREGISTERED"; outdata_aclr_a : string := "OUTACLR_A"; -- PORT B READ PARAMETERS width_read_b : natural := 1; widthad_read_b : natural := 1; numwords_read_b : natural := 0; rdcontrol_reg_b : string := "OUTCLOCK_B"; rdcontrol_aclr_b : string := "OUTACLR_B"; rdaddress_reg_b : string := "OUTCLOCK_B"; rdaddress_aclr_b : string := "OUTACLR_B"; outdata_reg_b : string := "UNREGISTERED"; outdata_aclr_b : string := "OUTACLR_B"; init_file : string := "UNUSED"; lpm_hint : string := "UNUSED"; lpm_type : string := "altqpram" ); -- PORT DECLARATION port ( wren_a : in std_logic := '0'; wren_b : in std_logic := '0'; data_a : in std_logic_vector(width_write_a-1 downto 0) := (others => '0'); data_b : in std_logic_vector(width_write_b-1 downto 0) := (others => '0'); wraddress_a : in std_logic_vector(widthad_write_a-1 downto 0) := (others => '0'); wraddress_b : in std_logic_vector(widthad_write_b-1 downto 0) := (others => '0'); inclock_a : in std_logic := '0'; inclock_b : in std_logic := '0'; inclocken_a : in std_logic := '1'; inclocken_b : in std_logic := '1'; rden_a : in std_logic := '1'; rden_b : in std_logic := '1'; rdaddress_a : in std_logic_vector(widthad_read_a-1 downto 0) := (others => '0'); rdaddress_b : in std_logic_vector(widthad_read_b-1 downto 0) := (others => '0'); outclock_a : in std_logic := '0'; outclock_b : in std_logic := '0'; outclocken_a : in std_logic := '1'; outclocken_b : in std_logic := '1'; inaclr_a : in std_logic := '0'; inaclr_b : in std_logic := '0'; outaclr_a : in std_logic := '0'; outaclr_b : in std_logic := '0'; q_a : out std_logic_vector(width_read_a-1 downto 0); q_b : out std_logic_vector(width_read_b-1 downto 0) ); end altqpram; -- END OF ENTITY -- BEGINNING OF ARCHITECTURE architecture behavior of altqpram is -- TYPE DECLARATION type alt_mem_read is array((2**widthad_read_a)-1 downto 0) of std_logic_vector(width_read_a-1 downto 0); type alt_mem_write is array((2**widthad_write_a)-1 downto 0) of std_logic_vector(width_write_a-1 downto 0); -- SIGNAL DECLARATION signal i_data_tmp_a : std_logic_vector(width_write_a-1 downto 0) := (others => '0'); signal i_data_reg_a : std_logic_vector(width_write_a-1 downto 0) := (others => '0'); signal i_data_tmp_b : std_logic_vector(width_write_b-1 downto 0) := (others => '0'); signal i_data_reg_b : std_logic_vector(width_write_b-1 downto 0) := (others => '0'); signal i_data_hi_a : std_logic_vector(width_write_a-1 downto 0) := (others => '0'); signal i_data_lo_a : std_logic_vector(width_write_a-1 downto 0) := (others => '0'); signal i_data_hi_b : std_logic_vector(width_write_b-1 downto 0) := (others => '0'); signal i_data_lo_b : std_logic_vector(width_write_b-1 downto 0) := (others => '0'); signal i_q_tmp_a : std_logic_vector(width_read_a-1 downto 0) := (others => '0'); signal i_q_reg_a : std_logic_vector(width_read_a-1 downto 0) := (others => '0'); signal i_q_tmp_b : std_logic_vector(width_read_b-1 downto 0) := (others => '0'); signal i_q_reg_b : std_logic_vector(width_read_b-1 downto 0) := (others => '0'); signal i_rdaddress_tmp_a : std_logic_vector(widthad_read_a-1 downto 0) := (others => '0'); signal i_rdaddress_reg_a : std_logic_vector(widthad_read_a-1 downto 0) := (others => '0'); signal i_rdaddress_tmp_b : std_logic_vector(widthad_read_b-1 downto 0) := (others => '0'); signal i_rdaddress_reg_b : std_logic_vector(widthad_read_b-1 downto 0) := (others => '0'); signal i_wraddress_tmp_a : std_logic_vector(widthad_write_a-1 downto 0) := (others => '0'); signal i_wraddress_reg_a : std_logic_vector(widthad_write_a-1 downto 0) := (others => '0'); signal i_wraddress_tmp_b : std_logic_vector(widthad_write_b-1 downto 0) := (others => '0'); signal i_wraddress_reg_b : std_logic_vector(widthad_write_b-1 downto 0) := (others => '0'); signal i_wraddress_hi_a : std_logic_vector(widthad_write_a-1 downto 0) := (others => '0'); signal i_wraddress_lo_a : std_logic_vector(widthad_write_a-1 downto 0) := (others => '0'); signal i_wraddress_hi_b : std_logic_vector(widthad_write_b-1 downto 0) := (others => '0'); signal i_wraddress_lo_b : std_logic_vector(widthad_write_b-1 downto 0) := (others => '0'); signal i_wren_tmp_a : std_logic := '0'; signal i_wren_reg_a : std_logic := '0'; signal i_wren_tmp_b : std_logic := '0'; signal i_wren_reg_b : std_logic := '0'; signal i_wren_hi_a : std_logic := '0'; signal i_wren_lo_a : std_logic := '0'; signal i_wren_hi_b : std_logic := '0'; signal i_wren_lo_b : std_logic := '0'; signal i_rden_tmp_a : std_logic := '0'; signal i_rden_reg_a : std_logic := '0'; signal i_rden_tmp_b : std_logic := '0'; signal i_rden_reg_b : std_logic := '0'; signal i_indata_aclr_a : std_logic := '0'; signal i_outdata_aclr_a : std_logic := '0'; signal i_wrcontrol_aclr_a : std_logic := '0'; signal i_wraddress_aclr_a : std_logic := '0'; signal i_rdcontrol_aclr_a : std_logic := '0'; signal i_rdaddress_aclr_a : std_logic := '0'; signal i_indata_aclr_b : std_logic := '0'; signal i_outdata_aclr_b : std_logic := '0'; signal i_wrcontrol_aclr_b : std_logic := '0'; signal i_wraddress_aclr_b : std_logic := '0'; signal i_rdcontrol_aclr_b : std_logic := '0'; signal i_rdaddress_aclr_b : std_logic := '0'; signal i_numwords_write_a : integer := numwords_write_a; signal i_numwords_write_b : integer := numwords_write_b; signal i_numwords_read_a : integer := numwords_read_a; signal i_numwords_read_b : integer := numwords_read_b; signal write_at_low_clock_a : boolean := false; signal write_at_low_clock_b : boolean := false; signal mem_init : boolean := false; signal aclr_updated : std_logic := '0'; signal both_clk_trigger : std_logic := '0'; signal op_mode : natural := 0; begin -- This process handling the aclr signals ACLRS : process (inaclr_a, outaclr_a, inaclr_b, outaclr_b) begin -- ACLR_A i_indata_aclr_a <= '0'; i_wrcontrol_aclr_a <= '0'; i_wraddress_aclr_a <= '0'; i_outdata_aclr_a <= '0'; i_rdcontrol_aclr_a <= '0'; i_rdaddress_aclr_a <= '0'; if (inaclr_a = '1') then if ((indata_aclr_a = "INACLR_A") and (indata_reg_a /= "UNREGISTERED")) then i_indata_aclr_a <= '1'; end if; if ((wrcontrol_aclr_a = "INACLR_A") and (wrcontrol_wraddress_reg_a /= "UNREGISTERED")) then i_wrcontrol_aclr_a <= '1'; end if; if ((wraddress_aclr_a = "INACLR_A") and (wrcontrol_wraddress_reg_a /= "UNREGISTERED")) then i_wraddress_aclr_a <= '1'; end if; if ((outdata_aclr_a = "INACLR_A") and (outdata_reg_a /= "UNREGISTERED")) then i_outdata_aclr_a <= '1'; end if; if ((rdcontrol_aclr_a = "INACLR_A") and (rdcontrol_reg_a /= "UNREGISTERED")) then i_rdcontrol_aclr_a <= '1'; end if; if ((rdaddress_aclr_a = "INACLR_A") and (rdaddress_reg_a /= "UNREGISTERED")) then i_rdaddress_aclr_a <= '1'; end if; end if; if (outaclr_a = '1') then if ((outdata_aclr_a = "OUTACLR_A") and (outdata_reg_a /= "UNREGISTERED")) then i_outdata_aclr_a <= '1'; end if; if ((rdcontrol_aclr_a = "OUTACLR_A") and (rdcontrol_reg_a /= "UNREGISTERED")) then i_rdcontrol_aclr_a <= '1'; end if; if ((rdaddress_aclr_a = "OUTACLR_A") and (rdaddress_reg_a /= "UNREGISTERED")) then i_rdaddress_aclr_a <= '1'; end if; end if; -- ACLR_B -- i_indata_aclr_b <= '0'; i_wrcontrol_aclr_b <= '0'; i_wraddress_aclr_b <= '0'; i_outdata_aclr_b <= '0'; i_rdcontrol_aclr_b <= '0'; i_rdaddress_aclr_b <= '0'; if (inaclr_b = '1') then if ((indata_aclr_b = "INACLR_B") and (indata_reg_b /= "UNREGISTERED")) then i_indata_aclr_b <= '1'; end if; if ((wrcontrol_aclr_b = "INACLR_B") and (wrcontrol_wraddress_reg_b /= "UNREGISTERED")) then i_wrcontrol_aclr_b <= '1'; end if; if ((wraddress_aclr_b = "INACLR_B") and (wrcontrol_wraddress_reg_b /= "UNREGISTERED")) then i_wraddress_aclr_b <= '1'; end if; if ((outdata_aclr_b = "INACLR_B") and (outdata_reg_b /= "UNREGISTERED")) then i_outdata_aclr_b <= '1'; end if; if ((rdcontrol_aclr_b = "INACLR_B") and (rdcontrol_reg_b /= "UNREGISTERED")) then i_rdcontrol_aclr_b <= '1'; end if; if ((rdaddress_aclr_b = "INACLR_B") and (rdaddress_reg_b /= "UNREGISTERED")) then i_rdaddress_aclr_b <= '1'; end if; end if; if (outaclr_b = '1') then if ((outdata_aclr_b = "OUTACLR_B") and (outdata_reg_b /= "UNREGISTERED")) then i_outdata_aclr_b <= '1'; end if; if ((rdcontrol_aclr_b = "OUTACLR_B") and (rdcontrol_reg_b /= "UNREGISTERED")) then i_rdcontrol_aclr_b <= '1'; end if; if ((rdaddress_aclr_b = "OUTACLR_B") and (rdaddress_reg_b /= "UNREGISTERED")) then i_rdaddress_aclr_b <= '1'; end if; end if; aclr_updated <= not aclr_updated; end process ACLRS; -- This process synchronize input and output signals. -- It assigns the correct signals to temporary buffers accordingly, -- ie cleared, registered or not. SYNC: process (data_a, data_b, i_data_reg_a, i_data_reg_b, rden_a, rden_b, i_rden_reg_a, i_rden_reg_b, rdaddress_a, rdaddress_b, i_rdaddress_reg_a, i_rdaddress_reg_b, wren_a, wren_b, i_wren_reg_a, i_wren_reg_b, wraddress_a, wraddress_b, i_wraddress_reg_a, i_wraddress_reg_b, i_q_tmp_a, i_q_tmp_b, i_q_reg_a, i_q_reg_b, aclr_updated) begin if ((not inaclr_a'event) and (not outaclr_a'event) and (not inaclr_b'event) and (not outaclr_b'event)) then if (i_rdaddress_aclr_a = '1') then i_rdaddress_tmp_a <= (others => '0'); elsif (rdaddress_reg_a = "UNREGISTERED") then i_rdaddress_tmp_a <= rdaddress_a; else i_rdaddress_tmp_a <= i_rdaddress_reg_a; end if; if (i_rdaddress_aclr_b = '1') then i_rdaddress_tmp_b <= (others => '0'); elsif (rdaddress_reg_b = "UNREGISTERED") then i_rdaddress_tmp_b <= rdaddress_b; else i_rdaddress_tmp_b <= i_rdaddress_reg_b; end if; if (i_rdcontrol_aclr_a = '1') then i_rden_tmp_a <= '0'; elsif (rdcontrol_reg_a = "UNREGISTERED") then i_rden_tmp_a <= rden_a; else i_rden_tmp_a <= i_rden_reg_a; end if; if (i_rdcontrol_aclr_b = '1') then i_rden_tmp_b <= '0'; elsif (rdcontrol_reg_b = "UNREGISTERED") then i_rden_tmp_b <= rden_b; else i_rden_tmp_b <= i_rden_reg_b; end if; if (i_wraddress_aclr_a = '1') then i_wraddress_tmp_a <= (others => '0'); elsif (wrcontrol_wraddress_reg_a = "UNREGISTERED") then i_wraddress_tmp_a <= wraddress_a; else i_wraddress_tmp_a <= i_wraddress_reg_a; end if; if (i_wraddress_aclr_b = '1') then i_wraddress_tmp_b <= (others => '0'); elsif (wrcontrol_wraddress_reg_b = "UNREGISTERED") then i_wraddress_tmp_b <= wraddress_b; else i_wraddress_tmp_b <= i_wraddress_reg_b; end if; if (i_wrcontrol_aclr_a = '1') then i_wren_tmp_a <= '0'; elsif (wrcontrol_wraddress_reg_a = "UNREGISTERED") then i_wren_tmp_a <= wren_a; else i_wren_tmp_a <= i_wren_reg_a; end if; if (i_wrcontrol_aclr_b = '1') then i_wren_tmp_b <= '0'; elsif (wrcontrol_wraddress_reg_b = "UNREGISTERED") then i_wren_tmp_b <= wren_b; else i_wren_tmp_b <= i_wren_reg_b; end if; if (i_indata_aclr_a = '1') then i_data_tmp_a <= (others => '0'); elsif (indata_reg_a = "UNREGISTERED") then i_data_tmp_a <= data_a; else i_data_tmp_a <= i_data_reg_a; end if; if (i_indata_aclr_b = '1') then i_data_tmp_b <= (others => '0'); elsif (indata_reg_b = "UNREGISTERED") then i_data_tmp_b <= data_b; else i_data_tmp_b <= i_data_reg_b; end if; if (((op_mode mod 6) = 0) or (i_outdata_aclr_a = '1')) then q_a <= (others => '0'); elsif (outdata_reg_a = "UNREGISTERED") then q_a <= i_q_tmp_a; else q_a <= i_q_reg_a; end if; if (((op_mode mod 5) = 0) or (i_outdata_aclr_b = '1')) then q_b <= (others => '0'); elsif (outdata_reg_b = "UNREGISTERED") then q_b <= i_q_tmp_b; else q_b <= i_q_reg_b; end if; end if; end process SYNC; -- This process synchronize the port A inputs. -- (For both clock edges) SYNC_A: process (i_data_hi_a, i_data_lo_a, i_indata_aclr_a, i_wraddress_hi_a, i_wraddress_lo_a, i_wren_hi_a, i_wren_lo_a, i_wraddress_aclr_a, i_wrcontrol_aclr_a) begin if (i_indata_aclr_a = '1') then i_data_reg_a <= (others => '0'); elsif (write_at_low_clock_a) then i_data_reg_a <= i_data_lo_a; else i_data_reg_a <= i_data_hi_a; end if; if (i_wrcontrol_aclr_a = '1') then i_wren_reg_a <= '0'; elsif (operation_mode /= "BIDIR_DUAL_PORT") then if (write_at_low_clock_a) then i_wren_reg_a <= i_wren_lo_a; else i_wren_reg_a <= i_wren_hi_a; end if; else i_wren_reg_a <= i_wren_hi_a; end if; if (i_wraddress_aclr_a = '1') then i_wraddress_reg_a <= (others => '0'); elsif (write_at_low_clock_a) then if ((operation_mode = "QUAD_PORT") or (operation_mode = "DUAL_PORT")) then i_wraddress_reg_a <= i_wraddress_lo_a; else i_wraddress_reg_a <= i_wraddress_hi_a; end if; else i_wraddress_reg_a <= i_wraddress_hi_a; end if; end process SYNC_A; -- This process synchronize the port B inputs. -- (For both clock edges) SYNC_B: process(i_data_hi_b, i_data_lo_b, i_wraddress_hi_b, i_wraddress_lo_b, i_wren_hi_b, i_wren_lo_b, i_wraddress_aclr_b, i_wrcontrol_aclr_b, i_indata_aclr_b) begin if (i_indata_aclr_b = '1') then i_data_reg_b <= (others => '0'); elsif (write_at_low_clock_b) then i_data_reg_b <= i_data_lo_b; else i_data_reg_b <= i_data_hi_b; end if; if (i_wrcontrol_aclr_b = '1') then i_wren_reg_b <= '0'; elsif (write_at_low_clock_b) then if ((operation_mode = "QUAD_PORT") or (operation_mode = "DUAL_PORT")) then i_wren_reg_b <= i_wren_lo_b; else i_wren_reg_b <= i_wren_hi_b; end if; else i_wren_reg_b <= i_wren_hi_b; end if; if (i_wraddress_aclr_b = '1') then i_wraddress_reg_b <= (others => '0'); elsif (write_at_low_clock_b) then if ((operation_mode = "QUAD_PORT") or (operation_mode = "DUAL_PORT")) then i_wraddress_reg_b <= i_wraddress_lo_b; else i_wraddress_reg_b <= i_wraddress_hi_b; end if; else i_wraddress_reg_b <= i_wraddress_hi_b; end if; end process SYNC_B; -- This process is to check whether inclock for both ports -- trigger at the same time. SIMULTANEOUS_CLOCK: process(inclock_a, inclock_b) begin if (inclock_a'event and inclock_b'event) then both_clk_trigger <= '1'; else both_clk_trigger <= '0'; end if; end process SIMULTANEOUS_CLOCK; -- This process is to handling registered inputs and output for port A REG_A: process (inclock_a, outclock_a) begin if (inclock_a'event) then if (i_indata_aclr_a = '1') then i_data_hi_a <= (others => '0'); i_data_lo_a <= (others => '0'); elsif ((inclock_a = '1') and (inclocken_a = '1')) then i_data_hi_a <= data_a; elsif (inclock_a = '0') then i_data_lo_a <= i_data_hi_a; end if; if (i_wraddress_aclr_a = '1') then i_wraddress_hi_a <= (others => '0'); i_wraddress_lo_a <= (others => '0'); elsif ((inclock_a = '1') and (inclocken_a = '1')) then i_wraddress_hi_a <= wraddress_a; elsif (inclock_a = '0') then i_wraddress_lo_a <= i_wraddress_hi_a; end if; if (i_wrcontrol_aclr_a = '1') then i_wren_hi_a <= '0'; i_wren_lo_a <= '0'; elsif ((inclock_a = '1') and (inclocken_a = '1')) then i_wren_hi_a <= wren_a; elsif (inclock_a = '0') then i_wren_lo_a <= i_wren_hi_a; end if; if (outdata_reg_a = "INCLOCK_A") then if (i_outdata_aclr_a = '1') then i_q_reg_a <= (others => '0'); elsif ((inclock_a = '1') and (inclocken_a = '1')) then i_q_reg_a <= i_q_tmp_a; end if; end if; if (rdaddress_reg_a = "INCLOCK_A") then if (i_rdaddress_aclr_a = '1') then i_rdaddress_reg_a <= (others => '0'); elsif ((inclock_a = '1') and (inclocken_a = '1')) then i_rdaddress_reg_a <= rdaddress_a; end if; end if; if (rdcontrol_reg_a = "INCLOCK_A") then if (i_rdcontrol_aclr_a = '1') then i_rden_reg_a <= '0'; elsif ((inclock_a = '1') and (inclocken_a = '1')) then i_rden_reg_a <= rden_a; end if; end if; end if; if (outclock_a'event) then if (outdata_reg_a = "OUTCLOCK_A") then if (i_outdata_aclr_a = '1') then i_q_reg_a <= (others => '0'); elsif ((outclock_a = '1') and (outclocken_a = '1')) then i_q_reg_a <= i_q_tmp_a; end if; end if; if (rdaddress_reg_a = "OUTCLOCK_A") then if (i_rdaddress_aclr_a = '1') then i_rdaddress_reg_a <= (others => '0'); elsif ((outclock_a = '1') and (outclocken_a = '1')) then i_rdaddress_reg_a <= rdaddress_a; end if; end if; if (rdcontrol_reg_a = "OUTCLOCK_A") then if (i_rdcontrol_aclr_a = '1') then i_rden_reg_a <= '0'; elsif ((outclock_a = '1') and (outclocken_a = '1')) then i_rden_reg_a <= rden_a; end if; end if; end if; end process REG_A; -- This process is to handling registered inputs and output for port B REG_B : process (inclock_b, outclock_b) begin if (inclock_b'event) then if (i_indata_aclr_b = '1') then i_data_hi_b <= (others => '0'); i_data_lo_b <= (others => '0'); elsif ((inclock_b = '1') and (inclocken_b = '1')) then i_data_hi_b <= data_b; elsif (inclock_b = '0') then i_data_lo_b <= i_data_hi_b; end if; if (i_wraddress_aclr_b = '1') then i_wraddress_hi_b <= (others => '0'); i_wraddress_lo_b <= (others => '0'); elsif ((inclock_b = '1') and (inclocken_b = '1')) then i_wraddress_hi_b <= wraddress_b; elsif (inclock_b = '0') then i_wraddress_lo_b <= i_wraddress_hi_b; end if; if (i_wrcontrol_aclr_b = '1') then i_wren_hi_b <= '0'; i_wren_lo_b <= '0'; elsif ((inclock_b = '1') and (inclocken_b = '1')) then i_wren_hi_b <= wren_b; elsif (inclock_b = '0') then i_wren_lo_b <= i_wren_hi_b; end if; if (outdata_reg_b = "INCLOCK_B") then if (i_outdata_aclr_b = '1') then i_q_reg_b <= (others => '0'); elsif ((inclock_b = '1') and (inclocken_b = '1')) then i_q_reg_b <= i_q_tmp_b; end if; end if; if (rdaddress_reg_b = "INCLOCK_B") then if (i_rdaddress_aclr_b = '1') then i_rdaddress_reg_b <= (others => '0'); elsif ((inclock_b = '1') and (inclocken_b = '1')) then i_rdaddress_reg_b <= rdaddress_b; end if; end if; if (rdcontrol_reg_b = "INCLOCK_B") then if (i_rdcontrol_aclr_b = '1') then i_rden_reg_b <= '0'; elsif ((inclock_b = '1') and (inclocken_b = '1')) then i_rden_reg_b <= rden_b; end if; end if; end if; if (outclock_b'event) then if (outdata_reg_b = "OUTCLOCK_B") then if (i_outdata_aclr_b = '1') then i_q_reg_b <= (others => '0'); elsif ((outclock_b = '1') and (outclocken_b = '1')) then i_q_reg_b <= i_q_tmp_b; end if; end if; if (rdaddress_reg_b = "OUTCLOCK_B") then if (i_rdaddress_aclr_b = '1') then i_rdaddress_reg_b <= (others => '0'); elsif ((outclock_b = '1') and (outclocken_b = '1')) then i_rdaddress_reg_b <= rdaddress_b; end if; end if; if (rdcontrol_reg_b = "OUTCLOCK_B") then if (i_rdcontrol_aclr_b = '1') then i_rden_reg_b <= '0'; elsif ((outclock_b = '1') and (outclocken_b = '1')) then i_rden_reg_b <= rden_b; end if; end if; end if; end process REG_B; -- This process is to initial memory contents and signals or variables -- initialization, and also to update the memory contents during write cycles MEMORY : process (i_data_tmp_a, i_wren_tmp_a, i_wraddress_tmp_a, i_wraddress_lo_a, i_rden_tmp_a, i_rdaddress_tmp_a, i_wren_lo_a, i_data_tmp_b, i_wren_tmp_b, i_wraddress_tmp_b, i_wraddress_lo_b, i_rden_tmp_b, i_rdaddress_tmp_b, i_wren_lo_b, mem_init) variable mem_rd_data : alt_mem_read; variable mem_wr_data : alt_mem_write; variable mem_rd_data_word : std_logic_vector(width_read_a-1 downto 0) := (others => '0'); variable mem_wr_data_word : std_logic_vector(width_write_a-1 downto 0) := (others => '0'); variable read_ratio : integer := 0; variable write_ratio : integer := 0; variable write_read_ratio : integer := 0; variable bytes_per_entry : integer := 0; variable i : integer := 0; variable j : integer := 0; variable k : integer := 0; variable l : integer := 0; variable n : integer := 0; variable m : integer := 0; variable p : integer := 0; variable lineno : integer := 0; variable buf : line; variable base : string(2 downto 1) := " "; variable byte : string(2 downto 1) := " "; variable rec_type : string(2 downto 1) := " "; variable datain : string(2 downto 1) := " "; variable addr : string(2 downto 1) := " "; variable checksum : string(2 downto 1) := " "; variable startadd: string(4 downto 1) := " "; variable ibase: integer := 0; variable ibyte: integer := 0; variable istartadd: integer := 0; variable check_sum_vec : std_logic_vector(7 downto 0) := (others => '0'); variable check_sum_vec_tmp : std_logic_vector(7 downto 0) := (others => '0'); variable booval : boolean := true; variable simultaneous_write : boolean := false; variable m_op_mode : integer := 0; file mem_data_file : text; begin -- Initialization if (not mem_init) then -- CHECK FOR OPERATION_MODE -- -- -- This is the table for encoding of op_mode -- << PORT A >> | << PORT B >> -- RD RD WR WR | RD RD WR WR -- EN ADDR EN ADDR %6 | EN ADDR EN ADDR %5 -- QP o o o o 3 | o o o o 3 -- BDP o o 2 | o o 2 -- DP o o o o 3 | 0 -- SP o o 2 | 0 -- ROM o 1 | 0 -- if (operation_mode = "QUAD_PORT") then m_op_mode := 3; elsif (operation_mode = "BIDIR_DUAL_PORT") then m_op_mode := 2; elsif (operation_mode = "DUAL_PORT") then m_op_mode := 15; elsif (operation_mode = "SINGLE_PORT") then m_op_mode := 20; elsif (operation_mode = "ROM") then m_op_mode := 25; else assert false report "Illegal OPERATION_MODE property value for ALTQPRAM!" severity error; end if; op_mode <= m_op_mode; -- Parameters value checking -- Port_A if ((width_write_a <= 0) and ((m_op_mode mod 6) > 1)) then assert false report "Illegal WIDTH_WRITE_A property value for ALTQPRAM!" severity error; end if; if ((widthad_write_a <= 0) and ((m_op_mode mod 6) > 1)) then assert false report "Illegal WIDTHAD_WRITE_A property value for ALTQPRAM!" severity error; end if; if ((width_read_a <= 0) and ((m_op_mode mod 6) > 0) and ((m_op_mode mod 6) /= 2)) then assert false report "Illegal WIDTH_READ_A property value for ALTQPRAM!" severity error; end if; if ((widthad_read_a <= 0) and ((m_op_mode mod 6) > 0) and ((m_op_mode mod 6) /= 2)) then assert false report "Illegal WIDTHAD_READ_A property value for ALTQPRAM!" severity error; end if; if ((width_read_a /= width_write_a) and ((m_op_mode mod 6) = 2)) then assert false report "WIDTH_READ_A and WIDTH_WRITE_A property values for ALTQPRAM must equal!" severity error; end if; -- Port_B if ((width_write_b <= 0) and ((m_op_mode mod 5) > 1)) then assert false report "Illegal WIDTH_WRITE_B property value for ALTQPRAM!" severity error; end if; if ((widthad_write_b <= 0) and ((m_op_mode mod 5) > 1)) then assert false report "Illegal WIDTHAD_WRITE_B property value for ALTQPRAM!" severity error; end if; if ((width_read_b <= 0) and ((m_op_mode mod 5) > 2)) then assert false report "Illegal WIDTH_READ_B property value for ALTQPRAM!" severity error; end if; if ((widthad_read_b <= 0) and ((m_op_mode mod 5) > 2)) then assert false report "Illegal WIDTHAD_READ_B property value for ALTQPRAM!" severity error; end if; if ((width_read_b /= width_write_b) and ((m_op_mode mod 5) = 2)) then assert false report "width_read_b and width_write_b property values for ALTQPRAM must equal!" severity error; end if; -- Set default values for numwords if (numwords_write_a = 0) then i_numwords_write_a <= 2**widthad_write_a; end if; if (numwords_write_b = 0) then i_numwords_write_b <= 2**widthad_write_b; end if; if (numwords_read_a = 0) then i_numwords_read_a <= 2**widthad_read_a; end if; if (numwords_read_b = 0) then i_numwords_read_b <= 2**widthad_read_b; end if; -- Check RAM port size if (((width_read_a * i_numwords_read_a) /= (width_write_a * i_numwords_write_a)) and (m_op_mode mod 6 > 0) and (m_op_mode mod 6 /= 2)) then assert false report "Inconsistant RAM size for port A of ALTQPRAM!" severity error; end if; if (m_op_mode mod 5 > 1) then if ((width_read_b * i_numwords_read_b) /= (width_write_b * i_numwords_write_b)) then assert false report "Inconsistant RAM size for port B of ALTQPRAM!" severity error; end if; if ((width_read_a * i_numwords_read_a) /= (width_read_b * i_numwords_read_b)) then assert false report "Inconsistant RAM size between port A and port B of ALTQPRAM!" severity error; end if; end if; -- Check RAM size ratio read_ratio := width_read_b / width_read_a; if (read_ratio < 1) then read_ratio := width_read_a / width_read_b; end if; write_ratio := width_write_b / width_write_a; if (write_ratio < 1) then write_ratio := width_write_a / width_write_b; end if; write_read_ratio := width_write_a / width_read_a; if (write_read_ratio < 1) then write_read_ratio := width_read_a / width_write_a; end if; if ((operation_mode /= "QUAD_PORT") or (operation_mode /= "BIDIR_DUAL_PORT")) then read_ratio := 1; write_ratio := 1; end if; if (((read_ratio /= 1) and (read_ratio /= 2) and (read_ratio /= 4) and (read_ratio /= 8) and (read_ratio /= 16)) or ((write_ratio /= 1) and (write_ratio /= 2) and (write_ratio /= 4) and (write_ratio /= 8) and (write_ratio /= 16)) or ((write_read_ratio /= 1) and (write_read_ratio /= 2) and (write_read_ratio /= 4) and (write_read_ratio /= 8) and (write_read_ratio /= 16))) then assert false report "Invalid RAM size for port A and/or port B of ALTQPRAM!" severity error; end if; -- Set memory writting behaviour if (wrcontrol_wraddress_reg_a /= "UNREGISTERED") then write_at_low_clock_a <= true; end if; if (wrcontrol_wraddress_reg_b /= "UNREGISTERED") then write_at_low_clock_b <= true; end if; -- Initialize memory contents if ((INIT_FILE = "UNUSED") or (INIT_FILE = "")) then if (m_op_mode mod 6 = 1) then -- if ROM mode assert false report "Initialization file not found!" severity error; elsif (m_op_mode mod 6 = 2) then -- if SP or BDP mode for i in mem_wr_data'low to mem_wr_data'high loop mem_wr_data(i) := (others => '0'); end loop; else -- if QP or DP mode for i in mem_rd_data'low to mem_rd_data'high loop mem_rd_data(i) := (others => '0'); end loop; end if; else file_open(mem_data_file, init_file, read_mode); while not endfile(mem_data_file) loop booval := true; readline(mem_data_file, buf); lineno := lineno + 1; check_sum_vec := (others => '0'); if (buf(buf'low) = ':') then i := 1; SHRINK_LINE(buf, i); read(l => buf, value => byte, good => booval); if not (booval) then assert false report "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format!" severity error; end if; ibyte := HEX_STR_TO_INT(byte); check_sum_vec := unsigned(check_sum_vec) + unsigned(conv_std_logic_vector(ibyte, 8)); read(l => buf, value => startadd, good => booval); if not (booval) then assert false report "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format! " severity error; end if; istartadd := HEX_STR_TO_INT(startadd); addr(2) := startadd(4); addr(1) := startadd(3); check_sum_vec := unsigned(check_sum_vec) + unsigned(conv_std_logic_vector(HEX_STR_TO_INT(addr), 8)); addr(2) := startadd(2); addr(1) := startadd(1); check_sum_vec := unsigned(check_sum_vec) + unsigned(conv_std_logic_vector(HEX_STR_TO_INT(addr), 8)); read(l=>buf, value=>rec_type, good=>booval); if not (booval) then assert false report "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format! " severity error; end if; check_sum_vec := unsigned(check_sum_vec) + unsigned(conv_std_logic_vector(HEX_STR_TO_INT(rec_type), 8)); else assert false report "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format! " severity error; end if; case rec_type is when "00"=> -- Data record i := 0; if ((m_op_mode mod 6) = 2) then -- if SP or BDP mode bytes_per_entry := (width_write_a + 7) / 8; else -- if ROM, QP or DP mode bytes_per_entry := (width_read_a + 7) / 8; end if; while (i < ibyte) loop n := (bytes_per_entry - 1) * 8; if ((m_op_mode mod 6) = 2) then mem_wr_data_word := (others => '0'); m := width_write_a - 1; else mem_rd_data_word := (others => '0'); m := width_read_a - 1; end if; for j in 1 to bytes_per_entry loop read(l => buf, value => datain, good => booval); if not (booval) then assert false report "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format! " severity error; end if; check_sum_vec := unsigned(check_sum_vec) + unsigned(conv_std_logic_vector(HEX_STR_TO_INT(datain), 8)); if ((m_op_mode mod 6) = 2) then -- if SP or BDP mode mem_wr_data_word(m downto n) := conv_std_logic_vector(HEX_STR_TO_INT(datain), m - n + 1); else -- if ROM, QP or DP mode mem_rd_data_word(m downto n) := conv_std_logic_vector(HEX_STR_TO_INT(datain), m - n + 1); end if; m := n - 1; n := n - 8; end loop; i := i + bytes_per_entry; if ((m_op_mode mod 6) = 2) then -- if SP or BDP mode mem_wr_data(ibase + istartadd) := mem_wr_data_word; else -- if ROM, QP or DP mode mem_rd_data(ibase + istartadd) := mem_rd_data_word; end if; istartadd := istartadd + 1; end loop; when "01"=> exit; when "02"=> ibase := 0; if (ibyte /= 2) then assert false report "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format for record type 02! " severity error; end if; for i in 0 to (ibyte-1) loop read(l => buf, value => base, good => booval); ibase := (ibase * 256) + HEX_STR_TO_INT(base); if not (booval) then assert false report "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal Intel Hex Format! " severity error; end if; check_sum_vec := unsigned(check_sum_vec) + unsigned(conv_std_logic_vector(HEX_STR_TO_INT(base), 8)); end loop; ibase := ibase * 16; when others => assert false report "[Line "& INT_TO_STR_RAM(lineno) & "]:Illegal record type in Intel Hex File! " severity error; end case; read(l => buf, value => checksum, good => booval); if not (booval) then assert false report "[Line "& INT_TO_STR_RAM(lineno) & "]:Checksum is missing! " severity error; end if; check_sum_vec := unsigned(not (check_sum_vec)) + 1; check_sum_vec_tmp := conv_std_logic_vector(HEX_STR_TO_INT(checksum),8); if (unsigned(check_sum_vec) /= unsigned(check_sum_vec_tmp)) then assert false report "[Line "& INT_TO_STR_RAM(lineno) & "]:Incorrect checksum!" severity error; end if; end loop; file_close(mem_data_file); end if; mem_init <= true; -- end of initialization else if (i_wren_tmp_a'event or i_wraddress_tmp_a'event or i_wraddress_lo_a'event or i_data_tmp_a'event or i_wren_lo_a'event or i_wren_tmp_b'event or i_wraddress_tmp_b'event or i_wren_lo_b'event or i_wraddress_lo_b'event or i_data_tmp_b'event) then if ((write_at_low_clock_a = true) and (write_at_low_clock_b = true)) then if ((both_clk_trigger = '1') and (inclock_a = '0') and (inclock_b = '0')) then simultaneous_write := true; else simultaneous_write := false; end if; else simultaneous_write := true; end if; if ((i_wren_tmp_a = '1') and (i_wren_tmp_b = '1') and (inclock_a = '0') and (inclock_b = '0') and (simultaneous_write = true) and ((op_mode mod 5) > 0)) then -- QP mode or BDP mode j := ieee.std_logic_unsigned.conv_integer(i_wraddress_tmp_a) * width_write_a; k := ieee.std_logic_unsigned.conv_integer(i_wraddress_tmp_b) * width_write_b; n := ieee.std_logic_unsigned.conv_integer(i_wraddress_tmp_a); if ((op_mode mod 5) = 2) then -- BDP mode for i in 0 to (width_write_b - 1) loop l := (k + i) mod width_write_a; m := (k + i) / width_write_a; if ((n = m) and (l < width_write_a)) then mem_wr_data(m)(l) := 'X'; simultaneous_write := true; else simultaneous_write := false; end if; end loop; else -- QP mode for i in 0 to (width_write_a - 1) loop for m in 0 to (width_write_b - 1) loop l := (j + i) / width_read_a; p := (j + i) mod width_read_a; if ((l = ((k + m) / width_read_a)) and (p = ((k + m) mod width_read_a))) then mem_rd_data(l)(p) := 'X'; simultaneous_write := true; else simultaneous_write := false; end if; end loop; end loop; end if; else simultaneous_write := false; end if; if not (simultaneous_write) then --write from data port a if ((i_wren_tmp_a = '1') and (inclock_a = '0') and (op_mode mod 6 > 1)) then -- not ROM mode if (op_mode mod 6 = 2) then -- SP or BDP mode j := ieee.std_logic_unsigned.conv_integer(i_wraddress_tmp_a); mem_wr_data(j) := i_data_tmp_a; else -- QP or DP mode j := ieee.std_logic_unsigned.conv_integer(i_wraddress_tmp_a) * width_write_a; for i in 0 to (width_write_a - 1) loop mem_rd_data((j+i)/width_read_a)((j+i) mod width_read_a) := i_data_tmp_a(i); end loop; end if; end if; --write from data port b if ((i_wren_tmp_b = '1') and (inclock_b = '0') and ((op_mode mod 5) > 0)) then -- QP or BDP mode j := ieee.std_logic_unsigned.conv_integer(i_wraddress_tmp_b) * width_write_b; if ((op_mode mod 5) = 2) then -- BDP mode for i in 0 to (width_write_b - 1) loop mem_wr_data((j+i)/width_write_a)((j+i) mod width_write_a) := i_data_tmp_b(i); end loop; else -- QP mode for i in 0 to (width_write_b - 1) loop mem_rd_data((j+i)/width_read_a)((j+i) mod width_read_a) := i_data_tmp_b(i); end loop; end if; end if; end if; end if; --read data to data port a if ((op_mode mod 6) = 3) then -- QP or DP mode if (i_rden_tmp_a = '1') then j := ieee.std_logic_unsigned.conv_integer(i_rdaddress_tmp_a); i_q_tmp_a <= mem_rd_data(j); end if; elsif ((op_mode mod 6) = 2) then -- BDP or SP mode j := ieee.std_logic_unsigned.conv_integer(i_wraddress_tmp_a); i_q_tmp_a <= mem_wr_data(j); elsif ((op_mode mod 6) = 1) then -- ROM mode j := ieee.std_logic_unsigned.conv_integer(i_rdaddress_tmp_a); i_q_tmp_a <= mem_rd_data(j); end if; --read data to data port b if ((op_mode mod 5) = 3) then -- QP mode if (i_rden_tmp_b = '1') then j := ieee.std_logic_unsigned.conv_integer(i_rdaddress_tmp_b) * width_read_b; for i in 0 to (width_read_b - 1) loop i_q_tmp_b(i) <= mem_rd_data((j+i)/width_read_a)((j+i) mod width_read_a); end loop; end if; elsif ((op_mode mod 5) = 2) then -- BDP mode j := ieee.std_logic_unsigned.conv_integer(i_wraddress_tmp_b) * width_write_b; for i in 0 to (width_write_b - 1) loop i_q_tmp_b(i) <= mem_wr_data((j+i)/width_write_a)((j+i) mod width_write_a); end loop; end if; end if; end process MEMORY; end behavior; -- END OF ARCHITECTURE ALTQPRAM ---START_ENTITY_HEADER--------------------------------------------------------- -- -- entity Name : parallel_add -- -- Description : Parameterized parallel adder megafunction. The data input -- is a concatenated group of input words. The size -- parameter indicates the number of 'width'-bit words. -- -- Each word is added together to generate the result output. -- Each word is left shifted according to the shift -- parameter. The shift amount is multiplied by the word -- index, with the least significant word being word 0. -- The shift for word I is (shift * I). -- -- The most significant word can be subtracted from the total -- by setting the msw_subtract parameter to 1. -- if the result width is less than is required to show the -- full result, the result output can be aligned to the MSB -- or the LSB of the internal result. when aligning to the -- MSB, the internally calculated BEST_RESULT_WIDTH is used -- to find the true MSB. -- The input data can be signed or unsigned, and the output -- can be pipelined. -- -- Limitations : Minimum data width is 1, and at least 2 words are required. -- -- Results expected: result - The sum of all inputs. -- ---END_ENTITY_HEADER----------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use IEEE.std_logic_arith.all; use work.altera_mf_components.all; -- BEGINNING OF ENTITY -- ENTITY DECLARATION entity parallel_add is -- GENERIC DECLARATION generic ( width : integer := 4; size : integer := 2; widthr : integer := 4; shift : integer := 0; msw_subtract : string := "NO"; representation : string := "UNSIGNED"; pipeline : integer := 0; result_alignment : string := "LSB"; lpm_type : string := "parallel_add" ); -- PORT DECLARATION port ( -- INPUT PORT DECLARATION data : in altera_mf_logic_2D(size - 1 downto 0, width- 1 downto 0); clock : in std_logic := '1'; aclr : in std_logic := '0'; clken : in std_logic := '1'; -- OUTPUT PORT DECLARATION result : out std_logic_vector(widthr - 1 downto 0)); end parallel_add; -- END OF ENTITY -- BEGINNING OF ARCHITECTURE architecture behaviour OF parallel_add IS -- TYPE DECLARATION TYPE pipeline_type is ARRAY (pipeline downto 0) OF std_logic_vector(widthr - 1 downto 0); -- Maximum precision required for internal calculations. -- This is a pessimistic estimate, but it is guaranteed to be sufficient. -- The +30 is there only to simplify the test generator, which occasionally asks -- for output widths far in excess of what is needed. The excess is always less than 30. constant MAX_PRECISION : integer := (width + size + shift * (size - 1) + 30); -- Bitwise Left shift -- Bitwise Left shift procedure shift_left ( val : inout std_logic_vector; num : in integer) is variable temp : std_logic_vector((val'length - 1) downto 0); begin if num /= 0 then temp := val; if (val'length > 1) then for i in temp'high downto num loop temp(i) := temp(i- num); end loop; for i in num-1 downto 0 loop temp(i) := '0'; end loop; end if; temp(0) :='0'; val := temp; end if; end shift_left; -- Bitwise right shift procedure shift_right ( val : inout std_logic_vector; num : in integer ) is variable temp : std_logic_vector(val'length-1 downto 0); begin if num /= 0 then temp := val; if (val'length > 1) then for i in 0 to temp'high - 1 loop if (i + num) <= (temp'high - 1) then temp(i) := temp(i+num); else temp(i) := '0'; end if; end loop; end if; temp(temp'high) := '0'; val := temp; end if; end shift_right; function ceil_log2 (input_num : in std_logic_vector(MAX_PRECISION - 1 downto 0)) return integer IS variable i : integer; variable try_result : std_logic_vector(MAX_PRECISION - 1 downto 0); variable ceil_log2 : integer; begin i := 0; try_result := conv_std_logic_vector(1,MAX_PRECISION); WHILE (i < MAX_PRECISION) loop shift_left(try_result,1); if (unsigned(try_result) < unsigned(input_num)) then i := i + 1; else exit; end if; end loop; ceil_log2 := i; return (ceil_log2); end ceil_log2; -- best_result_width calculation -- DEFINE CALC_PADD_WIDTHR(w, z, s) = (s == 0) ? CEIL(LOG2(z*((2^w)-1))) : -- CEIL(LOG2(((2^w)-1) * (2^(z*s)-1) / ((2^s)-1))); -- Note: The recommended value for WIDTHR parameter, -- the width of addition result, for full -- precision is: -- if shift = 0 then -- WIDTHR = CEIL(LOG2( ((2^WIDTH)-1) * SIZE)) -- -- -- if shift /= 0 then -- ((2^WIDTH)-1) * (2^(SIZE*SHIFT)-1) -- WIDTHR = CEIL(LOG2(-----------------------------------)) -- (2^SHIFT)-1 function get_best_result_width (shift, width, size : in integer) return integer is variable best_result_width : integer; variable input_num : std_logic_vector(MAX_PRECISION - 1 downto 0) := (others => '0'); variable size_vec : std_logic_vector(size downto 0) := (others => '0'); variable width_power : std_logic_vector(width downto 0) := (others => '0'); variable size_shift_power : std_logic_vector((size * shift) downto 0) := (others => '0'); variable i_denom : std_logic_vector(width + (size * shift) + 1 downto 0) := (others => '0'); variable mult_power : std_logic_vector(width + (size * shift) + 1 downto 0) := (others => '0'); variable max_width : integer; variable trailing_zero_count : integer; variable i_remain : std_logic_vector(width + (size * shift) + 1 downto 0) := (others => '0'); variable i_quotient : std_logic_vector(MAX_PRECISION - 1 downto 0) := (others => '0'); begin -- Convert size integer into std logic vector size_vec := conv_std_logic_vector(size,size+1); -- width_power = (2^WIDTH)-1) width_power := conv_std_logic_vector(1,width+1); shift_left(width_power,width+1); width_power := width_power - '1'; if (shift = 0) then input_num(size + width + 1 downto 0) := (width_power * size_vec); else -- size_shift_power = (2^(SIZE*SHIFT)-1) size_shift_power := conv_std_logic_vector(1, size * shift+1); shift_left(size_shift_power,size * shift + 1); size_shift_power := size_shift_power - '1'; -- i_denom = (2^SHIFT)-1 i_denom := conv_std_logic_vector(1, width + (size * shift) + 2); shift_left(i_denom,shift+1); i_denom := i_denom - '1'; -- mult_power := ((2^WIDTH)-1) * (2^(SIZE*SHIFT)-1) mult_power := (width_power * size_shift_power); max_width := width + (size * shift) + 1; -- perform division using long division algorithm using LPM_DIVIDE method trailing_zero_count := 0; for i in 0 to max_width loop if i_denom(i) /= '0' then trailing_zero_count := i; exit; end if; end loop; for i in 0 to max_width loop if i_denom(max_width - i) /= '0' then shift_left(i_denom,i); exit; end if; end loop; i_remain := mult_power; if (unsigned(i_remain) >= unsigned(i_denom)) then i_remain := i_remain - i_denom; i_quotient(0) := '1'; else i_quotient(0) := '0'; end if; while (i_denom(trailing_zero_count) = '0') loop shift_right(i_denom,1); shift_left(i_quotient, 1); if (unsigned(i_remain) >= unsigned(i_denom)) then i_remain := i_remain - i_denom; i_quotient(0) := '1'; else i_quotient(0) := '0'; end if; end loop; input_num := i_quotient; end if; best_result_width := ceil_log2(input_num); return (best_result_width); end get_best_result_width; constant BEST_RESULT_WIDTH : integer := get_best_result_width(shift, width, size); -- constant BEST_RESULT_WIDTH : integer := 33; -- INTERNAL SIGNAL DECLARATION signal isigned : std_logic; signal imsw_subtract : std_logic; signal imsb_align : std_logic; signal aligned_result : std_logic_vector(widthr - 1 downto 0); signal resultpipe : pipeline_type := (others => (others => '0')); -- INTERNAL INTEGER DECLARATION signal pipe_ptr : integer := 0; begin -- checking for invalid parameters MSG: process begin if (width <= 0) then ASSERT FALSE REPORT "The width parameter must be greater than 0" SEVERITY ERROR; end if; if (widthr > MAX_PRECISION) then ASSERT FALSE REPORT "Error! WIDTHR must not exceed WIDTH+SIZE+SHIFT*(SIZE-1)." SEVERITY ERROR; end if; if (size < 2) then ASSERT FALSE REPORT "Error! SIZE must be greater than 1." SEVERITY ERROR; end if; wait; end process MSG; isigned <= '0' when (representation = "UNSIGNED") else '1'; imsw_subtract <= '1' when (msw_subtract = "YES") else '0'; imsb_align <= '1' when (result_alignment = "MSB" and widthr < BEST_RESULT_WIDTH) else '0'; process (data) variable zero_padding : std_logic_vector(MAX_PRECISION - width - 1 downto 0) := (others => '0'); variable one_padding : std_logic_vector(MAX_PRECISION - width - 1 downto 0) := (others => '1'); variable tmp_result : std_logic_vector(MAX_PRECISION - 1 downto 0); variable idata_word : std_logic_vector(width - 1 downto 0); variable idata : std_logic_vector(MAX_PRECISION - 1 downto 0); variable idata_extended : std_logic_vector(MAX_PRECISION - 1 downto 0); variable ni : integer; variable nj : integer; begin tmp_result := (others => '0'); idata_extended := (others => '0'); idata_word := (others => '0'); for ni in 0 to (size - 1) loop for nj in 0 to (width - 1) loop idata_word(nj) := '0'; -- To ensure there is only '1' or '0' in idata_word to avoid any warning arithmetic message . if (data(ni, nj) = '1') then idata_word(nj) := '1'; end if; end loop; if ((isigned = '1') and (idata_word(width - 1) = '1')) then idata_extended := one_padding & idata_word; shift_left(idata_extended, (shift * ni)); else idata_extended := zero_padding & idata_word; shift_left(idata_extended,(shift * ni)); end if; if ((imsw_subtract = '1') and (ni = (size - 1))) then tmp_result := tmp_result - idata_extended; else tmp_result := tmp_result + idata_extended; end if; end loop; if (imsb_align = '1') then shift_right(tmp_result, (BEST_RESULT_WIDTH - widthr)); end if; aligned_result <= tmp_result(widthr - 1 downto 0); end process; process (clock, aclr, clken) variable ni : integer; begin if (aclr = '1') then for ni in 0 to (pipeline - 1) loop resultpipe(ni) <= (others => '0'); end loop; elsif (clock = '1') and (clock'last_value = '0') and clock'event and (clken = '1') then resultpipe(pipe_ptr) <= aligned_result; if (pipeline > 1) then pipe_ptr <= (pipe_ptr + 1) mod pipeline; end if; end if; end process; result <= resultpipe(pipe_ptr) when (pipeline > 0) else aligned_result; end behaviour; -- END OF ARCHITECTURE PARALLEL_ADD ---START_ENTITY_HEADER--------------------------------------------------------- -- -- Entity Name : scfifo -- -- Description : Single Clock FIFO -- -- Limitation : USE_EAB=OFF is not supported -- -- Results Expected: -- ---END_ENTITY_HEADER----------------------------------------------------------- -- BEGINNING OF ENTITY library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; use IEEE.std_logic_unsigned.all; use work.ALTERA_DEVICE_FAMILIES.all; -- ENTITY DECLARATION entity SCFIFO is -- GENERIC DECLARATION generic ( lpm_width : natural; lpm_widthu : natural; lpm_numwords : natural; lpm_showahead : string := "OFF"; intended_device_family : string := "NON_STRATIX"; almost_full_value : natural := 0; almost_empty_value : natural := 0; maximum_depth : natural := 0; underflow_checking : string := "ON"; overflow_checking : string := "ON"; allow_rwcycle_when_full : string := "OFF"; lpm_hint : string := "USE_EAB=ON"; use_eab : string := "ON"; add_ram_output_register : string := "OFF"; lpm_type : string := "scfifo"); -- PORT DECLARATION port ( -- INPUT PORT DECLARATION data : in std_logic_vector(lpm_width-1 downto 0); clock : in std_logic; wrreq : in std_logic; rdreq : in std_logic; aclr : in std_logic := '0'; sclr : in std_logic := '0'; -- OUTPUT PORT DECLARATION q : out std_logic_vector(lpm_width-1 downto 0); usedw : out std_logic_vector(lpm_widthu-1 downto 0); full : out std_logic; empty : out std_logic; almost_full : out std_logic; almost_empty : out std_logic); end SCFIFO; -- END OF ENTITY -- BEGINNING OF ARCHITECTURE -- ARCHITECTURE DECLARATION architecture behavior of SCFIFO is -- TYPE DECLARATION type lpm_memory is array (2**lpm_widthu-1 downto 0) of std_logic_vector(lpm_width-1 downto 0); -- CONSTANT DECLARATION constant ZEROS : std_logic_vector(lpm_width-1 downto 0) := (OTHERS => '0'); constant UNKNOWNS : std_logic_vector(lpm_width-1 downto 0) := (OTHERS => 'X'); -- SIGNAL DECLARATION signal i_count_id : integer := 0; signal i_read_id : integer := 0; signal i_full_flag : std_logic := '0'; signal i_empty_flag : std_logic := '1'; signal i_almost_full_flag : std_logic := '0'; signal i_almost_empty_flag : std_logic := '1'; signal i_tmp_q : std_logic_vector(lpm_width-1 downto 0) := ZEROS; signal i_write_id : integer := 0; signal i_write_latency1 : integer := 0; signal i_write_latency2 : integer := 0; signal i_write_latency3 : integer := 0; signal i_wrt_count : integer := 0; signal i_empty_latency1 : std_logic := '1'; signal i_empty_latency2 : std_logic := '1'; signal i_data_ready : std_logic_vector(2**lpm_widthu-1 downto 0) := (OTHERS => '0'); signal i_data_shown : std_logic_vector(2**lpm_widthu-1 downto 0) := (OTHERS => '0'); begin -- PROCESS DECLARATION process (clock, aclr) -- VARIABLE DECLARATION variable mem_data : lpm_memory := (OTHERS => ZEROS); variable tmp_data : std_logic_vector(lpm_width-1 downto 0) := ZEROS; variable write_flag : boolean := false; variable full_flag : boolean := false; variable valid_rreq : boolean := false; variable valid_wreq : boolean := false; variable max_widthu : integer := 0; variable numwords_minus_one : integer := 0; variable almost_full_minus_one : integer := 0; variable almost_empty_minus_one : integer := 0; variable need_init : boolean := true; begin if (need_init) then if ((lpm_showahead /= "ON") and (lpm_showahead /= "OFF")) then ASSERT FALSE REPORT "Illegal LPM_SHOWAHEAD property value for SCFIFO!" SEVERITY ERROR; end if; if ((underflow_checking /= "ON") and (underflow_checking /= "OFF")) then ASSERT FALSE REPORT "Illegal UNDERFLOW_CHECKING property value for SCFIFO!" SEVERITY ERROR; end if; if ((overflow_checking /= "ON") and (overflow_checking /= "OFF")) then ASSERT FALSE REPORT "Illegal OVERFLOW_CHECKING property value for SCFIFO!" SEVERITY ERROR; end if; if ((allow_rwcycle_when_full /= "ON") and (allow_rwcycle_when_full /= "OFF")) then ASSERT FALSE REPORT "Illegal ALLOW_RWCYCLE_WHEN_FULL property value for SCFIFO!" SEVERITY ERROR; end if; if (IS_VALID_FAMILY(intended_device_family) = false) then ASSERT FALSE REPORT "Illegal INTENDED_DEVICE_FAMILY for SCFIFO!" SEVERITY ERROR; end if; if ((add_ram_output_register /= "ON") and (add_ram_output_register /= "OFF")) then ASSERT FALSE REPORT "Error! ADD_RAM_OUTPUT_REGISTER must be ON or OFF." SEVERITY ERROR; end if; for i in 0 to (lpm_widthu - 1) loop if (IS_FAMILY_STRATIX(intended_device_family) or IS_FAMILY_STRATIXGX(intended_device_family) or IS_FAMILY_STRATIXII(intended_device_family) or IS_FAMILY_ACEX2K(intended_device_family)) then if (add_ram_output_register = "ON") then mem_data(i) := ZEROS; else mem_data(i) := UNKNOWNS; end if; else mem_data(i) := ZEROS; end if; end loop; if (IS_FAMILY_STRATIX(intended_device_family) or IS_FAMILY_STRATIXGX(intended_device_family) or IS_FAMILY_STRATIXII(intended_device_family) or IS_FAMILY_ACEX2K(intended_device_family)) then if (add_ram_output_register = "ON") then i_tmp_q <= ZEROS; else i_tmp_q <= UNKNOWNS; end if; else i_tmp_q <= ZEROS; end if; if (almost_full_value = 0) then i_almost_full_flag <= '1'; else i_almost_full_flag <= '0'; end if; if (almost_empty_value = 0) then i_almost_empty_flag <= '0'; else i_almost_empty_flag <= '1'; end if; max_widthu := (2 ** lpm_widthu) - 1; numwords_minus_one := lpm_numwords - 1; almost_full_minus_one := almost_full_value - 1; almost_empty_minus_one := almost_empty_value - 1; i_write_latency1 <= max_widthu+1; i_write_latency2 <= max_widthu+1; i_write_latency3 <= max_widthu+1; need_init := false; end if; if (aclr = '1') then full_flag := false; if (not (IS_FAMILY_STRATIX(intended_device_family) or IS_FAMILY_STRATIXGX(intended_device_family) or IS_FAMILY_STRATIXII(intended_device_family) or IS_FAMILY_ACEX2K(intended_device_family))) then if (lpm_showahead = "ON") then i_tmp_q <= mem_data(0); i_data_shown(0) <= '1'; else i_tmp_q <= ZEROS; end if; end if; end if; if (clock'event and (clock = '1') and ((aclr = '0') or (IS_FAMILY_STRATIX(intended_device_family) or IS_FAMILY_STRATIXGX(intended_device_family) or IS_FAMILY_STRATIXII(intended_device_family) or IS_FAMILY_ACEX2K(intended_device_family)))) then valid_rreq := rdreq = '1' and ((i_empty_flag = '0') or (underflow_checking = "OFF")); valid_wreq := wrreq = '1' and ((i_full_flag = '0') or (overflow_checking = "OFF") or ((rdreq = '1') and (allow_rwcycle_when_full = "ON"))); if ((sclr = '1') or (aclr = '1')) then if (sclr = '1') then if ((lpm_showahead = "ON") or (IS_FAMILY_STRATIX(intended_device_family) or IS_FAMILY_STRATIXGX(intended_device_family) or IS_FAMILY_STRATIXII(intended_device_family) or IS_FAMILY_ACEX2K(intended_device_family))) then if (not(add_ram_output_register = "ON" and lpm_showahead = "ON")) then i_tmp_q <= mem_data(0); end if; else i_tmp_q <= mem_data(i_read_id); end if; i_read_id <= 0; i_count_id <= 0; i_write_id <= 0; i_full_flag <= '0'; i_empty_flag <= '1'; i_empty_latency1 <= '1'; i_empty_latency2 <= '1'; if (almost_full_value > 0) then i_almost_full_flag <= '0'; end if; if (almost_empty_value > 0) then i_almost_empty_flag <= '1'; end if; full_flag := false; end if; else -- WRITE operation only if (valid_wreq) then tmp_data := data; write_flag := true; if (not(add_ram_output_register = "ON" and lpm_showahead = "ON")) then i_empty_flag <= '0'; else i_empty_latency1 <= '0'; end if; i_wrt_count <= i_wrt_count + 1; if (not valid_rreq) then if (i_count_id >= max_widthu) then i_count_id <= 0; else i_count_id <= i_count_id + 1; end if; else if (allow_rwcycle_when_full = "OFF") then i_full_flag <= '0'; end if; end if; if (not(add_ram_output_register = "ON" and lpm_showahead = "ON")) then if (not valid_rreq) then if ((i_count_id = numwords_minus_one) and (i_empty_flag = '0')) then i_full_flag <= '1'; full_flag := true; end if; end if; else if (not valid_rreq) then if (i_count_id = numwords_minus_one) then i_full_flag <= '1'; full_flag := true; end if; end if; end if; if (lpm_showahead = "ON") then if (add_ram_output_register = "ON" and lpm_showahead = "ON") then i_write_latency1 <= i_write_id; if (i_write_id <= max_widthu) then i_data_shown(i_write_id) <= '1'; i_data_ready(i_write_id) <= 'X'; end if; else i_tmp_q <= mem_data(i_read_id); end if; end if; end if; -- READ operation only if (valid_rreq) then i_wrt_count <= i_wrt_count - 1; if (not valid_wreq) then i_full_flag <= '0'; full_flag := false; if (i_count_id <= 0) then i_count_id <= max_widthu; else i_count_id <= i_count_id - 1; end if; end if; if (add_ram_output_register = "ON" and lpm_showahead = "ON") then if (i_data_shown(i_write_latency2) = '0') then i_empty_flag <= '1'; else if (i_wrt_count = 0) then i_empty_flag <= '1'; end if; end if; else if (not(valid_wreq)) then if (i_count_id = 1 and i_full_flag = '0') then i_empty_flag <= '1'; end if; end if; end if; if (i_read_id >= max_widthu) then if (lpm_showahead = "ON") then if (add_ram_output_register = "ON" and lpm_showahead = "ON") then if ((i_write_latency2 = ZEROS) or (i_data_ready(0) = '1')) then if (i_data_shown(0) = '1') then i_tmp_q <= mem_data(0); i_data_shown(0) <= '0'; i_data_ready(0) <= '0'; end if; end if; else i_tmp_q <= mem_data(0); end if; else i_tmp_q <= mem_data(i_read_id); end if; i_read_id <= 0; else if (lpm_showahead = "ON") then if (add_ram_output_register = "ON" and lpm_showahead = "ON") then if ((i_write_latency2 = i_read_id+1) or (i_data_ready(i_read_id+1) = '1')) then if (i_data_shown(i_read_id+1) = '1') then i_tmp_q <= mem_data(i_read_id + 1); i_data_shown(i_read_id+1) <= '0'; i_data_ready(i_read_id+1) <= '0'; end if; end if; else i_tmp_q <= mem_data(i_read_id + 1); end if; else i_tmp_q <= mem_data(i_read_id); end if; i_read_id <= i_read_id + 1; end if; end if; if (almost_full_value = 0) then i_almost_full_flag <= '1'; elsif (lpm_numwords = almost_full_value) then if (full_flag) then i_almost_full_flag <= '1'; else i_almost_full_flag <= '0'; end if; else if (i_almost_full_flag = '1') then if ((i_count_id = almost_full_value) and (wrreq = '0') and (rdreq = '1')) then i_almost_full_flag <= '0'; end if; else if ((almost_full_value = 1) and (i_count_id = 0) and (wrreq = '1')) then i_almost_full_flag <= '1'; elsif ((almost_full_value > 1) and (i_count_id = almost_full_minus_one) and (wrreq = '1') and (rdreq = '0')) then i_almost_full_flag <= '1'; end if; end if; end if; if (almost_empty_value = 0) then i_almost_empty_flag <= '0'; elsif (lpm_numwords = almost_empty_value) then if (full_flag) then i_almost_empty_flag <= '0'; else i_almost_empty_flag <= '1'; end if; else if (i_almost_empty_flag = '1') then if ((almost_empty_value = 1) and (i_count_id = 0) and (wrreq = '1')) then i_almost_empty_flag <= '0'; elsif ((almost_empty_value > 1) and (i_count_id = almost_empty_minus_one) and (wrreq = '1') and (rdreq = '0')) then i_almost_empty_flag <= '0'; end if; else if ((i_count_id = almost_empty_value) and (wrreq = '0') and (rdreq = '1')) then i_almost_empty_flag <= '1'; end if; end if; end if; end if; if ((clock'event and (clock = '1')) and (IS_FAMILY_STRATIX(intended_device_family) or IS_FAMILY_STRATIXGX(intended_device_family) or IS_FAMILY_STRATIXII(intended_device_family) or IS_FAMILY_ACEX2K(intended_device_family))) then if (lpm_showahead = "ON" and add_ram_output_register = "ON") then i_write_latency2 <= i_write_latency1; i_write_latency3 <= i_write_latency2; if (i_write_latency3 /= i_write_latency2) then if (i_write_latency2 <= max_widthu) then i_data_ready(i_write_latency2) <= '1'; end if; end if; i_empty_latency2 <= i_empty_latency1; if ((aclr = '1') or (sclr = '1')) then i_write_latency1 <= max_widthu+1; i_write_latency2 <= max_widthu+1; end if; if (i_write_latency2 <= max_widthu) then if (i_data_shown(i_write_latency2) = '1') then if ((i_read_id = i_write_latency2) or (aclr = '1') or (sclr = '1')) then if (not (aclr = '1') and (not(sclr = '1'))) then i_tmp_q <= mem_data(i_write_latency2); i_data_shown(i_write_latency2) <= '0'; i_data_ready(i_write_latency2) <= '0'; if (not valid_rreq) then i_empty_flag <= i_empty_latency2; end if; else if ((i_count_id /= 0) or (i_full_flag /= '0')) then if ((rdreq /= '0') or (i_empty_flag /= '0')) then if (rdreq = '1') then if (i_read_id >= ((2**lpm_widthu) - 1)) then if (i_data_ready(0) = '1') then i_tmp_q <= mem_data(0); i_data_shown(0) <= '0'; i_data_ready(0) <= '0'; else i_tmp_q <= mem_data(i_write_latency2); i_data_shown(i_write_latency2) <= '0'; i_data_ready(i_write_latency2) <= '0'; end if; else i_tmp_q <= mem_data(i_write_latency2); i_data_shown(i_write_latency2) <= '0'; i_data_ready(i_write_latency2) <= '0'; end if; else i_tmp_q <= mem_data(i_read_id); i_data_shown(i_read_id) <= '0'; i_data_ready(i_read_id) <= '0'; end if; end if; end if; end if; end if; end if; end if; end if; end if; elsif (clock'event and (clock = '0')) then if (write_flag) then write_flag := false; mem_data(i_write_id) := tmp_data; if ((aclr = '1') or (sclr = '1') or (i_write_id >= max_widthu)) then i_write_id <= 0; else i_write_id <= i_write_id + 1; end if; end if; if (not (IS_FAMILY_STRATIX(intended_device_family) or IS_FAMILY_STRATIXGX(intended_device_family) or IS_FAMILY_STRATIXII(intended_device_family) or IS_FAMILY_ACEX2K(intended_device_family))) then if (lpm_showahead = "ON") then i_tmp_q <= mem_data(i_read_id); end if; end if; end if; if (aclr = '1') then i_full_flag <= '0'; i_empty_flag <= '1'; if (almost_full_value > 0) then i_almost_full_flag <= '0'; end if; if (almost_empty_value > 0) then i_almost_empty_flag <= '1'; end if; i_read_id <= 0; i_write_id <= 0; i_count_id <= 0; end if; end process; q <= i_tmp_q; full <= i_full_flag; empty <= i_empty_flag; almost_full <= i_almost_full_flag; almost_empty <= i_almost_empty_flag; usedw <= conv_std_logic_vector(i_count_id, lpm_widthu); end behavior; -- scfifo -- END OF ARCHITECTURE ---START_ENTITY_HEADER--------------------------------------------------------- -- -- Entity Name : dcfifo_dffpipe -- -- Description : Dual Clocks FIFO -- -- Limitation : -- -- Results Expected: -- ---END_ENTITY_HEADER----------------------------------------------------------- -- BEGINNING OF ENTITY library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; use IEEE.std_logic_unsigned.all; -- ENTITY DECLARATION entity DCFIFO_DFFPIPE is -- GENERIC DECLARATION generic ( lpm_delay : natural; lpm_width : natural); -- PORT DECLARATION port ( -- INPUT PORT DECLARATION d : in std_logic_vector (lpm_width-1 downto 0); clock : in std_logic; aclr : in std_logic := '0'; -- OUTPUT PORT DECLARATION q : out std_logic_vector (lpm_width-1 downto 0)); end DCFIFO_DFFPIPE; -- END OF ENTITY -- BEGINNING OF ARCHITECTURE -- ARCHITECTURE DECLARATION architecture behavior of DCFIFO_DFFPIPE is -- TYPE DECLARATION type DELAYPIPE is array (lpm_delay downto 0) of std_logic_vector (lpm_width-1 downto 0); -- CONSTANT DECLARATION constant ZEROS : std_logic_vector(lpm_width-1 downto 0) := (OTHERS => '0'); begin -- PROCESS DECLARATION process (clock, aclr, d) ------ VARIABLE DECLARATION variable intpipe : DELAYPIPE := (OTHERS => ZEROS); variable delay : integer := lpm_delay - 1; variable need_init : boolean := true; begin if (lpm_delay = 0) then if ((aclr = '1') or need_init) then q <= ZEROS; need_init := false; else q <= d; end if; else if ((aclr = '1') or need_init) then for i in lpm_delay downto 0 loop intpipe(i) := ZEROS; end loop; need_init := false; q <= ZEROS; end if; if (clock'event and (clock = '1') and (NOW > 0 ns)) then if (delay > 0) then for i in delay downto 1 loop intpipe(i) := intpipe(i-1); end loop; end if; intpipe(0) := d; q <= intpipe(delay); end if; end if; -- (lpm_delay = 0) end process; -- clock, aclr, d events end behavior; -- dcfifo_dffpipe -- END OF ARCHITECTURE ---START_ENTITY_HEADER--------------------------------------------------------- -- -- Entity Name : dcfifo_fefifo -- -- Description : Dual Clocks FIFO -- -- Limitation : -- -- Results Expected: -- ---END_ENTITY_HEADER----------------------------------------------------------- -- BEGINNING OF ENTITY library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; use IEEE.std_logic_unsigned.all; -- ENTITY DECLARATION entity DCFIFO_FEFIFO is -- GENERIC DECLARATION generic ( lpm_widthad : natural; lpm_numwords : natural; underflow_checking : string := "ON"; overflow_checking : string := "ON"; lpm_mode : string); -- PORT DECLARATION port ( -- INPUT PORT DECLARATION usedw_in : in std_logic_vector(lpm_widthad-1 downto 0); wreq : in std_logic := 'Z'; rreq : in std_logic := 'Z'; clock : in std_logic; aclr : in std_logic := '0'; -- OUTPUT PORT DECLARATION empty : out std_logic; full : out std_logic); end DCFIFO_FEFIFO; -- END OF ENTITY -- BEGINNING OF ARCHITECTURE -- ARCHITECTURE DECLARATION architecture behavior of DCFIFO_FEFIFO is -- SIGNAL DECLARATION signal i_empty : std_logic := '1'; signal i_full : std_logic := '0'; begin -- PROCESS DECLARATION process (clock, aclr) ------ VARIABLE DECLARATION variable sm_empty : std_logic_vector(1 downto 0) := "00"; variable lrreq : std_logic := '0'; variable almost_full : integer := 0; variable usedw_is_1 : boolean := false; variable need_init : boolean := true; begin if (need_init) then if ((lpm_mode /= "READ") and (lpm_mode /= "WRITE")) then ASSERT FALSE REPORT "Error! LPM_MODE must be READ or WRITE." SEVERITY ERROR; end if; if ((underflow_checking /= "ON") and (underflow_checking /= "OFF")) then ASSERT FALSE REPORT "Error! UNDERFLOW_CHECKING must be ON or OFF." SEVERITY ERROR; end if; if ((overflow_checking /= "ON") and (overflow_checking /= "OFF")) then ASSERT FALSE REPORT "Error! OVERFLOW_CHECKING must be ON or OFF." SEVERITY ERROR; end if; if (lpm_numwords >= 3) then almost_full := lpm_numwords - 3; else almost_full := 0; end if; need_init := false; end if; -- need_init if (aclr'event and (aclr = '1')) then sm_empty := "00"; lrreq := '0'; i_empty <= '1'; i_full <= '0'; end if; -- aclr event if (clock'event and (clock = '1') and (aclr = '0') and (NOW > 0 ns)) then if (lpm_mode = "READ") then case sm_empty is -- state_empty when "00" => if (usedw_in /= 0) then sm_empty := "01"; end if; -- state_non_empty when "01" => if (lpm_widthad > 1) then usedw_is_1 := ((usedw_in = 1) and (lrreq = '0')) or ((usedw_in = 2) and (lrreq = '1')); else usedw_is_1 := (usedw_in = 1) and (lrreq = '0'); end if; if ((rreq = '1') and usedw_is_1) then sm_empty := "10"; end if; -- state_emptywait when "10" => if (usedw_in > 1) then sm_empty := "01"; else sm_empty := "00"; end if; when others => ASSERT FALSE REPORT "Error! Invalid sm_empty state in read mode." SEVERITY ERROR; end case; elsif (lpm_mode = "WRITE") then case sm_empty is -- state_empty when "00" => if (wreq = '1') then sm_empty := "01"; end if; -- state_one when "01" => if (wreq = '0') then sm_empty := "11"; end if; -- state_non_empty when "11" => if (wreq = '1') then sm_empty := "01"; elsif (usedw_in = 0) then sm_empty := "00"; end if; when others => ASSERT FALSE REPORT "Error! Invalid sm_empty state in write mode." SEVERITY ERROR; end case; end if; i_empty <= not sm_empty(0); if ((aclr = '0') and (usedw_in >= almost_full) and (NOW > 0 ns)) then i_full <= '1'; else i_full <= '0'; end if; if (underflow_checking = "OFF") then lrreq := rreq; else lrreq := rreq and not i_empty; end if; end if; -- clock event end process; -- clock, aclr events empty <= i_empty; full <= i_full; end behavior; -- dcfifo_fefifo -- END OF ARCHITECTURE ---START_ENTITY_HEADER--------------------------------------------------------- -- -- Entity Name : dcfifo_async -- -- Description : Asynchoronous Dual Clocks FIFO -- -- Limitation : -- -- Results Expected: -- ---END_ENTITY_HEADER----------------------------------------------------------- -- BEGINNING OF ENTITY library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; use IEEE.std_logic_unsigned.all; use work.ALTERA_DEVICE_FAMILIES.all; -- ENTITY DECLARATION entity DCFIFO_ASYNC is -- GENERIC DECLARATION generic ( lpm_width : natural; lpm_widthu : natural; lpm_numwords : natural; delay_rdusedw : natural := 1; delay_wrusedw : natural := 1; rdsync_delaypipe : natural := 3; wrsync_delaypipe : natural := 3; intended_device_family : string := "NON_STRATIX"; lpm_showahead : string := "OFF"; underflow_checking : string := "ON"; overflow_checking : string := "ON"; use_eab : string := "ON"; add_ram_output_register : string := "OFF"; clocks_are_synchronized : string := "FALSE"; lpm_hint : string := "USE_EAB=ON"); -- PORT DECLARATION port ( -- INPUT PORT DECLARATION data : in std_logic_vector(lpm_width-1 downto 0); rdclk : in std_logic; wrclk : in std_logic; rdreq : in std_logic; wrreq : in std_logic; aclr : in std_logic := '0'; -- OUTPUT PORT DECLARATION rdempty : out std_logic; wrempty : out std_logic; rdfull : out std_logic; wrfull : out std_logic; rdusedw : out std_logic_vector(lpm_widthu-1 downto 0); wrusedw : out std_logic_vector(lpm_widthu-1 downto 0); q : out std_logic_vector(lpm_width-1 downto 0)); end DCFIFO_ASYNC; -- END OF ENTITY -- BEGINNING OF ARCHITECTURE -- ARCHITECTURE DECLARATION architecture behavior of DCFIFO_ASYNC is -- TYPE DECLARATION type LPM_MEMORY is array (2**lpm_widthu-1 downto 0) of std_logic_vector(lpm_width-1 downto 0); -- CONSTANT DECLARATION constant ZEROS : std_logic_vector(lpm_width-1 downto 0) := (OTHERS => '0'); constant ZEROU : std_logic_vector(lpm_widthu-1 downto 0) := (OTHERS => '0'); constant GRAY_DELAYPIPE : integer := 1; constant WRUSEDW_DELAYPIPE : integer := 1; -- delayed usedw to compute empty/full constant RDUSEDW_DELAYPIPE : integer := 1; -- delayed usedw to compute empty/full -- SIGNAL DECLARATION signal i_data_tmp : std_logic_vector(lpm_width-1 downto 0); signal i_rdptr : std_logic_vector(lpm_widthu-1 downto 0) := (OTHERS => '0'); signal i_wrptr : std_logic_vector(lpm_widthu-1 downto 0) := (OTHERS => '0'); signal i_wrptr_tmp : std_logic_vector(lpm_widthu-1 downto 0) := (OTHERS => '0'); signal i_rdptrrg : std_logic_vector(lpm_widthu-1 downto 0) := (OTHERS => '0'); signal i_wrdelaycycle : std_logic_vector(lpm_widthu-1 downto 0) := (OTHERS => '0'); signal i_rden : std_logic := '0'; signal i_wren : std_logic := '0'; signal i_rdenclock : std_logic := '0'; signal i_wren_tmp : std_logic := '0'; signal i_rdempty : std_logic := '1'; signal i_wrempty : std_logic := '1'; signal i_rdfull : std_logic := '0'; signal i_wrfull : std_logic := '0'; signal i_rdusedw : std_logic_vector(lpm_widthu-1 downto 0) := (OTHERS => '0'); signal i_wrusedw : std_logic_vector(lpm_widthu-1 downto 0) := (OTHERS => '0'); signal i_ws_nbrp : std_logic_vector(lpm_widthu-1 downto 0) := (OTHERS => '0'); signal i_rs_nbwp : std_logic_vector(lpm_widthu-1 downto 0) := (OTHERS => '0'); signal i_ws_dbrp : std_logic_vector(lpm_widthu-1 downto 0) := (OTHERS => '0'); signal i_rs_dbwp : std_logic_vector(lpm_widthu-1 downto 0) := (OTHERS => '0'); signal i_wr_udwn : std_logic_vector(lpm_widthu-1 downto 0) := (OTHERS => '0'); signal i_rd_udwn : std_logic_vector(lpm_widthu-1 downto 0) := (OTHERS => '0'); signal i_wr_dbuw : std_logic_vector(lpm_widthu-1 downto 0) := (OTHERS => '0'); signal i_rd_dbuw : std_logic_vector(lpm_widthu-1 downto 0) := (OTHERS => '0'); signal i_q_tmp : std_logic_vector(lpm_width-1 downto 0) := (OTHERS => '0'); -- COMPONENT DECLARATION component DCFIFO_FEFIFO generic ( lpm_widthad : natural; lpm_numwords : natural; underflow_checking : string := "ON"; overflow_checking : string := "ON"; lpm_mode : string); port ( usedw_in : in std_logic_vector(lpm_widthad-1 downto 0); wreq : in std_logic := 'Z'; rreq : in std_logic := 'Z'; clock : in std_logic; aclr : in std_logic := '0'; empty : out std_logic; full : out std_logic); end component; component DCFIFO_DFFPIPE generic ( lpm_delay : natural; lpm_width : natural); port ( d : in std_logic_vector(lpm_width-1 downto 0); clock : in std_logic; aclr : in std_logic := '0'; q : out std_logic_vector(lpm_width-1 downto 0)); end component; begin -- COMPONENT ASSIGNMENTS -- Delays & DFF Pipes DP_RDPTR_D: DCFIFO_DFFPIPE generic map ( lpm_delay => 0, lpm_width => lpm_widthu) port map ( d => i_rdptr, clock => i_rdenclock, aclr => aclr, q => i_rdptrrg); DP_WRPTR_D: DCFIFO_DFFPIPE generic map ( lpm_delay => 1, lpm_width => lpm_widthu) port map ( d => i_wrptr, clock => wrclk, aclr => aclr, q => i_wrdelaycycle); DP_WS_NBRP: DCFIFO_DFFPIPE generic map ( lpm_delay => WRSYNC_DELAYPIPE, lpm_width => lpm_widthu) port map ( d => i_rdptrrg, clock => wrclk, aclr => aclr, q => i_ws_nbrp); DP_RS_NBWP: DCFIFO_DFFPIPE generic map ( lpm_delay => RDSYNC_DELAYPIPE, lpm_width => lpm_widthu) port map ( d => i_wrdelaycycle, clock => rdclk, aclr => aclr, q => i_rs_nbwp); DP_WS_DBRP: DCFIFO_DFFPIPE generic map ( lpm_delay => GRAY_DELAYPIPE, lpm_width => lpm_widthu) port map ( d => i_ws_nbrp, clock => wrclk, aclr => aclr, q => i_ws_dbrp); DP_RS_DBWP: DCFIFO_DFFPIPE generic map ( lpm_delay => GRAY_DELAYPIPE, lpm_width => lpm_widthu) port map ( d => i_rs_nbwp, clock => rdclk, aclr => aclr, q => i_rs_dbwp); DP_WR_USEDW: DCFIFO_DFFPIPE generic map ( lpm_delay => DELAY_WRUSEDW, lpm_width => lpm_widthu) port map ( d => i_wr_udwn, clock => wrclk, aclr => aclr, q => i_wrusedw); DP_RD_USEDW: DCFIFO_DFFPIPE generic map ( lpm_delay => DELAY_RDUSEDW, lpm_width => lpm_widthu) port map ( d => i_rd_udwn, clock => rdclk, aclr => aclr, q => i_rdusedw); DP_WR_DBUW: DCFIFO_DFFPIPE generic map ( lpm_delay => WRUSEDW_DELAYPIPE, lpm_width => lpm_widthu) port map ( d => i_wr_udwn, clock => wrclk, aclr => aclr, q => i_wr_dbuw); DP_RD_DBUW: DCFIFO_DFFPIPE generic map ( lpm_delay => RDUSEDW_DELAYPIPE, lpm_width => lpm_widthu) port map ( d => i_rd_udwn, clock => rdclk, aclr => aclr, q => i_rd_dbuw); -- Empty/Full WR_FE: DCFIFO_FEFIFO generic map ( lpm_widthad => lpm_widthu, lpm_numwords => lpm_numwords, underflow_checking => UNDERFLOW_CHECKING, overflow_checking => OVERFLOW_CHECKING, lpm_mode => "WRITE") port map ( usedw_in => i_wr_dbuw, wreq => wrreq, clock => wrclk, aclr => aclr, empty => i_wrempty, full => i_wrfull); RD_FE: DCFIFO_FEFIFO generic map ( lpm_widthad => lpm_widthu, lpm_numwords => lpm_numwords, underflow_checking => underflow_checking, overflow_checking => overflow_checking, lpm_mode => "READ") port map ( usedw_in => i_rd_dbuw, rreq => rdreq, clock => rdclk, aclr => aclr, empty => i_rdempty, full => i_rdfull); -- PROCESS DECLARATION -- FIFOram process (wrclk, rdclk, aclr) ------ VARIABLE DECLARATION variable max_widthu : integer := 0; variable max_widthu_minus_one : integer := 0; variable mem_data : LPM_MEMORY := (OTHERS => ZEROS); variable need_init : boolean := true; begin if (need_init) then if ((lpm_showahead /= "ON") and (lpm_showahead /= "OFF")) then ASSERT FALSE REPORT "Error! LPM_SHOWAHEAD must be ON or OFF." SEVERITY ERROR; end if; if ((underflow_checking /= "ON") and (underflow_checking /= "OFF")) then ASSERT FALSE REPORT "Error! UNDERFLOW_CHECKING must be ON or OFF." SEVERITY ERROR; end if; if ((overflow_checking /= "ON") and (overflow_checking /= "OFF")) then ASSERT FALSE REPORT "Error! OVERFLOW_CHECKING must be ON or OFF." SEVERITY ERROR; end if; if ((use_eab /= "ON") and (use_eab /= "OFF")) then ASSERT FALSE REPORT "Error! USE_EAB must be ON or OFF." SEVERITY ERROR; end if; if ((add_ram_output_register /= "ON") and (add_ram_output_register /= "OFF")) then ASSERT FALSE REPORT "Error! ADD_RAM_OUTPUT_REGISTER must be ON or OFF." SEVERITY ERROR; end if; if (IS_VALID_FAMILY(intended_device_family) = false) then ASSERT FALSE REPORT "Error! Illegal INTENDED_DEVICE_FAMILY." SEVERITY ERROR; end if; max_widthu := 2 ** lpm_widthu; max_widthu_minus_one := (2 ** lpm_widthu) - 1; for i in lpm_numwords - 1 downto 0 loop mem_data(i) := ZEROS; end loop; need_init := false; end if; -- need_init if (aclr'event and (aclr = '1')) then i_rdptr <= ZEROU; i_wrptr <= ZEROU; if (not (IS_FAMILY_STRATIX(intended_device_family) or IS_FAMILY_STRATIXGX(intended_device_family) or IS_FAMILY_ACEX2K(intended_device_family)) or (add_ram_output_register = "ON") or (use_eab = "OFF")) then if (lpm_showahead = "ON") then i_q_tmp <= mem_data(0); else i_q_tmp <= ZEROS; end if; end if; end if; -- aclr event if (wrclk'event) then if ((aclr = '1') and (not (IS_FAMILY_STRATIX(intended_device_family) or IS_FAMILY_STRATIXGX(intended_device_family) or IS_FAMILY_ACEX2K(intended_device_family)) or (add_ram_output_register = "ON") or (use_eab = "OFF"))) then i_data_tmp <= ZEROS; i_wrptr_tmp <= ZEROU; i_wren_tmp <= '0'; elsif ((wrclk = '1') and (NOW > 0 ns)) then i_data_tmp <= data; i_wrptr_tmp <= i_wrptr; i_wren_tmp <= i_wren; if (i_wren = '1') then if ((aclr = '0') and (i_wrptr < max_widthu_minus_one)) then i_wrptr <= i_wrptr + 1; else i_wrptr <= ZEROU; end if; if (use_eab = "OFF") then mem_data(CONV_INTEGER(i_wrptr) mod max_widthu) := data; if (lpm_showahead = "ON") then i_q_tmp <= mem_data(CONV_INTEGER(i_rdptr) mod max_widthu); end if; end if; end if; end if; if (((wrclk = '0') and (use_eab = "ON")) and (NOW > 0 ns)) then if (i_wren_tmp = '1') then mem_data(CONV_INTEGER(i_wrptr_tmp) mod max_widthu) := i_data_tmp; end if; if (lpm_showahead = "ON") then i_q_tmp <= mem_data(CONV_INTEGER(i_rdptr) mod max_widthu); end if; end if; end if; -- wrclk event if (rdclk'event) then if ((aclr = '1') and (not (IS_FAMILY_STRATIX(intended_device_family) or IS_FAMILY_STRATIXGX(intended_device_family) or IS_FAMILY_ACEX2K(intended_device_family)) or (add_ram_output_register = "ON") or (use_eab = "OFF"))) then if (lpm_showahead = "ON") then i_q_tmp <= mem_data(0); else i_q_tmp <= ZEROS; end if; elsif ((rdclk = '1') and (i_rden = '1') and (NOW > 0 ns)) then if ((aclr = '0') and (i_rdptr < max_widthu_minus_one)) then i_rdptr <= i_rdptr + 1; else i_rdptr <= ZEROU; end if; if (lpm_showahead = "ON") then i_q_tmp <= mem_data(CONV_INTEGER(i_rdptr + 1) mod max_widthu); else i_q_tmp <= mem_data(CONV_INTEGER(i_rdptr) mod max_widthu); end if; end if; end if; -- rdclk event end process; -- aclr, wrclk, rdclk events i_rden <= rdreq when underflow_checking = "OFF" else rdreq and not i_rdempty; i_wren <= wrreq when overflow_checking = "OFF" else wrreq and not i_wrfull; -- Delays & DFF Pipes process (rdclk) begin if (rdclk = '0') then i_rdenclock <= '0'; elsif ((rdclk = '1') and (i_rden = '1')) then i_rdenclock <= '1'; end if; end process; -- rdclk event process (i_wrptr, i_ws_dbrp) begin if (NOW > 0 ns) then i_wr_udwn <= i_wrptr - i_ws_dbrp; end if; end process; -- i_wrptr, i_ws_dbrp events process (i_rdptr, i_rs_dbwp) begin if (NOW > 0 ns) then i_rd_udwn <= i_rs_dbwp - i_rdptr; end if; end process; -- i_rdptr, i_rs_dbwp events -- Outputs rdempty <= i_rdempty; rdfull <= i_rdfull; wrempty <= i_wrempty; wrfull <= i_wrfull; rdusedw <= i_rdusedw; wrusedw <= i_wrusedw; q <= i_q_tmp; end behavior; -- dcfifo_async -- END OF ARCHITECTURE ---START_ENTITY_HEADER--------------------------------------------------------- -- -- Entity Name : dcfifo_sync -- -- Description : Synchronous Dual Clocks FIFO -- -- Limitation : -- -- Results Expected: -- ---END_ENTITY_HEADER----------------------------------------------------------- -- BEGINNING OF ENTITY library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; use IEEE.std_logic_unsigned.all; use work.ALTERA_DEVICE_FAMILIES.all; -- ENTITY DECLARATION entity DCFIFO_SYNC is -- GENERIC DECLARATION generic ( lpm_width : natural; lpm_widthu : natural; lpm_numwords : natural; intended_device_family : string := "NON_STRATIX"; lpm_showahead : string := "OFF"; underflow_checking : string := "ON"; overflow_checking : string := "ON"; use_eab : string := "ON"; add_ram_output_register : string := "OFF"); -- PORT DECLARATION port ( -- INPUT PORT DECLARATION data : in std_logic_vector(lpm_width-1 downto 0); rdclk : in std_logic; wrclk : in std_logic; aclr : in std_logic := '0'; rdreq : in std_logic; wrreq : in std_logic; -- OUTPUT PORT DECLARATION rdfull : out std_logic; wrfull : out std_logic; rdempty : out std_logic; wrempty : out std_logic; rdusedw : out std_logic_vector(lpm_widthu-1 downto 0); wrusedw : out std_logic_vector(lpm_widthu-1 downto 0); q : out std_logic_vector(lpm_width-1 downto 0)); end DCFIFO_SYNC; -- END OF ENTITY -- BEGINNING OF ARCHITECTURE -- ARCHITECTURE DECLARATION architecture behavior of DCFIFO_SYNC is -- TYPE DECLARATION type LPM_MEMORY is array (2**lpm_widthu-1 downto 0) of std_logic_vector(lpm_width-1 downto 0); -- CONSTANT DECLARATION constant ZEROS : std_logic_vector(lpm_width-1 downto 0) := (OTHERS => '0'); constant ZEROU : std_logic_vector(lpm_widthu downto 0) := (OTHERS => '0'); -- SIGNAL DECLARATION signal i_data_tmp : std_logic_vector(lpm_width-1 downto 0); signal i_rdptr : std_logic_vector(lpm_widthu downto 0) := (OTHERS => '0'); signal i_wrptr : std_logic_vector(lpm_widthu downto 0) := (OTHERS => '0'); signal i_wrptr_tmp : std_logic_vector(lpm_widthu downto 0) := (OTHERS => '0'); signal i_rdptr_s : std_logic_vector(lpm_widthu downto 0) := (OTHERS => '0'); signal i_wrptr_r : std_logic_vector(lpm_widthu downto 0) := (OTHERS => '0'); signal i_wrptr_s : std_logic_vector(lpm_widthu downto 0) := (OTHERS => '0'); signal i_rdempty : std_logic := '1'; signal i_wrempty : std_logic := '1'; signal i_rdfull : std_logic := '0'; signal i_wrfull : std_logic := '0'; signal i_rden : std_logic := '0'; signal i_wren : std_logic := '0'; signal i_wren_tmp : std_logic := '0'; signal i_rdusedw : std_logic_vector(lpm_widthu downto 0) := (OTHERS => '0'); signal i_wrusedw : std_logic_vector(lpm_widthu downto 0) := (OTHERS => '0'); signal i_q_tmp : std_logic_vector(lpm_width-1 downto 0) := (OTHERS => '0'); signal i_cnt_mod : integer := 0; signal i_max_widthu : integer := 0; -- COMPONENT DECLARATION component DCFIFO_DFFPIPE generic ( lpm_delay : natural; lpm_width : natural); port ( d : in std_logic_vector(LPM_WIDTH-1 downto 0); clock : in std_logic; aclr : in std_logic := '0'; q : out std_logic_vector(LPM_WIDTH-1 downto 0)); end component; begin -- Delays RDPTR_D: DCFIFO_DFFPIPE generic map ( lpm_delay => 1, lpm_width => lpm_widthu + 1) port map ( d => i_rdptr, clock => wrclk, aclr => aclr, q => i_rdptr_s); WRPTR_D: DCFIFO_DFFPIPE generic map ( lpm_delay => 1, lpm_width => lpm_widthu + 1) port map ( d => i_wrptr, clock => wrclk, aclr => aclr, q => i_wrptr_r); WRPTR_E: DCFIFO_DFFPIPE generic map ( lpm_delay => 1, lpm_width => lpm_widthu + 1) port map ( d => i_wrptr_r, clock => rdclk, aclr => aclr, q => i_wrptr_s); -- PROCESS DECLARATION -- FIFOram process (aclr, wrclk, rdclk) variable need_init : boolean := true; variable mem_data : LPM_MEMORY := (OTHERS => ZEROS); begin if (need_init) then if ((lpm_showahead /= "ON") and (lpm_showahead /= "OFF")) then ASSERT FALSE REPORT "Error! LPM_SHOWAHEAD must be ON or OFF." SEVERITY ERROR; end if; if ((underflow_checking /= "ON") and (underflow_checking /= "OFF")) then ASSERT FALSE REPORT "Error! UNDERFLOW_CHECKING must be ON or OFF." SEVERITY ERROR; end if; if ((overflow_checking /= "ON") and (overflow_checking /= "OFF")) then ASSERT FALSE REPORT "Error! OVERFLOW_CHECKING must be ON or OFF." SEVERITY ERROR; end if; if ((use_eab /= "ON") and (use_eab /= "OFF")) then ASSERT FALSE REPORT "Error! USE_EAB must be ON or OFF." SEVERITY ERROR; end if; if (lpm_numwords > 2 ** lpm_widthu) then ASSERT FALSE REPORT "Error! LPM_NUMWORDS must be less than or equal to 2**LPM_WIDTHU." SEVERITY ERROR; end if; if ((add_ram_output_register /= "ON") and (add_ram_output_register /= "OFF")) then ASSERT FALSE REPORT "Error! ADD_RAM_OUTPUT_REGISTER must be ON or OFF." SEVERITY ERROR; end if; if (IS_VALID_FAMILY(intended_device_family) = false) then ASSERT FALSE REPORT "Error! Illegal INTENDED_DEVICE_FAMILY." SEVERITY ERROR; end if; for i in lpm_numwords-1 downto 0 loop mem_data(i) := ZEROS; end loop; if (lpm_numwords = 2 ** lpm_widthu) then i_cnt_mod <= 2 ** (lpm_widthu + 1); else i_cnt_mod <= 2 ** lpm_widthu; end if; i_max_widthu <= 2 ** lpm_widthu; need_init := false; end if; -- need_init if (aclr'event and (aclr = '1')) then i_rdptr <= ZEROU; i_wrptr <= ZEROU; if (not (IS_FAMILY_STRATIX(intended_device_family) or IS_FAMILY_STRATIXGX(intended_device_family) or IS_FAMILY_ACEX2K(intended_device_family)) or ((add_ram_output_register = "ON") and (use_eab = "OFF"))) then if (lpm_showahead = "ON") then i_q_tmp <= mem_data(0); else i_q_tmp <= ZEROS; end if; end if; end if; -- aclr event if (wrclk'event) then if ((aclr = '1') and (not (IS_FAMILY_STRATIX(intended_device_family) or IS_FAMILY_STRATIXGX(intended_device_family) or IS_FAMILY_ACEX2K(intended_device_family)) or ((add_ram_output_register = "ON") and (use_eab = "OFF")))) then i_data_tmp <= ZEROS; i_wrptr_tmp <= ZEROU; i_wren_tmp <= '0'; elsif ((wrclk = '1') and (NOW > 0 ns)) then i_data_tmp <= data; i_wrptr_tmp <= i_wrptr; i_wren_tmp <= i_wren; if (i_wren = '1') then if ((aclr = '0') and (i_wrptr < i_cnt_mod - 1)) then i_wrptr <= i_wrptr + 1; else i_wrptr <= ZEROU; end if; if (use_eab = "OFF") then mem_data(CONV_INTEGER(i_wrptr) mod i_max_widthu) := data; if (lpm_showahead = "ON") then i_q_tmp <= mem_data(CONV_INTEGER(i_rdptr) mod i_max_widthu); end if; end if; end if; end if; if (((wrclk = '0') and (use_eab = "ON")) and (NOW > 0 ns)) then if (i_wren_tmp = '1') then mem_data(CONV_INTEGER(i_wrptr_tmp) mod i_max_widthu) := i_data_tmp; end if; if (lpm_showahead = "ON") then i_q_tmp <= mem_data(CONV_INTEGER(i_rdptr) mod i_max_widthu); end if; end if; end if; -- wrclk event if (rdclk'event) then if ((aclr = '1') and (not (IS_FAMILY_STRATIX(intended_device_family) or IS_FAMILY_STRATIXGX(intended_device_family) or IS_FAMILY_ACEX2K(intended_device_family)) or ((add_ram_output_register = "ON") and (use_eab = "OFF")))) then if (lpm_showahead = "ON") then i_q_tmp <= mem_data(0); else i_q_tmp <= ZEROS; end if; elsif ((rdclk = '1') and (i_rden = '1') and (NOW > 0 ns)) then if ((aclr = '0') and (i_rdptr < i_cnt_mod - 1)) then i_rdptr <= i_rdptr + 1; else i_rdptr <= ZEROU; end if; if (lpm_showahead = "ON") then i_q_tmp <= mem_data(CONV_INTEGER(i_rdptr + 1) mod i_max_widthu); else i_q_tmp <= mem_data(CONV_INTEGER(i_rdptr) mod i_max_widthu); end if; end if; end if; -- rdclk event end process; -- aclr, wrclk, rdclk events i_rden <= rdreq when (underflow_checking = "OFF") else rdreq and not i_rdempty; i_wren <= wrreq when (overflow_checking = "OFF") else wrreq and not i_wrfull; -- Usedw/Empty/Full process (i_rdptr, i_wrptr_s) begin if (NOW > 0 ns) then if (CONV_INTEGER (i_wrptr_s) >= CONV_INTEGER (i_rdptr)) then i_rdusedw <= i_wrptr_s - i_rdptr; else i_rdusedw <= i_wrptr_s + i_cnt_mod - i_rdptr; end if; end if; end process; -- i_rdusedw event process (i_wrptr, i_rdptr_s) begin if (NOW > 0 ns) then if (CONV_INTEGER (i_wrptr) >= CONV_INTEGER (i_rdptr_s)) then i_wrusedw <= i_wrptr - i_rdptr_s; else i_wrusedw <= i_wrptr + i_cnt_mod - i_rdptr_s; end if; end if; end process; -- i_wrusedw event process (i_rdusedw) begin if (i_rdusedw = 0) then i_rdempty <= '1'; else i_rdempty <= '0'; end if; if ((lpm_numwords = i_max_widthu) and (i_rdusedw >= i_max_widthu)) or ((lpm_numwords < i_max_widthu) and (i_rdusedw = lpm_numwords)) then i_rdfull <= '1'; else i_rdfull <= '0'; end if; end process; -- i_rdempty and i_rdfull event process (i_wrusedw) begin if (i_wrusedw = 0) then i_wrempty <= '1'; else i_wrempty <= '0'; end if; if ((lpm_numwords = i_max_widthu) and (i_wrusedw >= i_max_widthu)) or ((lpm_numwords < i_max_widthu) and (i_wrusedw = lpm_numwords)) then i_wrfull <= '1'; else i_wrfull <= '0'; end if; end process; -- i_wrempty and i_wrfull event -- Outputs rdfull <= i_rdfull; wrfull <= i_wrfull; rdempty <= i_rdempty; wrempty <= i_wrempty; rdusedw <= i_rdusedw (lpm_widthu-1 downto 0); wrusedw <= i_wrusedw (lpm_widthu-1 downto 0); q <= i_q_tmp; end behavior; -- dcfifo_sync -- END OF ARCHITECTURE ---START_ENTITY_HEADER--------------------------------------------------------- -- -- Entity Name : dcfifo -- -- Description : Dual clocks FIFO -- -- Limitation : -- -- Results Expected: -- ---END_ENTITY_HEADER----------------------------------------------------------- -- BEGINNING OF ENTITY library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; use IEEE.std_logic_unsigned.all; -- ENTITY DECLARATION entity DCFIFO is -- GENERIC DECLARATION generic ( lpm_width : natural; lpm_widthu : natural; lpm_numwords : natural; delay_rdusedw : natural := 1; delay_wrusedw : natural := 1; rdsync_delaypipe : natural := 3; wrsync_delaypipe : natural := 3; intended_device_family : string := "NON_STRATIX"; lpm_showahead : string := "OFF"; underflow_checking : string := "ON"; overflow_checking : string := "ON"; clocks_are_synchronized : string := "FALSE"; use_eab : string := "ON"; add_ram_output_register : string := "OFF"; add_width : natural := 1; lpm_hint : string := "USE_EAB=ON"; lpm_type : string := "dcfifo"); -- PORT DECLARATION port ( -- INPUT PORT DECLARATION data : in std_logic_vector(lpm_width-1 downto 0); rdclk : in std_logic; wrclk : in std_logic; aclr : in std_logic := '0'; rdreq : in std_logic; wrreq : in std_logic; -- OUTPUT PORT DECLARATION rdfull : out std_logic; wrfull : out std_logic; rdempty : out std_logic; wrempty : out std_logic; rdusedw : out std_logic_vector(lpm_widthu-1 downto 0); wrusedw : out std_logic_vector(lpm_widthu-1 downto 0); q : out std_logic_vector(lpm_width-1 downto 0)); end DCFIFO; -- END OF ENTITY -- BEGINNING OF ARCHITECTURE -- ARCHITECTURE DECLARATION architecture behavior of DCFIFO is -- SIGNAL DECLARATION signal i_rdfull_a : std_logic := '0'; signal i_wrfull_a : std_logic := '0'; signal i_rdempty_a : std_logic := '1'; signal i_wrempty_a : std_logic := '1'; signal i_rdfull_s : std_logic := '0'; signal i_wrfull_s : std_logic := '0'; signal i_rdempty_s : std_logic := '1'; signal i_wrempty_s : std_logic := '1'; signal i_rdusedw_a : std_logic_vector(lpm_widthu-1 downto 0) := (OTHERS => '0'); signal i_wrusedw_a : std_logic_vector(lpm_widthu-1 downto 0) := (OTHERS => '0'); signal i_rdusedw_s : std_logic_vector(lpm_widthu-1 downto 0) := (OTHERS => '0'); signal i_wrusedw_s : std_logic_vector(lpm_widthu-1 downto 0) := (OTHERS => '0'); signal i_q_a : std_logic_vector(lpm_width-1 downto 0) := (OTHERS => '0'); signal i_q_s : std_logic_vector(lpm_width-1 downto 0) := (OTHERS => '0'); -- COMPONENT DECLARATION component DCFIFO_ASYNC generic ( lpm_width : natural; lpm_widthu : natural; lpm_numwords : natural; delay_rdusedw : natural := 1; delay_wrusedw : natural := 1; rdsync_delaypipe : natural := 3; wrsync_delaypipe : natural := 3; intended_device_family : string := "NON_STRATIX"; lpm_showahead : string := "OFF"; underflow_checking : string := "ON"; overflow_checking : string := "ON"; use_eab : string := "ON"; add_ram_output_register : string := "OFF"); port ( data : in std_logic_vector(lpm_width-1 downto 0); rdclk : in std_logic; wrclk : in std_logic; aclr : in std_logic := '0'; rdreq : in std_logic; wrreq : in std_logic; rdfull : out std_logic; wrfull : out std_logic; rdempty : out std_logic; wrempty : out std_logic; rdusedw : out std_logic_vector(lpm_widthu-1 downto 0); wrusedw : out std_logic_vector(lpm_widthu-1 downto 0); q : out std_logic_vector(lpm_width-1 downto 0)); end component; component DCFIFO_SYNC generic ( lpm_width : natural; lpm_widthu : natural; lpm_numwords : natural; intended_device_family : string := "NON_STRATIX"; lpm_showahead : string := "OFF"; underflow_checking : string := "ON"; overflow_checking : string := "ON"; use_eab : string := "ON"; add_ram_output_register : string := "OFF"); port ( data : in std_logic_vector(lpm_width-1 downto 0); rdclk : in std_logic; wrclk : in std_logic; aclr : in std_logic := '0'; rdreq : in std_logic; wrreq : in std_logic; rdfull : out std_logic; wrfull : out std_logic; rdempty : out std_logic; wrempty : out std_logic; rdusedw : out std_logic_vector(lpm_widthu-1 downto 0); wrusedw : out std_logic_vector(lpm_widthu-1 downto 0); q : out std_logic_vector(lpm_width-1 downto 0)); end component; begin -- COMPONENT ASSIGNMENTS ASYNC: DCFIFO_ASYNC generic map ( lpm_width => lpm_width, lpm_widthu => lpm_widthu, lpm_numwords => lpm_numwords, delay_rdusedw => delay_rdusedw, delay_wrusedw => delay_wrusedw, rdsync_delaypipe => rdsync_delaypipe, wrsync_delaypipe => wrsync_delaypipe, intended_device_family => intended_device_family, lpm_showahead => lpm_showahead, underflow_checking => underflow_checking, overflow_checking => overflow_checking, use_eab => use_eab, add_ram_output_register => add_ram_output_register) port map ( data => data, rdclk => rdclk, wrclk => wrclk, aclr => aclr, rdreq => rdreq, wrreq => wrreq, rdfull => i_rdfull_a, wrfull => i_wrfull_a, rdempty => i_rdempty_a, wrempty => i_wrempty_a, rdusedw => i_rdusedw_a, wrusedw => i_wrusedw_a, q => i_q_a); SYNC: DCFIFO_SYNC generic map ( lpm_width => lpm_width, lpm_widthu => lpm_widthu, lpm_numwords => lpm_numwords, intended_device_family => intended_device_family, lpm_showahead => lpm_showahead, underflow_checking => underflow_checking, overflow_checking => overflow_checking, use_eab => use_eab, add_ram_output_register => add_ram_output_register) port map ( data => data, rdclk => rdclk, wrclk => wrclk, aclr => aclr, rdreq => rdreq, wrreq => wrreq, rdfull => i_rdfull_s, wrfull => i_wrfull_s, rdempty => i_rdempty_s, wrempty => i_wrempty_s, rdusedw => i_rdusedw_s, wrusedw => i_wrusedw_s, q => i_q_s); rdfull <= i_rdfull_s when clocks_are_synchronized = "TRUE" else i_rdfull_a; wrfull <= i_wrfull_s when clocks_are_synchronized = "TRUE" else i_wrfull_a; rdempty <= i_rdempty_s when clocks_are_synchronized = "TRUE" else i_rdempty_a; wrempty <= i_wrempty_s when clocks_are_synchronized = "TRUE" else i_wrempty_a; rdusedw <= i_rdusedw_s when clocks_are_synchronized = "TRUE" else i_rdusedw_a; wrusedw <= i_wrusedw_s when clocks_are_synchronized = "TRUE" else i_wrusedw_a; q <= i_q_s when clocks_are_synchronized = "TRUE" else i_q_a; end behavior; -- dcfifo -- END OF ARCHITECTURE -------------------------------------------------------------------------------- -- Module Name : altshift_taps -- -- Description : Parameterized shift register with taps megafunction. -- Implements a RAM-based shift register for efficient -- creation of very large shift registers -- -- Limitation : This megafunction is provided only for backward -- compatibility in Cyclone, Stratix, and Stratix GX -- designs. -- -- Results expected : Produce output from the end of the shift register -- and from the regularly spaced taps along the -- shift register. -- -------------------------------------------------------------------------------- library IEEE; use IEEE.std_logic_1164.all; -- ENTITY DECLARATION entity altshift_taps is generic (number_of_taps : integer := 4; -- Specifies the number of regularly spaced -- taps along the shift register tap_distance : integer := 3; -- Specifies the distance between the -- regularly spaced taps in clock cycles -- This number translates to the number of -- RAM words that will be used width : integer := 8; power_up_state : string := "CLEARED"; lpm_hint : string := "UNUSED"; lpm_type : string := "altshift_taps" ); port (-- data input to the shifter shiftin : in std_logic_vector (width-1 downto 0); -- Positive-edge triggered clock clock : in std_logic; -- Clock enable for the clock port clken : in std_logic := '1'; -- Output from the end of the shift register shiftout : out std_logic_vector (width-1 downto 0); -- Output from the regularly spaced taps along the shift register taps : out std_logic_vector ((width*number_of_taps)-1 downto 0) ); end altshift_taps; -- ARCHITECTURE DECLARATION architecture behavioural of altshift_taps is -- CONSTANT DECLARATION constant TOTAL_TAP_DISTANCE : integer := number_of_taps * tap_distance; -- TYPE DECLARATION type mxn_array is array (TOTAL_TAP_DISTANCE-1 downto 0) of std_logic_vector (width downto 0); -- SIGNAL DECLARATION signal contents : mxn_array; signal head_pipe : integer := 0; signal i : integer:= 0; begin -- PROCESS BLOCKS SHIFT: process (clock) variable head: integer := 0; variable init : boolean := true; begin if init and (power_up_state = "CLEARED") then shiftout <= (others => '0'); taps <= (others => '0'); contents <= (others => (others => '0')); init := false; end if; if (clock'event and (clock = '1') and (clken = '1')) then head := head_pipe; contents (head)(width-1 downto 0) <= shiftin; shiftout <= contents ((head+1) mod TOTAL_TAP_DISTANCE)(width-1 downto 0); head := (head+1) mod TOTAL_TAP_DISTANCE; for i in 0 to (number_of_taps-1) loop taps (((i+1)*width)-1 downto (i*width) ) <= contents ((((number_of_taps - i - 1)*tap_distance) + head) mod TOTAL_TAP_DISTANCE)(width-1 downto 0); end loop; head_pipe <= head; end if; end process shift; end behavioural; -- altshift_taps ---START_ENTITY_HEADER--------------------------------------------------------- -- -- Entity Name : a_graycounter -- -- Description : Gray counter with Count-enable, Up/Down, aclr and sclr -- -- Limitation : Sync sigal priority: clk_en (higher),sclr,cnt_en (lower) -- -- Results Expected: q is graycounter output and qbin is normal counter -- ---END_ENTITY_HEADER----------------------------------------------------------- -- BEGINNING OF ENTITY library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; use IEEE.std_logic_unsigned.all; -- ENTITY DECLARATION entity A_GRAYCOUNTER is -- GENERIC DECLARATION generic ( width : natural; pvalue : natural; lpm_type : string := "a_graycounter"); -- PORT DECLARATION port ( -- INPUT PORT DECLARATION clock : in std_logic; clk_en : in std_logic := '1'; cnt_en : in std_logic := '1'; updown : in std_logic := '1'; aclr : in std_logic := '0'; sclr : in std_logic := '0'; -- OUTPUT PORT DECLARATION qbin : out std_logic_vector(width-1 downto 0); q : out std_logic_vector(width-1 downto 0)); end A_GRAYCOUNTER; -- END OF ENTITY -- BEGINNING OF ARCHITECTURE -- ARCHITECTURE DECLARATION architecture behavior of A_GRAYCOUNTER is -- SIGNAL DECLARATION signal cnt : std_logic_vector(width-1 downto 0); signal qbin_tmp : std_logic_vector(width-1 downto 0); begin -- PROCESS DECLARATION -- basic error checking for invalid parameters MSG: process begin if (width <= 0) then ASSERT FALSE REPORT "Value of WIDTH parameter of a_graycounter must be greater than 0!" SEVERITY ERROR; end if; wait; end process MSG; process(aclr, clock) variable init : boolean := true; begin if (init) then -- Initialize to pvalue cnt <= conv_std_logic_vector(pvalue, width); init := false; elsif (aclr'event and (aclr = '1')) then cnt <= conv_std_logic_vector(pvalue, width); elsif (aclr = '0' and clock'event and (clock = '1')) then if (clk_en = '1') then if (sclr = '1') then cnt <= conv_std_logic_vector(pvalue, width); elsif (cnt_en = '1') then if (updown = '1') then cnt <= cnt + 1; else cnt <= cnt - 1; end if; end if; end if; end if; end process; qbin_tmp <= cnt; process(qbin_tmp) variable qbin_rshift : std_logic_vector(width-1 downto 0); begin if (width > 1) then qbin_rshift(width-2 downto 0) := qbin_tmp(width-1 downto 1); end if; qbin_rshift(width-1) := '0'; q <= qbin_tmp xor qbin_rshift; end process; qbin <= cnt; end behavior; -- a_graycounter -- END OF ARCHITECTURE -- -- Excalibur DPRAM atom. -- library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_unsigned.all; use IEEE.std_logic_textio.all; use std.textio.all; entity alt_exc_dpram is generic ( width : integer; addrwidth : integer; depth : integer; ramblock : integer := 65535; operation_mode : string := "SINGLE_PORT"; output_mode : string := "REG"; lpm_file : string := "NONE"; lpm_type : string := "alt_exc_dpram" ); port ( portaclk : in std_logic := '0'; portaena : in std_logic := '0'; portawe : in std_logic := '0'; portaaddr : in std_logic_vector(addrwidth-1 downto 0) := (others =>'0'); portadatain : in std_logic_vector(width-1 downto 0) := (others =>'0'); portadataout : out std_logic_vector(width-1 downto 0); portbclk : in std_logic := '0'; portbena : in std_logic := '0'; portbwe : in std_logic := '0'; portbaddr : in std_logic_vector(addrwidth-1 downto 0) := (others =>'0'); portbdatain : in std_logic_vector(width-1 downto 0) := (others =>'0'); portbdataout : out std_logic_vector(width-1 downto 0)); end alt_exc_dpram; architecture behaviour of alt_exc_dpram is -- -- Hex Read procedure. -- procedure local_Char2QuadBits(C: Character; RESULT: out Bit_Vector(3 downto 0); GOOD: out Boolean; ISSUE_ERROR: in Boolean) is begin case c is when '0' => result := x"0"; good := TRUE; when '1' => result := x"1"; good := TRUE; when '2' => result := x"2"; good := TRUE; when '3' => result := x"3"; good := TRUE; when '4' => result := x"4"; good := TRUE; when '5' => result := x"5"; good := TRUE; when '6' => result := x"6"; good := TRUE; when '7' => result := x"7"; good := TRUE; when '8' => result := x"8"; good := TRUE; when '9' => result := x"9"; good := TRUE; when 'A' => result := x"A"; good := TRUE; when 'B' => result := x"B"; good := TRUE; when 'C' => result := x"C"; good := TRUE; when 'D' => result := x"D"; good := TRUE; when 'E' => result := x"E"; good := TRUE; when 'F' => result := x"F"; good := TRUE; when 'a' => result := x"A"; good := TRUE; when 'b' => result := x"B"; good := TRUE; when 'c' => result := x"C"; good := TRUE; when 'd' => result := x"D"; good := TRUE; when 'e' => result := x"E"; good := TRUE; when 'f' => result := x"F"; good := TRUE; when others => if ISSUE_ERROR then assert FALSE report "HREAD Error: Read a '" & c & "', expected a Hex character (0-F)."; end if; good := FALSE; end case; end; procedure HREAD_BV(L:inout LINE; VALUE:out BIT_VECTOR) is variable ok: boolean; variable c: character; constant ne: integer := value'length/4; variable bv: bit_vector(0 to value'length-1); variable s: string(1 to ne-1); begin if value'length mod 4 /= 0 then assert FALSE report "HREAD_BV Error: Trying to read vector " & "with an odd (non multiple of 4) length"; return; end if; loop -- skip white space read(l,c); exit when ((c /= ' ') and (c /= CR) and (c /= HT)); end loop; local_Char2QuadBits(c, bv(0 to 3), ok, TRUE); if not ok then return; end if; read(L, s, ok); if not ok then assert FALSE report "HREAD_bv Error: Failed to read the STRING"; return; end if; for i in 1 to ne-1 loop local_Char2QuadBits(s(i), bv(4*i to 4*i+3), ok, TRUE); if not ok then return; end if; end loop; value := bv; end HREAD_bv; type dpram_memory is array (depth-1 downto 0) of std_logic_vector(width-1 downto 0); ------------------------- function dpram_loadmem return dpram_memory is variable result : dpram_memory := (others=>(others=>'X')); file memory_file : TEXT; variable data_line : LINE ; variable memory_bitvector : bit_vector (width-1 downto 0) ; variable line_counter : INTEGER := 0 ; begin read_memory : FILE_OPEN(memory_file, lpm_file, READ_MODE); while not ENDFILE(memory_file) loop if ( line_counter <= depth-1 ) then READLINE (memory_file, data_line) ; if ( data_line'LENGTH = 0 ) then next ; elsif ( data_line (1) = '/' ) then next ; end if ; HREAD_bv (data_line , memory_bitvector ) ; result (line_counter) := To_StdLogicVector (memory_bitvector) ; line_counter := line_counter + 1 ; end if ; end loop ; FILE_CLOSE(memory_file); return result; end dpram_loadmem; ------------------------- ------------------------- function dpram_checkmem return dpram_memory is variable result : dpram_memory := (others=>(others=>'X')); begin if (lpm_file /= "NONE" and lpm_file /= "none") then result := dpram_loadmem ; end if ; return result; end dpram_checkmem; ------------------------- signal portadataout_reg : std_logic_vector(width-1 downto 0); signal portbdataout_reg : std_logic_vector(width-1 downto 0); signal portadataout_reg_out : std_logic_vector(width-1 downto 0); signal portbdataout_reg_out : std_logic_vector(width-1 downto 0); signal portadataout_unreg : std_logic_vector(width-1 downto 0); signal portbdataout_unreg : std_logic_vector(width-1 downto 0); signal portaclk_ipd : std_logic; signal portbclk_ipd : std_logic; signal portawe_ipd : std_logic; signal portbwe_ipd : std_logic; signal portaena_ipd : std_logic; signal portbena_ipd : std_logic; signal portadatain_ipd : std_logic_vector(width-1 downto 0); signal portbdatain_ipd : std_logic_vector(width-1 downto 0); signal portaaddr_ipd : std_logic_vector(addrwidth-1 downto 0); signal portbaddr_ipd : std_logic_vector(addrwidth-1 downto 0); signal portadataout_tmp : std_logic_vector(width-1 downto 0); signal portbdataout_tmp : std_logic_vector(width-1 downto 0); begin portaclk_ipd <= portaclk; portawe_ipd <= portawe; portaena_ipd <= portaena; portadatain_ipd <= portadatain; portbclk_ipd <= portbclk; portbwe_ipd <= portbwe; portbena_ipd <= portbena; portadatain_ipd <= portadatain; portbdatain_ipd <= portbdatain; portaaddr_ipd <= portaaddr; portbaddr_ipd <= portbaddr; portadataout <= portadataout_tmp; portbdataout <= portbdataout_tmp; CLOCK: process(portaclk_ipd, portbclk_ipd) variable dpram_content : dpram_memory := dpram_checkmem ; variable portawe_latched : std_ulogic; variable portbwe_latched : std_ulogic; variable address_A : integer; variable address_B : integer; variable valid_addr_A : boolean:=FALSE; variable valid_addr_B : boolean:=FALSE; begin -- Dual Port Contention Port A address = Port B address -- -- +-----------+----------+-------------+-------------+--------------+--------------+---------------------+ -- | Port A | Port B | A Data In | B Data In | A Data Out | B Data Out | Memory State | -- +-----------+----------+-------------+-------------+--------------+--------------+---------------------+ -- | read | read | DA | DB | memory | memory | no change | -- +-----------+----------+-------------+-------------+--------------+--------------+---------------------+ -- | write | read | DA | DB | unknown | unknown | memory <= DA | -- +-----------+----------+-------------+-------------+--------------+--------------+---------------------+ -- | read | write | DA | DB | unknown | unknown | memory <= DB | -- +-----------+----------+-------------+-------------+--------------+--------------+---------------------+ -- | write | write | DA | DB | unknown | unknown | memory <= unknown | -- +-----------+----------+-------------+-------------+--------------+--------------+---------------------+ -- -- Dual Port Contention Port A address != Port B address -- -- +-----------+----------+-------------+-------------+--------------+--------------+---------------------+ -- | Port A | Port B | A Data In | B Data In | A Data Out | B Data Out | Memory State | -- +-----------+----------+-------------+-------------+--------------+--------------+---------------------+ -- | read | read | DA | DB | mem[A_addr] | mem[B_Addr] | no change | -- +-----------+----------+-------------+-------------+--------------+--------------+---------------------+ -- | write | read | DA | DB | unknown | mem[B_Addr] | mem[A_Addr] <= DA | -- +-----------+----------+-------------+-------------+--------------+--------------+---------------------+ -- | read | write | DA | DB | mem[A_addr] | unknown | mem[B_Addr] <= DB | -- +-----------+----------+-------------+-------------+--------------+--------------+---------------------+ -- | write | write | DA | DB | unknown | unknown | mem[A_Addr] <= DA | -- | | | | | | | mem[B_Addr] <= DB | -- +-----------+----------+-------------+-------------+--------------+--------------+---------------------+ -- -- NB: output is always unknown when writing if(portaclk_ipd'event and portaclk_ipd='1') then -- rising edge port a clock portawe_latched := portawe_ipd; valid_addr_A := not Is_X(portaaddr_ipd(addrwidth-1 downto 0)); if ( valid_addr_A ) then address_A := conv_integer(portaaddr_ipd); if portawe_latched ='0' then -- reading from A if valid_addr_B and address_A = address_B and portbwe_latched = '1' then -- B simultaneously writing to same address (effect of B write to memory handled below) portadataout_reg <= portadataout_unreg; portadataout_unreg <= (others => 'X') ; else -- B reading from same address, or reading/writing to different address. portadataout_reg <= portadataout_unreg ; portadataout_unreg <= dpram_content(address_A); end if; else -- writing to A if valid_addr_B and address_A = address_B and portawe_latched = '1' and portbwe_latched = '1' then -- A and B simultaneously writing to same address portadataout_reg <= portadataout_unreg; dpram_content(address_A) := (others => 'X') ; portadataout_unreg <= (others => 'X') ; else -- B reading from same address or reading/writing to different address portadataout_reg <= portadataout_unreg; dpram_content(address_A) := portadatain_ipd ; portadataout_unreg <= (others => 'X') ; end if; end if; else portadataout_reg <= portadataout_unreg; address_A := 0 ; portadataout_unreg <= (others => 'X') ; end if ; end if ; if (portbclk_ipd'event and portbclk_ipd = '1') then -- rising edge port b clock portbwe_latched := portbwe_ipd; valid_addr_B := not Is_X(portbaddr_ipd(addrwidth-1 downto 0)); if ( valid_addr_B ) then address_B := conv_integer(portbaddr_ipd); if portbwe_latched ='0' then -- reading from B if valid_addr_A and address_B = address_A and portawe_latched = '1' then -- A simultaneously writing to same address (effect of A write to memory handled above) portbdataout_reg <= portbdataout_unreg; portbdataout_unreg <= (others => 'X') ; else -- A reading from same address, or reading/writing to different address. portbdataout_reg <= portbdataout_unreg ; portbdataout_unreg <= dpram_content(address_B); end if; else -- writing to B if valid_addr_A and address_B = address_A and portbwe_latched = '1' and portawe_latched = '1' then -- B and A simultaneously writing to same address portbdataout_reg <= portbdataout_unreg; dpram_content(address_B) := (others => 'X') ; portbdataout_unreg <= (others => 'X') ; else -- A reading from same address or reading/writing to different address portbdataout_reg <= portbdataout_unreg; dpram_content(address_B) := portbdatain_ipd ; portbdataout_unreg <= (others => 'X') ; end if; end if; else portbdataout_reg <= portbdataout_unreg; address_B := 0 ; portbdataout_unreg <= (others => 'X') ; end if ; end if; end process CLOCK; OUTPUT_ENABLE_A : process(portaena_ipd, portadataout_reg) begin if((output_mode = "REG" or output_mode = "reg") and portaena_ipd = '1') then portadataout_reg_out <= portadataout_reg ; end if; end process OUTPUT_ENABLE_A; OUTPUT_ENABLE_B : process(portbena_ipd, portbdataout_reg) begin if((output_mode = "REG" or output_mode = "reg") and portbena_ipd = '1') then portbdataout_reg_out <= portbdataout_reg ; end if; end process OUTPUT_ENABLE_B; REG_UNREG_SEL_A : process(portadataout_reg_out, portadataout_unreg) begin if(output_mode = "UNREG" or output_mode = "unreg") then portadataout_tmp <= portadataout_unreg; else portadataout_tmp <= portadataout_reg_out; end if; end process REG_UNREG_SEL_A; REG_UNREG_SEL_B : process(portbdataout_reg_out, portbdataout_unreg) begin if(output_mode = "UNREG" or output_mode = "unreg") then portbdataout_tmp <= portbdataout_unreg; else portbdataout_tmp <= portbdataout_reg_out; end if; end process REG_UNREG_SEL_B; end behaviour; -- -- Excalibur UPCORE atom. -- library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; use IEEE.std_logic_textio.all; use IEEE.std_logic_unsigned.all; use std.textio.all; entity alt_exc_upcore is generic ( processor : string := "ARM"; source : string := ""; sdram_width : integer := 32; sdramdqm_width : integer := 4; gpio_width : integer := 4; lpm_type : string := "alt_exc_upcore" ); port ( npor : in std_logic := '1'; clk_ref : in std_logic := '0'; nreset : inout std_logic := '1'; intpld : in std_logic_vector(5 downto 0) := (others => '0'); intnmi : in std_logic := '0'; intuart : out std_logic; inttimer0 : out std_logic; inttimer1 : out std_logic; intcommtx : out std_logic; intcommrx : out std_logic; intproctimer : out std_logic; intprocbridge : out std_logic; perreset : out std_logic; debugrq : in std_logic := '0'; debugext0 : in std_logic := '0'; debugext1 : in std_logic := '0'; debugiebrkpt : in std_logic := '0'; debugdewpt : in std_logic := '0'; debugextin : in std_logic_vector(3 downto 0) := (others => '0'); debugack : out std_logic; debugrng0 : out std_logic; debugrng1 : out std_logic; debugextout : out std_logic_vector(3 downto 0); slavehclk : in std_logic := '0'; slavehwrite : in std_logic := '0'; slavehreadyi : in std_logic := '0'; slavehselreg : in std_logic := '0'; slavehsel : in std_logic := '0'; slavehmastlock : in std_logic := '0'; slavehaddr : in std_logic_vector(31 downto 0) := (others => '0'); slavehwdata : in std_logic_vector(31 downto 0) := (others => '0'); slavehtrans : in std_logic_vector(1 downto 0) := (others => '0'); slavehsize : in std_logic_vector(1 downto 0) := (others => '0'); slavehburst : in std_logic_vector(2 downto 0) := (others => '0'); slavehreadyo : out std_logic; slavebuserrint : out std_logic; slavehrdata : out std_logic_vector(31 downto 0); slavehresp : out std_logic_vector(1 downto 0); masterhclk : in std_logic := '0'; masterhrdata : in std_logic_vector(31 downto 0) := (others => '0'); masterhresp : in std_logic_vector(1 downto 0) := (others => '0'); masterhwrite : out std_logic; masterhlock : out std_logic; masterhbusreq : out std_logic; masterhaddr : out std_logic_vector(31 downto 0); masterhwdata : out std_logic_vector(31 downto 0); masterhtrans : out std_logic_vector(1 downto 0); masterhsize : out std_logic_vector(1 downto 0); masterhready : in std_logic := '0'; masterhburst : out std_logic_vector(2 downto 0); masterhgrant : in std_logic := '0'; lockreqdp0 : in std_logic := '0'; lockreqdp1 : in std_logic := '0'; lockgrantdp0 : out std_logic; lockgrantdp1 : out std_logic; ebiack : in std_logic := '0'; ebiwen : out std_logic; ebioen : out std_logic; ebiclk : out std_logic; ebibe : out std_logic_vector(1 downto 0); ebicsn : out std_logic_vector(3 downto 0); ebiaddr : out std_logic_vector(24 downto 0); ebidq : inout std_logic_vector(15 downto 0) := (others => '0'); uarttxd : out std_logic; uartrtsn : out std_logic; uartdtrn : out std_logic; uartctsn : in std_logic := '0'; uartdsrn : in std_logic := '0'; uartrxd : in std_logic := '0'; uartdcdn : inout std_logic := '0'; uartrin : inout std_logic := '0'; sdramclk : out std_logic; sdramclkn : out std_logic; sdramclke : out std_logic; sdramwen : out std_logic; sdramcasn : out std_logic; sdramrasn : out std_logic; sdramdqm : out std_logic_vector(sdramdqm_width-1 downto 0); sdramaddr : out std_logic_vector(14 downto 0); sdramcsn : out std_logic_vector(1 downto 0); sdramdq : inout std_logic_vector(sdram_width-1 downto 0) := (others => '0'); sdramdqs : inout std_logic_vector(sdramdqm_width-1 downto 0) := (others => '0'); intextpin : in std_logic := '0'; traceclk : out std_logic; tracesync : out std_logic; tracepipestat : out std_logic_vector(2 downto 0); tracepkt : out std_logic_vector(15 downto 0); gpi : in std_logic_vector(gpio_width-1 downto 0) := (others => '0'); gpo : out std_logic_vector(gpio_width-1 downto 0)); end alt_exc_upcore; architecture behaviour of alt_exc_upcore is -- -- Hex Read and Write procedures. -- procedure local_Char2QuadBits(C: Character; RESULT: out Bit_Vector(3 downto 0); GOOD: out Boolean; ISSUE_ERROR: in Boolean) is begin case c is when '0' => result := x"0"; good := TRUE; when '1' => result := x"1"; good := TRUE; when '2' => result := x"2"; good := TRUE; when '3' => result := x"3"; good := TRUE; when '4' => result := x"4"; good := TRUE; when '5' => result := x"5"; good := TRUE; when '6' => result := x"6"; good := TRUE; when '7' => result := x"7"; good := TRUE; when '8' => result := x"8"; good := TRUE; when '9' => result := x"9"; good := TRUE; when 'A' => result := x"A"; good := TRUE; when 'B' => result := x"B"; good := TRUE; when 'C' => result := x"C"; good := TRUE; when 'D' => result := x"D"; good := TRUE; when 'E' => result := x"E"; good := TRUE; when 'F' => result := x"F"; good := TRUE; when 'a' => result := x"A"; good := TRUE; when 'b' => result := x"B"; good := TRUE; when 'c' => result := x"C"; good := TRUE; when 'd' => result := x"D"; good := TRUE; when 'e' => result := x"E"; good := TRUE; when 'f' => result := x"F"; good := TRUE; when others => if ISSUE_ERROR then assert FALSE report "HREAD Error: Read a '" & c & "', expected a Hex character (0-F)."; end if; good := FALSE; end case; end; procedure HREAD_BV(L:inout LINE; VALUE:out BIT_VECTOR) is variable ok: boolean; variable c: character; constant ne: integer := value'length/4; variable bv: bit_vector(0 to value'length-1); variable s: string(1 to ne-1); begin if value'length mod 4 /= 0 then assert FALSE report "HREAD_BV Error: Trying to read vector " & "with an odd (non multiple of 4) length"; return; end if; loop -- skip white space read(l,c); exit when ((c /= ' ') and (c /= CR) and (c /= HT)); end loop; local_Char2QuadBits(c, bv(0 to 3), ok, TRUE); if not ok then return; end if; read(L, s, ok); if not ok then assert FALSE report "HREAD_bv Error: Failed to read the STRING"; return; end if; for i in 1 to ne-1 loop local_Char2QuadBits(s(i), bv(4*i to 4*i+3), ok, TRUE); if not ok then return; end if; end loop; value := bv; end HREAD_bv; -- functions to match Verilog functions and operators -- Bitwise left shift function shift_left ( val : std_logic_vector ) return std_logic_vector is variable result : std_logic_vector(val'length-1 downto 0); begin result:=val; if (val'length>1) then for i in (val'length-1) downto 1 loop result(i):=result(i-1); end loop; end if; result(0) := '0'; return result; end shift_left; function shift_left ( val : std_logic_vector; n : integer ) return std_logic_vector is variable result : std_logic_vector(val'length-1 downto 0); begin result:=val; for i in 1 to n loop result:=shift_left(result); end loop; return result; end shift_left; -- Unary reduction OR : use ur_OR(foo) as a replacement for Verilog (|foo). function ur_OR (val : std_logic_vector ) return std_logic is variable result : std_logic ; begin if (val'length > 0) then result := val(val'length-1) ; for i in (val'length-2) downto 0 loop result := (result or val(i)); end loop; else result := '0'; end if; return result; end ur_OR; -- Unary reduction XOR : use ur_XOR(foo) as a replacement for Verilog (^foo). function ur_XOR (val : std_logic_vector ) return std_logic is variable result : std_logic := '0' ; variable count : integer := 0 ; begin if (val'length > 0) then for i in (val'length-1) downto 0 loop if (result /= 'X') then if (val(i) = '1') then count := count + 1 ; elsif (val(i) = 'X') then result := 'X' ; end if ; end if ; end loop; else result := '0'; end if; if ( result = 'X') then return result ; elsif (count > 1 ) then return '0' ; else return '1' ; end if ; end ur_XOR; -- Components -- +---------------+ -- | AHB Constants | -- +---------------+ -- // number of memory banks constant NUMBANKS : integer := 6 ; -- // respones (HRESP) constant H_OKAY : std_logic_vector(1 downto 0) := "00" ; constant H_ERROR : std_logic_vector(1 downto 0) := "01" ; constant H_RETRY : std_logic_vector(1 downto 0) := "10" ; constant H_SPLIT : std_logic_vector(1 downto 0) := "11" ; -- // transaction types (HTRANS) constant H_IDLE : std_logic_vector(1 downto 0) := "00" ; constant H_BUSY : std_logic_vector(1 downto 0) := "01" ; constant H_NONSEQ : std_logic_vector(1 downto 0) := "10" ; constant H_SEQ : std_logic_vector(1 downto 0) := "11" ; -- // burst mode (HBURST) constant H_SINGLE : std_logic_vector(2 downto 0) := "000"; constant H_INCR : std_logic_vector(2 downto 0) := "001"; constant H_WRAP4 : std_logic_vector(2 downto 0) := "010"; constant H_INCR4 : std_logic_vector(2 downto 0) := "011"; constant H_WRAP8 : std_logic_vector(2 downto 0) := "100"; constant H_INCR8 : std_logic_vector(2 downto 0) := "101"; constant H_WRAP16 : std_logic_vector(2 downto 0) := "110"; constant H_INCR16 : std_logic_vector(2 downto 0) := "111"; -- // transaction sizes (HSIZE 8,16,32 bits -- larger sizes not supported) constant H_BYTE : std_logic_vector(1 downto 0) := "00" ; constant H_HWORD : std_logic_vector(1 downto 0) := "01" ; constant H_WORD : std_logic_vector(1 downto 0) := "10" ; -- // maximum number of transmissions constant NUMTRANS : integer := 2048 ; -- was 65535, but may lead to memory allocation problems -- // data sub-ranges within transmission constant Trns_b : integer := 255 ; -- 255..254 ; -- spare constant Trns_RESP_b : integer := 253 ; -- response constant Trns_RESP_l : integer := 252 ; constant Trns_READ_b : integer := 251 ; -- read data constant Trns_READ_l : integer := 220 ; constant Trns_BUSY : integer := 219 ; -- go busy -- 218..217 ; -- spare constant Trns_NUMSEQBEATS_b : integer := 216 ; -- number of beats in sequential transaction constant Trns_NUMSEQBEATS_l : integer := 208 ; constant Trns_STARTADDR_b : integer := 207 ; -- start address of transaction constant Trns_STARTADDR_l : integer := 176 ; constant Trns_EXPDATA_b : integer := 175 ; -- expected data constant Trns_EXPDATA_l : integer := 144 ; constant Trns_TRANSNUM_b : integer := 143 ; -- transaction number constant Trns_TRANSNUM_l : integer := 128 ; -- ---------------------------------------------------- -- following fields read from command file -- 127..112 ; -- spare -- 111..109 ; -- spare constant Trns_BUSCOMMD : integer := 108 ; -- bus command (0 => inactive) constant Trns_ADDR_b : integer := 107 ; -- address constant Trns_ADDR_l : integer := 76 ; -- 75.. 73 ; -- spare constant Trns_WRITE : integer := 72 ; -- write constant Trns_DATA_b : integer := 71 ; -- write data / expected read data constant Trns_DATA_l : integer := 40 ; -- 39.. 37 ; -- spare constant Trns_LOCK : integer := 36 ; -- lock (not implemented) -- 35.. 33 ; -- spare constant Trns_CHKDATA : integer := 32 ; -- check expected data (not implemented) -- 31.. 30 ; -- spare constant Trns_TRANSTYPE_b : integer := 29 ; -- transaction type constant Trns_TRANSTYPE_l : integer := 28 ; -- 27.. 23 ; -- spare constant Trns_BURSTTYPE_b : integer := 22 ; -- burst type constant Trns_BURSTTYPE_l : integer := 20 ; -- 19 ; -- spare constant Trns_SIZE_b : integer := 18 ; -- size constant Trns_SIZE_l : integer := 16 ; constant Trns_RPTCOUNT_b : integer := 15 ; -- repeat count constant Trns_RPTCOUNT_l : integer := 0 ; -- +------------+ -- | slave port | -- +------------+ -- record of address and control information (latched on address phase) signal startReg : std_logic_vector(31 downto 0) := ( others => '0') ; --// start address for burst signal addrReg : std_logic_vector(31 downto 0) := ( others => '0') ; signal transReg : std_logic_vector( 1 downto 0) := H_IDLE ; signal sizeReg : std_logic_vector( 1 downto 0) := H_WORD ; signal writeReg : std_logic := '0' ; signal burstReg : std_logic_vector( 2 downto 0) := H_SINGLE ; signal selReg : std_logic := '0' ; signal waitReg : std_logic_vector( 7 downto 0) := ( others => '0') ; -- Implement 6 banks of 256K = (1.5MB of address space) constant membank_size : integer := 20480 ; -- full 65535 leads to memory allocation problems type upcore_membank is array (0 to membank_size) of std_logic_vector(31 downto 0); type upcore_bankcfg is array (0 to 5) of std_logic_vector(79 downto 0); type upcore_bankstart_end is array (0 to 5) of std_logic_vector(31 downto 0); type upcore_memwait is array (0 to 5) of std_logic_vector( 7 downto 0); constant start_addr_b : integer := 79 ; -- start address index upper limit constant start_addr_l : integer := 48 ; -- start address index lower limit constant end_addr_b : integer := 47 ; -- end address index upper limit constant end_addr_l : integer := 16 ; -- end address index lower limit constant first_acc_wait_b : integer := 15 ; -- wait states on first access index upper limit constant first_acc_wait_l : integer := 8 ; -- wait states on first access index lower limit constant cycle_wait_b : integer := 7 ; -- wait states per cycle index upper limit constant cycle_wait_l : integer := 0 ; -- wait states per cycle index lower limit ------------------------- function upcore_loadcfg return upcore_bankcfg is file slavememory_cfg : TEXT; variable result : upcore_bankcfg := (others=>(others=>'0')) ; variable memory_cfg_bitvector : bit_vector (start_addr_b downto 0) ; variable mem_bank_counter : INTEGER := 0 ; variable cfgline : LINE ; begin read_memory : FILE_OPEN(slavememory_cfg, "slavememory.cfg.dat", READ_MODE); while (not ENDFILE(slavememory_cfg) and (mem_bank_counter < NUMBANKS)) loop -- read next data line READLINE (slavememory_cfg, cfgline) ; if ( cfgline'LENGTH = 0 ) then next ; elsif ( cfgline (1) = '/' ) then next ; end if ; -- data is a 20 digit (memory_bitvector'LENGTH/4) HEX string HREAD_bv (cfgline , memory_cfg_bitvector ) ; result (mem_bank_counter) := To_StdLogicVector ( memory_cfg_bitvector ); mem_bank_counter := mem_bank_counter + 1 ; end loop; -- read_memory FILE_CLOSE(slavememory_cfg); return result; end upcore_loadcfg; ------------------------- signal memCfg : upcore_bankcfg := upcore_loadcfg ; -- // slavememory.cfg.dat ------------------------- function upcore_loadbank(bank : integer ; bank_string : string(1 to 17); config : upcore_bankcfg ) return upcore_membank is variable result : upcore_membank := (others=>(others=>'0')); file memory_file : TEXT; variable data_line : LINE ; variable memory_bitvector : bit_vector (31 downto 0) ; variable line_counter : INTEGER := 0 ; begin read_slave_bank : FILE_OPEN(memory_file, bank_string, READ_MODE); while not ENDFILE(memory_file) loop READLINE (memory_file, data_line) ; if ( data_line'LENGTH = 0 ) then next ; elsif ( data_line (1) = '/' ) then next ; end if ; HREAD_bv (data_line , memory_bitvector ) ; result (line_counter) := To_StdLogicVector (memory_bitvector) ; line_counter := line_counter + 1 ; end loop ; FILE_CLOSE(memory_file); return result; end upcore_loadbank; ------------------------- ------------------------- function upcore_checkbank(bank : integer ; bank_string : string(1 to 17) ) return upcore_membank is variable config : upcore_bankcfg := upcore_loadcfg ; variable result : upcore_membank := (others=>(others=>'0')); begin -- If end =/= start, read in the memory file (otherwise everything set to zero). if ( conv_integer((config(bank)(start_addr_b downto start_addr_l))) /= conv_integer((config(bank)(end_addr_b downto end_addr_l))) ) then result := upcore_loadbank(bank,bank_string,config); end if ; -- different start and end address return result; end upcore_checkbank; ------------------------- ------------------------- function initialise_memstart return upcore_bankstart_end is variable config : upcore_bankcfg := upcore_loadcfg ; variable result : upcore_bankstart_end := (others=>(others=>'0')) ; begin result(0) := config(0) (start_addr_b downto start_addr_l); result(1) := config(1) (start_addr_b downto start_addr_l); result(2) := config(2) (start_addr_b downto start_addr_l); result(3) := config(3) (start_addr_b downto start_addr_l); result(4) := config(4) (start_addr_b downto start_addr_l); result(5) := config(5) (start_addr_b downto start_addr_l); return result; end initialise_memstart; ------------------------- ------------------------- function initialise_memend return upcore_bankstart_end is variable config : upcore_bankcfg := upcore_loadcfg ; variable result : upcore_bankstart_end := (others=>(others=>'0')) ; begin result(0) := config(0) (end_addr_b downto end_addr_l); result(1) := config(1) (end_addr_b downto end_addr_l); result(2) := config(2) (end_addr_b downto end_addr_l); result(3) := config(3) (end_addr_b downto end_addr_l); result(4) := config(4) (end_addr_b downto end_addr_l); result(5) := config(5) (end_addr_b downto end_addr_l); return result; end initialise_memend; ------------------------- ------------------------- function initialise_memwaitstart return upcore_memwait is variable config : upcore_bankcfg := upcore_loadcfg ; variable result : upcore_memwait := (others=>(others=>'0')) ; begin result(0) := config(0) (first_acc_wait_b downto first_acc_wait_l); result(1) := config(1) (first_acc_wait_b downto first_acc_wait_l); result(2) := config(2) (first_acc_wait_b downto first_acc_wait_l); result(3) := config(3) (first_acc_wait_b downto first_acc_wait_l); result(4) := config(4) (first_acc_wait_b downto first_acc_wait_l); result(5) := config(5) (first_acc_wait_b downto first_acc_wait_l); return result; end initialise_memwaitstart; ------------------------- ------------------------- function initialise_memwait return upcore_memwait is variable config : upcore_bankcfg := upcore_loadcfg ; variable result : upcore_memwait := (others=>(others=>'0')) ; begin result(0) := config(0) (cycle_wait_b downto cycle_wait_l); result(1) := config(1) (cycle_wait_b downto cycle_wait_l); result(2) := config(2) (cycle_wait_b downto cycle_wait_l); result(3) := config(3) (cycle_wait_b downto cycle_wait_l); result(4) := config(4) (cycle_wait_b downto cycle_wait_l); result(5) := config(5) (cycle_wait_b downto cycle_wait_l); return result; end initialise_memwait; ------------------------- signal memStart : upcore_bankstart_end := initialise_memstart ; signal memEnd : upcore_bankstart_end := initialise_memend ; signal memWaitStart : upcore_memwait := initialise_memwaitstart ; signal memWait : upcore_memwait := initialise_memwait ; signal sel : std_logic := '0' ; signal doWork : std_logic := '0' ; signal doBusyWork : std_logic := '0' ; signal seqTrans : std_logic := '0' ; signal wrapmask : std_logic_vector(31 downto 0) := (others=>'0') ; signal wrapmask_w : std_logic_vector(31 downto 0) := (others=>'0') ; signal seqPlusAddr : std_logic_vector(31 downto 0) := (others=>'0') ; signal seqAddr : std_logic_vector(31 downto 0) := (others=>'0') ; signal startNext : std_logic_vector(31 downto 0) := (others=>'0') ; signal addrNext : std_logic_vector(31 downto 0) := (others=>'0') ; signal transNext : std_logic_vector( 1 downto 0) := (others=>'0') ; signal sizeNext : std_logic_vector( 1 downto 0) := (others=>'0') ; signal burstNext : std_logic_vector( 2 downto 0) := (others=>'0') ; signal writeNext : std_logic := '0' ; signal bankA : std_logic := '0' ; signal bankB : std_logic := '0' ; signal bankC : std_logic := '0' ; signal bankD : std_logic := '0' ; signal bankE : std_logic := '0' ; signal bankF : std_logic := '0' ; signal offsetA : std_logic_vector(31 downto 0) := (others=>'0') ; signal offsetB : std_logic_vector(31 downto 0) := (others=>'0') ; signal offsetC : std_logic_vector(31 downto 0) := (others=>'0') ; signal offsetD : std_logic_vector(31 downto 0) := (others=>'0') ; signal offsetE : std_logic_vector(31 downto 0) := (others=>'0') ; signal offsetF : std_logic_vector(31 downto 0) := (others=>'0') ; signal wordA : std_logic_vector(15 downto 0) := (others=>'0') ; signal wordB : std_logic_vector(15 downto 0) := (others=>'0') ; signal wordC : std_logic_vector(15 downto 0) := (others=>'0') ; signal wordD : std_logic_vector(15 downto 0) := (others=>'0') ; signal wordE : std_logic_vector(15 downto 0) := (others=>'0') ; signal wordF : std_logic_vector(15 downto 0) := (others=>'0') ; signal be0 : std_logic := '0' ; signal be1 : std_logic := '0' ; signal be2 : std_logic := '0' ; signal be3 : std_logic := '0' ; signal readDataMask : std_logic_vector(31 downto 0) := (others=>'0') ; signal currentValSig : std_logic_vector(31 downto 0) := (others=>'0') ; -- +--------------+ -- | master port | -- +--------------+ type upcore_transStore is array (NUMTRANS downto 1) of std_logic_vector(Trns_TRANSNUM_l-1 downto 0); ------------------------- function upcore_loadtrans return upcore_transStore is file mastercommands : TEXT ; variable result : upcore_transStore := (others=>(others=>'0')) ; variable commandsline : LINE ; variable transaction_bitvector : bit_vector (Trns_TRANSNUM_l-1 downto 0) ; variable trans_num_iter : INTEGER := 1 ; begin read_commands : FILE_OPEN(mastercommands, "mastercommands.dat", READ_MODE); while not ENDFILE(mastercommands) loop -- read next data line READLINE (mastercommands , commandsline) ; if ( commandsline'LENGTH = 0 ) then next ; elsif ( commandsline (1) = '/' ) then next ; end if ; HREAD_bv (commandsline , transaction_bitvector ) ; result (trans_num_iter) := To_StdLogicVector (transaction_bitvector) ; trans_num_iter := trans_num_iter + 1 ; end loop; -- read_commands FILE_CLOSE(mastercommands); return result; end upcore_loadtrans; ------------------------- -- +-----------------------------------------------------------------+ -- | Transaction records | -- | | -- | The transactor pipeline consists of 4 stages: | -- | | -- | nextTrans - the next transaction from the store | -- | controlTrans - the current control/address stage transaction | -- | dataTrans - the data stage transaction | -- | reportTrans - the completed stage for reporting | -- | | -- | controlTrans is updated from nextTrans when a new transaction | -- | begins or from dataTrans in the case of split/retry | -- | | -- +-----------------------------------------------------------------+ -- dataTrans <= idleTrans ; -- fill pipe with null's -- controlTrans <= idleTrans ; -- reportTrans <= idleTrans ; -- nextTrans <= idleTrans ; -- nextTrans(2) <= '1' ; -- repeat 4 subtype trans_vector is std_logic_vector (Trns_b downto 0) ; ------------------------- function initialise_idle return trans_vector is variable result : trans_vector := (others=>'0') ; begin -- set up a null transaction record result (Trns_TRANSNUM_b downto Trns_TRANSNUM_l ) := (OTHERS => '1') ; result (Trns_TRANSTYPE_b downto Trns_TRANSTYPE_l) := H_IDLE ; return result; end initialise_idle; ------------------------- ------------------------- function initialise_next return trans_vector is variable result : trans_vector := (others=>'0') ; begin -- set up a null transaction record result (Trns_TRANSNUM_b downto Trns_TRANSNUM_l ) := (OTHERS => '1') ; result (Trns_TRANSTYPE_b downto Trns_TRANSTYPE_l) := H_IDLE ; -- repeat 4 result (2) := '1' ; return result; end initialise_next; ------------------------- signal trans_num : std_logic_vector(15 downto 0) := (others=>'0') ; -- limit is 2^16-1 = NUMTRANS signal tmp_transaction : std_logic_vector(Trns_TRANSNUM_l-1 downto 0) := (others=>'0') ; signal currTransNum : std_logic_vector(15 downto 0) := (others=>'0') ; signal tmp_beats : std_logic_vector( 8 downto 0) := (others=>'0') ; signal idleTrans : trans_vector := initialise_idle ; signal controlTrans : trans_vector := initialise_idle ; signal dataTrans : trans_vector := initialise_idle ; signal reportTrans : trans_vector := initialise_idle ; signal retryTrans : trans_vector := initialise_idle ; signal nextTrans : trans_vector := initialise_next ; -- +-----------------------------------------+ -- | Control signals for master transactor | -- +-----------------------------------------+ signal reset : std_logic := '1' ; signal stop : std_logic := '0' ; signal continue_after_error : std_logic := '1' ; signal generate_data : std_logic := '0' ; signal write : std_logic ; signal start : std_logic ; signal go_busy : std_logic ; signal insert_busy : std_logic_vector( 1 downto 0) := "00" ; signal beats : std_logic_vector( 8 downto 0) ; signal start_address : std_logic_vector(31 downto 0) ; signal data : std_logic_vector(31 downto 0) ; signal burst : std_logic_vector( 2 downto 0) ; signal size : std_logic_vector( 2 downto 0) ; signal length : std_logic_vector( 8 downto 0) := (others=>'0') ; signal address_length : std_logic_vector( 8 downto 0) := (others=>'0') ; -- +----------------------------------+ -- | Transactor state and responses | -- +----------------------------------+ signal masterhgrant_in_r : std_logic := '0' ; signal break_wrap : std_logic := '0' ; signal original_burst : std_logic_vector( 2 downto 0) := (others=>'0') ; signal busy_states : std_logic_vector( 1 downto 0) := (others=>'0') ; signal busy_counter : std_logic_vector( 1 downto 0) := (others=>'0') ; signal init_wrap_mask : std_logic_vector( 9 downto 0) := (others=>'0') ; signal wrap_mask : std_logic_vector( 9 downto 0) := (others=>'0') ; signal masterhaddr_out_r_inc : std_logic_vector( 7 downto 0) := (others=>'0') ; signal init_wrap_boundary_bit : std_logic_vector( 7 downto 0) := (others=>'0') ; signal init_next_masterhaddr_out_r : std_logic_vector(10 downto 0) := (others=>'0') ; signal wrap_boundary_bit : std_logic_vector(10 downto 0) := (others=>'0') ; signal next_masterhaddr_out_r : std_logic_vector( 9 downto 0) := (others=>'0') ; signal address_bus_owned : std_logic := '0' ; signal data_bus_owned : std_logic := '0' ; signal add_go : std_logic := '0' ; signal data_go : std_logic := '0' ; signal reading : std_logic := '0' ; signal writing : std_logic := '0' ; signal first_beat : std_logic := '0' ; signal need_retry : std_logic := '0' ; signal wrap : std_logic := '0' ; signal new_grant : std_logic := '0' ; signal first_masterhtrans_out_r : std_logic := '0' ; signal addr_ack : std_logic := '0' ; signal data_ack : std_logic := '0' ; signal add_go_r : std_logic := '0' ; signal replay_wrap : std_logic_vector( 2 downto 0) := (others=>'0') ; -- output signals signal masterhwrite_out : std_logic := '0' ; signal masterhlock_out : std_logic := '0' ; signal masterhbusreq_out : std_logic := '0' ; signal masterhaddr_out : std_logic_vector (31 downto 0) := (others=>'0'); signal masterhwdata_out : std_logic_vector (31 downto 0) := (others=>'0'); signal masterhtrans_out : std_logic_vector ( 1 downto 0) := (others=>'0'); signal masterhsize_out : std_logic_vector ( 1 downto 0) := (others=>'0'); signal masterhburst_out : std_logic_vector ( 2 downto 0) := (others=>'0'); signal slavehrdata_out : std_logic_vector (31 downto 0) := (others=>'0'); signal slavehreadyo_out : std_logic := '0' ; signal slavehresp_out : std_logic_vector ( 1 downto 0) := (others=>'0'); signal slavebuserrint_out : std_logic := '0' ; -- register outputs signal masterhtrans_out_r : std_logic_vector ( 1 downto 0) := (others=>'0'); signal masterhaddr_out_r : std_logic_vector (31 downto 0) := (others=>'0'); signal masterhwdata_out_r : std_logic_vector (31 downto 0) := (others=>'0'); signal masterhburst_out_r : std_logic_vector ( 2 downto 0) := (others=>'0'); signal masterhwrite_out_r : std_logic := '0' ; signal masterhsize_outl : std_logic_vector ( 2 downto 0) := (others=>'0'); -- the transactor implements the full 3 bit size field signal slavehreadyo_out_r : std_logic := '0' ; signal slavehresp_out_r : std_logic_vector ( 1 downto 0) := (others=>'0'); -- bus request signals signal single_beat : std_logic := '0' ; signal last_beat : std_logic := '0' ; signal retry : std_logic := '0' ; signal error : std_logic := '0' ; -- bus request states constant req_idle : std_logic_vector(2 downto 0) := "000"; constant req_first : std_logic_vector(2 downto 0) := "001"; constant req_wait : std_logic_vector(2 downto 0) := "101"; constant req_masterhold : std_logic_vector(2 downto 0) := "011"; constant req_using : std_logic_vector(2 downto 0) := "010"; constant req_again : std_logic_vector(2 downto 0) := "111"; signal req_state : std_logic_vector(2 downto 0) := "000"; signal single_beat_r : std_logic := '0' ; -- complete data phase signals signal trans_end : std_logic := '0' ; -- write data signals signal addr_offset : std_logic_vector( 7 downto 0) := (others=>'0'); signal masterhwdata_out_r_pipe : std_logic_vector(31 downto 0) := (others=>'0'); signal masterhwdata_out_r_retry : std_logic_vector(31 downto 0) := (others=>'0'); -- wait state generation signal s_addr_latch : std_logic := '0' ; -- slave address latched this cycle signal waitStart : std_logic_vector( 7 downto 0) := (others=>'0'); signal waitSeq : std_logic_vector( 7 downto 0) := (others=>'0'); signal waitStartNext : std_logic_vector( 7 downto 0) := (others=>'0'); file results_file : TEXT OPEN WRITE_MODE is "output.dat" ; begin -- Note: in processes where signals are assigned to and used at the same simulation time, -- temporary variables have been created to remove non-determinism as far as possible. -- +==================================================================+ -- | Initialisation : | -- | This process is executed once at the start of run then suspended | -- +==================================================================+ initialisation : process begin -- Unused signals tied off to ground lockgrantdp0 <= '0'; lockgrantdp1 <= '0'; debugack <= '0'; debugrng0 <= '0'; debugrng1 <= '0'; debugextout <= ( others => '0') ; intuart <= '0'; inttimer0 <= '0'; inttimer1 <= '0'; intcommtx <= '0'; intcommrx <= '0'; intproctimer <= '0'; intprocbridge <= '0'; perreset <= '0'; slavehresp_out_r <= H_OKAY; reset <= '1' ; wait for 10 ns ; reset <= '1' ; wait for 20 ns ; reset <= '0' ; wait ; end process initialisation ; -- +---------------------------------------------------------------------------------+ -- | Concurrent Signal Assignments (these will appear as wires in the Verilog model) | -- | also see - 'Slave port implementation' and 'burst mode support' | -- +---------------------------------------------------------------------------------+ start <= nextTrans(Trns_BUSCOMMD ) ; go_busy <= nextTrans(Trns_BUSY ) ; beats <= nextTrans(Trns_NUMSEQBEATS_b downto Trns_NUMSEQBEATS_l) ; burst <= nextTrans(Trns_BURSTTYPE_b downto Trns_BURSTTYPE_l ) ; size <= nextTrans(Trns_SIZE_b downto Trns_SIZE_l ) ; write <= nextTrans(Trns_WRITE ) ; start_address <= nextTrans(Trns_STARTADDR_b downto Trns_STARTADDR_l ) ; data <= nextTrans(Trns_DATA_b downto Trns_DATA_l ) ; -- +----------------------------+ -- | Output Signal Assignments | -- +----------------------------+ -- direct output assignments masterhwrite <= masterhwrite_out ; masterhlock <= masterhlock_out ; masterhbusreq <= masterhbusreq_out ; masterhaddr <= masterhaddr_out ; masterhwdata <= masterhwdata_out ; masterhtrans <= masterhtrans_out ; masterhsize <= masterhsize_out ; masterhburst <= masterhburst_out ; slavehreadyo <= slavehreadyo_out ; slavebuserrint <= slavebuserrint_out ; slavehrdata <= slavehrdata_out ; slavehresp <= slavehresp_out ; -- registered output assignments masterhtrans_out <= masterhtrans_out_r ; masterhaddr_out <= masterhaddr_out_r ; masterhwdata_out <= masterhwdata_out_r ; masterhburst_out <= masterhburst_out_r ; masterhtrans_out <= masterhtrans_out_r ; masterhwrite_out <= masterhwrite_out_r ; masterhsize_out <= masterhsize_outl (1 downto 0); -- upCore only uses 2 bits of the full 3 bit size field slavehreadyo_out <= slavehreadyo_out_r ; slavehresp_out <= slavehresp_out_r ; -- +===============================================+ -- | process NEXTTRANSACTION | -- | | -- | Sets up the next transaction and waits for | -- | it to be accepted (rising edge of clk) | -- +===============================================+ nexttransaction : process -- Some signals are used in checks at current simulation time, t, -- rather than at t+delta, so create temporary variables. This should -- then give the same functionality as the blocking statements in the -- Verilog version of this model. variable temp_nextTrans : trans_vector ; variable temp_tmp_transaction : std_logic_vector(Trns_TRANSNUM_l-1 downto 0) := (others=>'0') ; variable temp_trans_num : std_logic_vector(15 downto 0) := (others=>'0') ; variable temp_tmp_beats : std_logic_vector( 8 downto 0) := (others=>'0') ; variable transactions : upcore_transStore := upcore_loadtrans ; begin while ( conv_integer(trans_num) < NUMTRANS ) loop temp_trans_num := trans_num ; temp_tmp_beats := tmp_beats ; if (conv_integer(nextTrans(Trns_RPTCOUNT_b downto Trns_RPTCOUNT_l)) = 0 ) then -- get the next record out of those read from the mastercommands file temp_trans_num := temp_trans_num + '1' ; -- set temp_tmp_transaction variable now so it can be used straight away in the assignments and checks below. temp_tmp_transaction := transactions(conv_integer(temp_trans_num)) ; temp_nextTrans := nextTrans ; temp_nextTrans(Trns_EXPDATA_b downto Trns_EXPDATA_l ) := temp_tmp_transaction (Trns_DATA_b downto Trns_DATA_l); -- copy data to expected transaction data temp_nextTrans(Trns_TRANSNUM_b downto Trns_TRANSNUM_l) := temp_trans_num ; temp_nextTrans(Trns_TRANSNUM_l-1 downto 0) := temp_tmp_transaction ; -- check for a BUSY if (UNSIGNED(temp_tmp_transaction(Trns_TRANSTYPE_b downto Trns_TRANSTYPE_l)) = UNSIGNED(H_BUSY)) then temp_nextTrans(Trns_BUSY) := '1'; else temp_nextTrans(Trns_BUSY) := '0'; end if ; -- compute the number of beats in burst if ( (UNSIGNED(temp_nextTrans(Trns_BURSTTYPE_b downto Trns_BURSTTYPE_l)) /= UNSIGNED(H_SINGLE)) and (UNSIGNED(temp_nextTrans(Trns_TRANSTYPE_b downto Trns_TRANSTYPE_l)) = UNSIGNED(H_NONSEQ)) ) then temp_tmp_beats := "000000001"; temp_nextTrans(Trns_NUMSEQBEATS_b downto Trns_NUMSEQBEATS_l) := "000000001"; temp_tmp_transaction := transactions(conv_integer(temp_trans_num) + conv_integer(temp_tmp_beats)) ; while ( (UNSIGNED(temp_tmp_transaction(Trns_TRANSTYPE_b downto Trns_TRANSTYPE_l)) = UNSIGNED(H_SEQ) ) or (UNSIGNED(temp_tmp_transaction(Trns_TRANSTYPE_b downto Trns_TRANSTYPE_l)) = UNSIGNED(H_BUSY)) ) loop temp_nextTrans(Trns_NUMSEQBEATS_b downto Trns_NUMSEQBEATS_l) := temp_nextTrans(Trns_NUMSEQBEATS_b downto Trns_NUMSEQBEATS_l) + conv_integer(temp_tmp_transaction(Trns_RPTCOUNT_b downto Trns_RPTCOUNT_l)) + 1 ; temp_tmp_beats := temp_tmp_beats + 1 ; temp_tmp_transaction := transactions(conv_integer(temp_trans_num) + conv_integer(temp_tmp_beats)); end loop ; tmp_beats <= temp_tmp_beats ; end if ; -- update the start address if ( (UNSIGNED(temp_nextTrans(Trns_TRANSTYPE_b downto Trns_TRANSTYPE_l)) /= UNSIGNED(H_SEQ) ) and (UNSIGNED(temp_nextTrans(Trns_TRANSTYPE_b downto Trns_TRANSTYPE_l)) /= UNSIGNED(H_BUSY)) ) then temp_nextTrans(Trns_STARTADDR_b downto Trns_STARTADDR_l) := temp_nextTrans(Trns_ADDR_b downto Trns_ADDR_l); -- start address end if ; -- assign the temporary variables we've been using to the signals they represent nextTrans <= temp_nextTrans ; tmp_transaction <= temp_tmp_transaction ; trans_num <= temp_trans_num ; else nextTrans(Trns_RPTCOUNT_b downto Trns_RPTCOUNT_l) <= nextTrans(Trns_RPTCOUNT_b downto Trns_RPTCOUNT_l)- 1 ; end if ; -- wait for the current transaction to be accepted (rising edge of clk) wait on masterhclk until ( masterhclk = '1' ) ; while ( not ( addr_ack='1' or data_ack='1' ) and nextTrans(Trns_BUSCOMMD)='1') loop wait on masterhclk until ( masterhclk = '1' ) ; end loop ; -- transactions in buffer end loop ; assert FALSE report "Altera BFM stripe-to-PLD transaction list exhausted" severity WARNING; wait; end process nexttransaction ; -- +=============================================================+ -- | process COMPBURSTLEN | -- | | -- | Compute burst length | -- | | -- | add_go_r prevents a newly loaded length being | -- | decremented by the last data beat of the previous | -- | transaction. | -- +=============================================================+ compburstlen : process ( masterhclk , reset ) variable report_string_80 : string(1 to 80) := (others=>' ') ; variable report_string_20 : string(1 to 20) := (others=>' ') ; variable report_string_10 : string(1 to 10) := (others=>' ') ; variable display_line : LINE ; begin if (masterhclk'event) then if (masterhready='1') then add_go_r <= add_go; end if ; end if ; if ( ( masterhclk'event and masterhclk='1') or ( reset'event and reset='1' ) ) then if (reset='1') then length <= "000000000"; elsif (add_go='1') then case burst is when H_SINGLE => length <= "000000001"; when H_INCR => length <= beats ; when H_WRAP4 | H_INCR4 => length <= "000000100"; when H_WRAP8 | H_INCR8 => length <= "000001000"; when H_WRAP16 | H_INCR16 => length <= "000010000"; when others => report_string_80(1 to 21) := "error in burst signal" ; std.textio.write(display_line , report_string_80); std.textio.writeline(results_file, display_line ); end case ; elsif ( (reading = '1' or writing = '1') and masterhready='1' and add_go_r /= '1' and (UNSIGNED(masterhresp)=UNSIGNED(H_OKAY) or UNSIGNED(masterhresp)=UNSIGNED(H_ERROR)) ) then length <= length - ur_OR(length); end if ; if (reset='1') then address_length <= "000000000"; elsif (add_go='1') then case burst is when H_SINGLE => address_length <= "000000001"; when H_INCR => address_length <= beats ; when H_WRAP4 | H_INCR4 => address_length <= "000000100"; when H_WRAP8 | H_INCR8 => address_length <= "000001000"; when H_WRAP16 | H_INCR16 => address_length <= "000010000"; when others => report_string_80(1 to 21) := "error in burst signal" ; std.textio.write(display_line , report_string_80); std.textio.writeline(results_file, display_line ); end case ; elsif ( data_bus_owned = '1' and masterhready /= '1' and (UNSIGNED(masterhresp) = UNSIGNED(H_RETRY) or UNSIGNED(masterhresp) = UNSIGNED(H_SPLIT)) ) then address_length <= address_length + '1' ; elsif ( address_bus_owned = '1' and masterhready = '1' and ur_OR (busy_states) /= '1' and UNSIGNED(masterhtrans_out_r) /= UNSIGNED(H_IDLE)) then address_length <= address_length - ur_OR (address_length); elsif ( address_bus_owned = '1' and masterhready = '1' and ur_OR (busy_states) = '1' and UNSIGNED(masterhtrans_out_r) = UNSIGNED(H_BUSY) and ur_OR (busy_counter) /= '1' ) then address_length <= address_length - ur_OR (address_length); end if ; end if ; end process compburstlen ; -- +-----------------------------------------------------------+ -- | Slave port implementation : concurrent signal assignments | -- +-----------------------------------------------------------+ -- select signal sel <= slavehsel and slavehreadyi; -- determine if the transaction includes an operation / a "busy" doWork <= '1' when ( selReg='1' and ( transReg=conv_integer(H_NONSEQ) or transReg=conv_integer(H_SEQ)) ) else '0'; doBusyWork <= '1' when ( selReg='1' and transReg=conv_integer(H_BUSY) ) else '0'; -- +--------------------------------------------------+ -- | BURST MODE SUPPORT | -- | | -- | If we are in burst mode we'll compute our own | -- | address and control settings based on the spec. | -- | | -- | compute values SEQuential (burst) transfers | -- +--------------------------------------------------+ seqTrans <= '1' when selReg='1' and ( doWork='1' or doBusyWork='1') and (slavehtrans=conv_integer(H_SEQ) or slavehtrans=conv_integer(H_BUSY)) else '0'; with burstReg select wrapmask <= (1 downto 0=>'0', others=>'1') when H_WRAP4 , (2 downto 0=>'0', others=>'1') when H_WRAP8 , (2 downto 0=>'0', others=>'1') when H_WRAP16 , (others=>'0') when others ; with sizeReg select wrapmask_w <= shift_left(wrapmask, 2) when H_WORD , shift_left(wrapmask, 1) when H_HWORD , wrapmask when others ; with sizeReg select seqPlusAddr<= addrReg + 1 when H_BYTE , addrReg + 2 when H_HWORD , addrReg + 4 when H_WORD , addrReg when others ; seqAddr <= addrReg when slavehtrans = conv_integer(H_BUSY) or burstReg = conv_integer(H_SINGLE) else (startReg and wrapmask_w) or (seqPlusAddr and (not(wrapmask_w))); -- if this is a sequential transaction only sample HTRANS startNext <= startReg when seqTrans='1' else slavehaddr ; addrNext <= seqAddr when seqTrans='1' else slavehaddr ; transNext <= slavehtrans; sizeNext <= sizeReg when seqTrans='1' else slavehsize ; burstNext <= burstReg when seqTrans='1' else slavehburst ; writeNext <= writeReg when seqTrans='1' else slavehwrite ; -- +==============================================================+ -- | | -- | process CTRLLATCH : | -- | | -- | Latch the control data if we are selected | -- | | -- +==============================================================+ ctrllatch: process ( slavehclk ) begin if ( slavehclk'event and slavehclk='1') then -- if read is low another device is wait stating its -- data phase and hence extending our address phase if ( slavehreadyi = '1' ) then selReg <= sel; if ( sel = '1' ) then -- latch the control data startReg <= startNext ; addrReg <= addrNext ; transReg <= transNext ; sizeReg <= sizeNext ; writeReg <= writeNext ; burstReg <= burstNext ; else startReg <= (others=>'0'); addrReg <= (others=>'0'); transReg <= H_IDLE ; sizeReg <= H_WORD ; writeReg <= '0' ; burstReg <= H_SINGLE ; end if; end if; end if; end process ctrllatch; bankA <= '1' when ( conv_integer(addrReg) >= memStart(0) and conv_integer(addrReg) <= memEnd(0) and conv_integer(memStart(0)) /= memEnd(0) ) else '0'; bankB <= '1' when ( conv_integer(addrReg) >= memStart(1) and conv_integer(addrReg) <= memEnd(1) and conv_integer(memStart(1)) /= memEnd(1) ) else '0'; bankC <= '1' when ( conv_integer(addrReg) >= memStart(2) and conv_integer(addrReg) <= memEnd(2) and conv_integer(memStart(2)) /= memEnd(2) ) else '0'; bankD <= '1' when ( conv_integer(addrReg) >= memStart(3) and conv_integer(addrReg) <= memEnd(3) and conv_integer(memStart(3)) /= memEnd(3) ) else '0'; bankE <= '1' when ( conv_integer(addrReg) >= memStart(4) and conv_integer(addrReg) <= memEnd(4) and conv_integer(memStart(4)) /= memEnd(4) ) else '0'; bankF <= '1' when ( conv_integer(addrReg) >= memStart(5) and conv_integer(addrReg) <= memEnd(5) and conv_integer(memStart(5)) /= memEnd(5) ) else '0'; -- byte offset into bank -- word offset into bank offsetA <= addrReg - memStart(0); wordA <= offsetA(17 downto 2); offsetB <= addrReg - memStart(1); wordB <= offsetB(17 downto 2); offsetC <= addrReg - memStart(2); wordC <= offsetC(17 downto 2); offsetD <= addrReg - memStart(3); wordD <= offsetD(17 downto 2); offsetE <= addrReg - memStart(4); wordE <= offsetE(17 downto 2); offsetF <= addrReg - memStart(5); wordF <= offsetF(17 downto 2); -- byte enables be0<= '1' when ( UNSIGNED(sizeReg)=UNSIGNED(H_WORD) or ( UNSIGNED(sizeReg)=UNSIGNED(H_HWORD) and addrReg(1)='0' ) or ( UNSIGNED(sizeReg)=UNSIGNED(H_BYTE) and UNSIGNED(addrReg(1 downto 0))=0) ) else '0'; be1<= '1' when ( UNSIGNED(sizeReg)=UNSIGNED(H_WORD) or ( UNSIGNED(sizeReg)=UNSIGNED(H_HWORD) and addrReg(1)='0' ) or ( UNSIGNED(sizeReg)=UNSIGNED(H_BYTE) and UNSIGNED(addrReg(1 downto 0))=1) ) else '0'; be2<= '1' when ( UNSIGNED(sizeReg)=UNSIGNED(H_WORD) or ( UNSIGNED(sizeReg)=UNSIGNED(H_HWORD) and addrReg(1)='1' ) or ( UNSIGNED(sizeReg)=UNSIGNED(H_BYTE) and UNSIGNED(addrReg(1 downto 0))=2) ) else '0'; be3<= '1' when ( UNSIGNED(sizeReg)=UNSIGNED(H_WORD) or ( UNSIGNED(sizeReg)=UNSIGNED(H_HWORD) and addrReg(1)='1' ) or ( UNSIGNED(sizeReg)=UNSIGNED(H_BYTE) and UNSIGNED(addrReg(1 downto 0))=3) ) else '0'; readDataMask( 7 downto 0) <= "11111111" when ( be0='1' ) else "00000000" ; readDataMask(15 downto 8) <= "11111111" when ( be1='1' ) else "00000000" ; readDataMask(23 downto 16) <= "11111111" when ( be2='1' ) else "00000000" ; readDataMask(31 downto 24) <= "11111111" when ( be3='1' ) else "00000000" ; -- +=================================+ -- | process waitgen | -- | | -- | wait state generation | -- +=================================+ waitstartgen : process (bankA, bankB, bankC, bankD, bankE, bankF ) begin if (bankA='1') then waitStart <= memWaitStart(0); elsif (bankB='1') then waitStart <= memWaitStart(1); elsif (bankC='1') then waitStart <= memWaitStart(2); elsif (bankD='1') then waitStart <= memWaitStart(3); elsif (bankE='1') then waitStart <= memWaitStart(4); elsif (bankF='1') then waitStart <= memWaitStart(5); end if ; end process waitstartgen ; waitseqgen : process (bankA, bankB, bankC, bankD, bankE, bankF ) begin if (bankA='1') then waitSeq <= memWait(0); elsif (bankB='1') then waitSeq <= memWait(1); elsif (bankC='1') then waitSeq <= memWait(2); elsif (bankD='1') then waitSeq <= memWait(3); elsif (bankE='1') then waitSeq <= memWait(4); elsif (bankF='1') then waitSeq <= memWait(5); end if ; end process waitseqgen ; -- +==================================================================+ -- | slave wait processes | -- | | -- | wait if | -- | first beat and memWaitStart and addr has just been latched | -- | or | -- | first beat and waitReg (more than 1 wait state) | -- | or | -- | seq beat and waitReg | -- | else ready | -- +==================================================================+ slavelatch : process ( slavehclk ) begin if ( slavehclk'event and slavehclk='1') then s_addr_latch <= slavehreadyi and slavehsel; end if ; end process slavelatch ; slavewait : process ( doWork, transReg, waitReg, waitStart, s_addr_latch ) variable report_string_20 : string(1 to 20) := (others=>' ') ; variable display_line : LINE ; begin if (doWork='1' and UNSIGNED(transReg)=UNSIGNED(H_NONSEQ) and UNSIGNED(waitStart)/=0 and s_addr_latch='1' ) then slavehreadyo_out_r <= '0' ; --report_string_20 := "SLAVE: wait on first" ; --std.textio.write (display_line , report_string_20); --std.textio.writeline (results_file, display_line ); elsif (doWork='1' and UNSIGNED(transReg)=UNSIGNED(H_NONSEQ) and UNSIGNED(waitReg)/=0 ) then slavehreadyo_out_r <= '0' ; --report_string_20 := "SLAVE: wait " ; --std.textio.write (display_line , report_string_20); --std.textio.writeline (results_file, display_line ); elsif (doWork='1' and UNSIGNED(transReg)=UNSIGNED(H_SEQ) and UNSIGNED(waitReg)/=0) then slavehreadyo_out_r <= '0' ; --report_string_20 := "SLAVE: wait " ; --std.textio.write (display_line , report_string_20); --std.textio.writeline (results_file, display_line ); else slavehreadyo_out_r <= '1' ; end if ; end process slavewait ; -- if we are waiting (waitReg>0) and not in a busy decrement the counter -- otherwise get the new value from memWait of memWaitStart according to -- the transaction type waitStartNext <= waitStart - 1 when ( UNSIGNED(waitStart) > 1 ) else "00000000"; slavewaitreg : process ( slavehclk ) begin if ( slavehclk'event and slavehclk='1') then if (UNSIGNED(waitReg) /= 0 and doBusyWork/='1') then waitReg <= waitReg - '1' ; elsif (doWork='1' and UNSIGNED(transReg)=UNSIGNED(H_NONSEQ) and UNSIGNED(waitStart)/=0 and s_addr_latch='1' ) then waitReg <= waitStartNext ; elsif (seqTrans='1' ) then waitReg <= waitSeq ; else waitReg <= "00000000" ; end if ; end if ; end process slavewaitreg ; -- read data slavehrdata_out <= (readDataMask and currentValSig) when (doWork='1' and writeReg/='1' and slavehreadyo_out_r='1') else (others=>'0'); -- +===========================================================================+ -- | | -- | process MEMWORK : | -- | | -- | + records reads and writes in memory banks | -- | + writes a text report to the screen | -- | | -- +===========================================================================+ memwork : process ( slavehclk , wordA, wordB, wordC, wordD, wordE, wordF, bankA, bankB, bankC, bankD, bankE, bankF) variable memMapA : upcore_membank := upcore_checkbank(0,"slavememory.0.dat") ; variable memMapB : upcore_membank := upcore_checkbank(1,"slavememory.1.dat") ; variable memMapC : upcore_membank := upcore_checkbank(2,"slavememory.2.dat") ; variable memMapD : upcore_membank := upcore_checkbank(3,"slavememory.3.dat") ; variable memMapE : upcore_membank := upcore_checkbank(4,"slavememory.4.dat") ; variable memMapF : upcore_membank := upcore_checkbank(5,"slavememory.5.dat") ; variable report_string_11 : string(1 to 11) := (others=>' ') ; variable report_string_10 : string(1 to 10) := (others=>' ') ; variable report_string_9 : string(1 to 9) := (others=>' ') ; variable report_string_8 : string(1 to 8) := (others=>' ') ; variable report_string_6 : string(1 to 6) := (others=>' ') ; variable display_line : LINE ; variable decimal : BOOLEAN := FALSE ; variable temp_memWord : std_logic_vector(31 downto 0) ; variable currentVal : std_logic_vector(31 downto 0) := (others=>'0') ; begin if (bankA='1' and conv_integer(wordA)< membank_size ) then currentVal := memMapA(conv_integer(wordA)) ; elsif (bankB='1' and conv_integer(wordB)< membank_size ) then currentVal := memMapB(conv_integer(wordB)) ; elsif (bankC='1' and conv_integer(wordC)< membank_size ) then currentVal := memMapC(conv_integer(wordC)) ; elsif (bankD='1' and conv_integer(wordD)< membank_size ) then currentVal := memMapD(conv_integer(wordD)) ; elsif (bankE='1' and conv_integer(wordE)< membank_size ) then currentVal := memMapE(conv_integer(wordE)) ; elsif (bankF='1' and conv_integer(wordF)< membank_size ) then currentVal := memMapF(conv_integer(wordF)) ; end if; currentValSig <= currentVal; if ( slavehclk'event and slavehclk='1') then if (doWork='1' and slavehreadyo_out_r='1') then temp_memWord := currentVal ; if (writeReg='1') then if (be0='1') then temp_memWord( 7 downto 0) := slavehwdata( 7 downto 0); end if; if (be1='1') then temp_memWord(15 downto 8) := slavehwdata(15 downto 8); end if; if (be2='1') then temp_memWord(23 downto 16) := slavehwdata(23 downto 16); end if; if (be3='1') then temp_memWord(31 downto 24) := slavehwdata(31 downto 24); end if; if (bankA='1') then memMapA(conv_integer(wordA)) := temp_memWord; end if; if (bankB='1') then memMapB(conv_integer(wordB)) := temp_memWord; end if; if (bankC='1') then memMapC(conv_integer(wordC)) := temp_memWord; end if; if (bankD='1') then memMapD(conv_integer(wordD)) := temp_memWord; end if; if (bankE='1') then memMapE(conv_integer(wordE)) := temp_memWord; end if; if (bankF='1') then memMapF(conv_integer(wordF)) := temp_memWord; end if; end if; -- display a text report on screen report_string_10 := "SLAVE: " ; std.textio.write (display_line , report_string_10); report_string_10 := " " ; std.textio.write (display_line , report_string_10); report_string_9 := " addr=[" ; std.textio.write (display_line , report_string_9); if (decimal) then std.textio.write (display_line, conv_integer(addrReg),right,8); else IEEE.std_logic_textio.hwrite (display_line,addrReg,right,8); end if ; if (writeReg = '1') then report_string_8 := "] WRITE " ; else report_string_8 := "] READ " ; end if; std.textio.write (display_line, report_string_8); report_string_6 := "data=[" ; std.textio.write (display_line , report_string_6); if (writeReg='1') then if (decimal) then std.textio.write (display_line, conv_integer(slavehwdata),right,8); else IEEE.std_logic_textio.hwrite (display_line,slavehwdata,right,8); end if ; else if (decimal) then std.textio.write (display_line, conv_integer(slavehrdata_out),right,8); else IEEE.std_logic_textio.hwrite (display_line,slavehrdata_out,right,8); end if ; end if; report_string_6 := "] " ; std.textio.write (display_line , report_string_6); report_string_11 := " " ; std.textio.write (display_line , report_string_11); report_string_10 := " " ; std.textio.write (display_line , report_string_10); case sizeReg is when H_BYTE => report_string_10 := " BYTE " ; when H_HWORD=> report_string_10 := "HALF WORD " ; when H_WORD => report_string_10 := " WORD " ; when others => report_string_10 := " " ; end case; std.textio.write (display_line , report_string_10); std.textio.writeline(results_file, display_line ); end if; end if; end process memwork; -- +==========================================+ -- | | -- | process reportcomptrans : | -- | | -- | Report completed transactions | -- | | -- +==========================================+ reportcomptrans : process ( masterhclk ) variable report_string_14 : string(1 to 14) := (others=>' ') ; variable report_string_9 : string(1 to 9 ) := (others=>' ') ; variable report_string_7 : string(1 to 7 ) := (others=>' ') ; variable display_line : LINE ; variable decimal : BOOLEAN := FALSE ; begin if ( masterhclk'event and masterhclk='1') then if (reportTrans(Trns_BUSCOMMD)='1') then report_string_7 := "MASTER:" ; std.textio.write (display_line, report_string_7); report_string_9 := " trans=[ " ; std.textio.write (display_line, report_string_9); std.textio.write (display_line, conv_integer(reportTrans(Trns_TRANSNUM_b downto Trns_TRANSNUM_l)),right,4); report_string_9 := "] addr=[" ; std.textio.write (display_line, report_string_9); if (decimal) then std.textio.write (display_line, conv_integer(reportTrans(Trns_ADDR_b downto Trns_ADDR_l)),right,8); else IEEE.std_logic_textio.hwrite (display_line, reportTrans(Trns_ADDR_b downto Trns_ADDR_l),right,8); end if ; if (reportTrans(Trns_WRITE) = '1') then report_string_14 := "] WRITE data=[" ; std.textio.write (display_line, report_string_14); if (decimal) then std.textio.write (display_line, conv_integer(reportTrans(Trns_DATA_b downto Trns_DATA_l)),right,8); else IEEE.std_logic_textio.hwrite (display_line, reportTrans(Trns_DATA_b downto Trns_DATA_l),right,8); end if ; else report_string_14 := "] READ data=[" ; std.textio.write (display_line, report_string_14); if (decimal) then std.textio.write (display_line, conv_integer(reportTrans(Trns_READ_b downto Trns_READ_l)),right,8); else IEEE.std_logic_textio.hwrite (display_line, reportTrans(Trns_READ_b downto Trns_READ_l),right,8); end if ; end if; report_string_14 := "] expected=[" ; std.textio.write (display_line, report_string_14); if (decimal) then std.textio.write (display_line, conv_integer(reportTrans(Trns_EXPDATA_b downto Trns_EXPDATA_l)),right,8); else IEEE.std_logic_textio.hwrite (display_line, reportTrans(Trns_EXPDATA_b downto Trns_EXPDATA_l),right,8); end if ; case reportTrans(Trns_SIZE_b-1 downto Trns_SIZE_l) -- (only 2 of the 3 bits are used) is when H_BYTE => report_string_14 := "] BYTE" ; when H_HWORD => report_string_14 := "] HALF WORD" ; when H_WORD => report_string_14 := "] WORD" ; when others => report_string_14 := "] " ; end case; std.textio.write (display_line , report_string_14); if (UNSIGNED(reportTrans(Trns_RESP_b downto Trns_RESP_l))=UNSIGNED(H_OKAY) ) then report_string_9 := " OKAY " ; else report_string_9 := " ERROR " ; end if ; std.textio.write (display_line , report_string_9); std.textio.writeline(results_file, display_line ); end if; end if; end process reportcomptrans; -- +====================================================================================+ -- | | -- | process BUSREQUEST : | -- | | -- | Bus request state machine | -- | | -- | Bus request machine follows the principle that the arbiter will generally | -- | only re-assign bus grants at the end of a burst transaction. For defined | -- | bursts masterhbusreq_out is removed as soon as we masterhave started the | -- | transaction. Undefined (INCR) bursts will masterhold masterhbusreq_out | -- | asserted until the last beat of the transaction. | -- | | -- | Locked transactions must always assert masterhlock_out for at least one | -- | cycle before the address to be locked to allow the arbiter to see the lock. | -- | In practice, this means inserting an idle cycle. | -- | | -- | Have to be careful using burst and beats from the control word. As soon | -- | as the master address phase masterhas finished and the addr_ack is asserted | -- | the testbench can change the control word. So don't use them after the | -- | initial request. Use the ahb outputs instead which will tell us what sort | -- | of transaction we're doing. | -- | | -- | Bus request machine master has 5 states: | -- | | -- | 1) req_idle: masterhbusreq_out negated. When we want to do something | -- | we jump to req_first. The last beat may get a retry | -- | response in which case we jump to req_again. | -- | | -- | 2) req_first: masterhbusreq_out asserted. Wait here for masterhgrant | -- | and until the transaction starts. If granted and it's an | -- | undefined and not a single beat then jump to req_masterhold. | -- | Else if it's a single beat jump to req_idle. Otherwise jump | -- | to req_using. | -- | | -- | 3) req_masterhold: masterhbusreq_out asserted. Hold masterhbusreq_out | -- | asserted until last beat of an undefined. If there's a | -- | new request then we jump to req_first, otherwise back to | -- | req_idle. If we lose masterhgrant in this state then we | -- | just stay here with masterhbusreq_out asserted until the | -- | transaction can be finished. Also hold in this state if | -- | retry is asserted to reduce the chance of releaseing the | -- | bus and having to re-request it to complete a transaction. | -- | | -- | 4) req_using: masterhbusreq_out negated. Wait here for last beat of | -- | defined length transaction. If there's a new request then | -- | we jump to req_first, otherwise back to req_idle. If a | -- | posted write is errored before the last beat or a transaction | -- | is retried or we lose masterhgrant then we jump to | -- | req_again. | -- | | -- | 5) req_again: masterhbusreq_out asserted for completion of transaction | -- | interrupted by loss of masterhgrant. Wait here for | -- | masterhgrant and until the transaction starts then | -- | jump to req_using if first_beat is asserted or | -- | req_masterhold if not. | -- | *** We may see a new address toggle whilst in this state. | -- | | -- +====================================================================================+ single_beat <= '1' when (UNSIGNED(burst)=UNSIGNED(H_SINGLE) or (UNSIGNED(burst)=UNSIGNED(H_INCR) and UNSIGNED(beats)=1)) else '0' ; last_beat <= '1' when (address_bus_owned='1' and masterhready='1' and UNSIGNED(address_length) <= 1) else '0' ; retry <= '1' when (data_bus_owned='1' and (UNSIGNED(masterhresp)=UNSIGNED(H_RETRY) or UNSIGNED(masterhresp)=UNSIGNED(H_SPLIT))) else '0' ; error <= '1' when (data_bus_owned='1' and masterhready='1' and UNSIGNED(masterhresp)=UNSIGNED(H_ERROR)) else '0' ; masterhbusreq_out <= '1' when ( (start = '1' ) or (UNSIGNED(req_state) = UNSIGNED(req_first) ) or (UNSIGNED(req_state) = UNSIGNED(req_wait) ) or (UNSIGNED(req_state) = UNSIGNED(req_masterhold)) or (UNSIGNED(req_state) = UNSIGNED(req_again) ) ) else '0' ; busrequest : process ( masterhclk , reset) begin if (masterhclk'event and masterhclk = '1') then if (addr_ack='1') then -- save single_beat for use after it may have changed single_beat_r <= single_beat; end if ; end if ; if ( (masterhclk'event and masterhclk = '1') or (reset'event and reset = '1') ) then if (reset='1') then req_state <= req_idle; else case req_state is when req_idle => if (retry='1') then req_state <= req_again; elsif (start='1') then req_state <= req_first; else req_state <= req_idle ; end if ; when req_first => if (retry='1') then req_state <= req_again; elsif (masterhgrant/='1' and not (UNSIGNED(masterhtrans_out_r)=UNSIGNED(H_NONSEQ) and masterhready='1')) then req_state <= req_first; elsif (UNSIGNED(masterhtrans_out_r)=UNSIGNED(H_NONSEQ) and masterhready='1') then if (add_go='1') then req_state <= req_first; elsif (UNSIGNED(burst)=UNSIGNED(H_INCR) and single_beat/='1') then req_state <= req_masterhold; elsif (single_beat='1') then req_state <= req_idle; else req_state <= req_using; end if ; else req_state <= req_wait; end if ; when req_wait => if (retry='1') then req_state <= req_again; elsif (masterhgrant/='1' and not (UNSIGNED(masterhtrans_out_r)=UNSIGNED(H_NONSEQ) and masterhready='1')) then req_state <= req_first; elsif (masterhgrant='1' and not (UNSIGNED(masterhtrans_out_r)=UNSIGNED(H_NONSEQ) and masterhready='1')) then req_state <= req_wait; elsif (add_go='1') then req_state <= req_first; elsif (UNSIGNED(burst)=UNSIGNED(H_INCR) and single_beat/='1') then req_state <= req_masterhold; elsif (single_beat_r='1') then req_state <= req_idle; else req_state <= req_using; end if ; when req_masterhold => if (error='1' and continue_after_error/='1') then req_state <= req_idle; elsif ( (masterhgrant/='1' and (conv_integer(address_length) > 1 )) or retry='1' ) then req_state <= req_again; elsif (last_beat='1') then if (start='1') then req_state <= req_first; else req_state <= req_idle; end if ; elsif (add_go='1') then req_state <= req_first; else req_state <= req_masterhold; end if ; when req_using => if (error='1' and continue_after_error/='1') then req_state <= req_idle; elsif (last_beat='1') then if (start='1') then req_state <= req_first; else req_state <= req_idle; end if ; elsif ( (masterhgrant/='1' and (conv_integer(address_length) > 1 )) or retry='1') then req_state <= req_again; else req_state <= req_using; end if ; when req_again => if (error='1' and continue_after_error/='1') then req_state <= req_idle; elsif ( ( (data_bus_owned/='1') or (data_bus_owned='1' and (UNSIGNED(masterhresp) = UNSIGNED(H_OKAY))) ) and address_bus_owned='1' and UNSIGNED(masterhtrans_out_r)=UNSIGNED(H_IDLE) and masterhready='1' and masterhlock_out/='1') then req_state <= req_idle; elsif ( (masterhgrant/='1' and (conv_integer(address_length) > 1 )) or (not ((UNSIGNED(masterhtrans_out_r)=UNSIGNED(H_NONSEQ)) and (masterhready='1'))) ) then req_state <= req_again; elsif ( ( (last_beat='1') or (UNSIGNED(masterhburst_out_r)=UNSIGNED(H_SINGLE))) or ( (UNSIGNED(masterhburst_out_r)=UNSIGNED(H_INCR)) and (single_beat_r='1')) ) then req_state <= req_idle; elsif (first_beat='1') then req_state <= req_using; else req_state <= req_masterhold; end if ; when others => req_state <= req_idle; end case ; end if ; end if ; end process busrequest ; -- +------------------------------------------------------+ -- | Address and Data acknowledge assignments | -- | | -- | Signals when an address has been transferred and a | -- | new one may be presented for the next transaction. | -- +------------------------------------------------------+ addr_ack <= add_go ; data_ack <= data_go ; -- +======================================================+ -- | process busownership | -- | | -- | Data bus ownership follows address by one cycle | -- +======================================================+ busownership : process (masterhclk, reset) begin if ( ( masterhclk'event and masterhclk='1') or ( reset'event and reset='1' ) ) then if ( reset ='1' ) then address_bus_owned <= '0' ; data_bus_owned <= '0' ; elsif (masterhready ='1' ) then address_bus_owned <= masterhgrant; data_bus_owned <= address_bus_owned; end if ; end if ; end process busownership ; -- +===============================================================+ -- | process ENABLEADDRESSPHASE | -- | | -- | add_go enables the address phase for a new transaction | -- | (not the continuation of a retried transaction or a | -- | transaction during which we lose the bus). | -- | It asserts immediately on address request if we're not | -- | actively using the bus and not waiting for it to be | -- | re-granted to complete a previous transaction, the | -- | (masterhtrans_out_r = IDLE) | -- | term ensuring it only asserts for one clock. | -- +===============================================================+ enableaddressphase : process (start, masterhbusreq_out, masterhgrant, masterhready, reading, writing, masterhtrans_out_r, req_state, length, reset ) begin if ( start = '1' and masterhbusreq_out = '1' and masterhgrant = '1' and masterhready = '1' and reading /= '1' and writing /= '1' and UNSIGNED(masterhtrans_out_r)=UNSIGNED(H_IDLE) and UNSIGNED(req_state) /=UNSIGNED(req_again) and reset /= '1' ) then add_go <= '1' ; elsif ( start = '1' and masterhbusreq_out = '1' and masterhgrant = '1' and masterhready = '1' and conv_integer(length) < 2 and retry /= '1' and UNSIGNED(masterhtrans_out_r)/=UNSIGNED(H_BUSY) and UNSIGNED(masterhtrans_out_r)/=UNSIGNED(H_NONSEQ) and reset /= '1' ) then add_go <= '1' ; else add_go <= '0' ; end if ; end process enableaddressphase ; -- +=================================================================+ -- | process COMPLETEDATAPHASE | -- | | -- | data_go indicates the completion of the data phase for a | -- | transaction. Like add_go it asserts when the master | -- | takes control of the address lines to start a transaction. | -- | It also asserts on all the accepted data beats of a burst | -- | except the last. | -- +=================================================================+ updatetrans_end : process ( data_bus_owned, reading, writing, masterhready, masterhresp ) variable boolean_1 : std_logic ; begin if (UNSIGNED(masterhresp)=UNSIGNED(H_OKAY) or UNSIGNED(masterhresp)=UNSIGNED(H_ERROR)) then boolean_1 := '1' ; else boolean_1 := '0' ; end if ; trans_end <= ( data_bus_owned and (reading or writing) and masterhready and boolean_1 ) ; end process updatetrans_end ; completedataphase : process (start, masterhbusreq_out, writing, reset, reading, masterhgrant, req_state, trans_end, length, masterhready, need_retry, masterhtrans_out_r ) begin if ( start = '1' and masterhbusreq_out = '1' and masterhgrant = '1' and masterhready = '1' and reading /= '1' and writing /= '1' and UNSIGNED(masterhtrans_out_r) = UNSIGNED(H_IDLE) and UNSIGNED(req_state) /= UNSIGNED(req_again) and reset /= '1' and need_retry /= '1' ) then data_go <= '1' ; elsif ( start = '1' and masterhbusreq_out = '1' and masterhgrant = '1' and masterhready = '1' and conv_integer(address_length) > 1 and retry /= '1' and reset /= '1' and (need_retry/='1' or trans_end='1') ) then data_go <= '1' ; else data_go <= '0' ; end if ; end process completedataphase ; -- +======================================================+ -- | process UPDATES | -- | | -- | update masterhwrite_out_r, Transaction size, | -- | busy state and counter on leading edge of clock | -- | or reset | -- +======================================================+ updates : process ( masterhclk, reset ) begin if ( ( masterhclk'event and masterhclk='1') or ( reset'event and reset='1' ) ) then -- +------------------------------------------------------+ -- | masterhwrite_out_r update | -- | | -- | Updated on any clock that starts a new transaction | -- +------------------------------------------------------+ if ( reset='1' ) then masterhwrite_out_r <= '1' ; elsif ( addr_ack='1' ) then masterhwrite_out_r <= write ; end if ; -- +------------------------------------------------------+ -- | Transaction size update | -- | | -- | Updated on any clock that starts a new transaction | -- +------------------------------------------------------+ if ( reset ='1' ) then masterhsize_outl <= "000" ; elsif ( addr_ack ='1' ) then masterhsize_outl <= size ; end if ; -- +------------------------------------------------------+ -- | Busy state and counter update | -- | | -- | Insert BUSY states into burst transactions. | -- | Capture control word. Load counter on every active | -- | phase and decrement to zero. | -- +------------------------------------------------------+ if ( reset ='1' ) then busy_states <= "00" ; elsif ( addr_ack ='1' ) then busy_states <= insert_busy ; end if ; if ( reset ='1' ) then busy_counter <= "00" ; elsif ((UNSIGNED(masterhtrans_out_r)=UNSIGNED(H_NONSEQ)) or (UNSIGNED(masterhtrans_out_r) = UNSIGNED(H_SEQ))) then busy_counter <= busy_states - 1; else busy_counter <= busy_counter - ur_OR(busy_counter); end if ; end if ; end process updates ; -- +=================================================================+ -- | RESTART TRANS processes | -- | | -- | first_masterhtrans_out_r is asserted to enable the first beat | -- | of a transaction addr_ack (which is always NONSEQ) to : | -- | + restart a transaction that was interrupted by loss | -- | of masterhgrant if we receive a new masterhgrant | -- | whilst in req_again or req_masterhold states. | -- | + restart a transaction after a RETRY response. | -- | + restart a transaction after a SPLIT response. | -- | + break an undefined INCR replay of a retried or split | -- | wrapping burst at the wrap address boundary. | -- +-----------------------------------------------------------------+ restarttrans : process (masterhclk, reset) variable masterhgrant_in_leading_edge : std_logic := '0' ; begin if ( masterhclk'event and masterhclk ='1') then masterhgrant_in_r <= masterhgrant; end if ; masterhgrant_in_leading_edge := masterhgrant and not masterhgrant_in_r ; if ( ( masterhclk'event and masterhclk ='1') or ( reset'event and reset='1' ) ) then if (reset = '1') then new_grant <= '0' ; elsif (masterhgrant_in_leading_edge = '1' and first_masterhtrans_out_r /= '1') then new_grant <= '1' ; elsif (first_masterhtrans_out_r = '1' or masterhgrant /= '1') then new_grant <= '0' ; end if ; end if ; end process restarttrans ; updatefirst_masterhtrans_out_r : process ( addr_ack, masterhgrant, masterhgrant_in_r, new_grant, masterhready, masterhwrite_out_r, first_beat, data_bus_owned, address_bus_owned, length, masterhresp, req_state) variable boolean_1 : std_logic := '0' ; variable boolean_2 : std_logic := '0' ; variable boolean_3 : std_logic := '0' ; variable boolean_4 : std_logic := '0' ; variable boolean_5 : std_logic := '0' ; variable masterhgrant_in_leading_edge : std_logic := '0' ; begin -- convert booleans in expression to '1's or '0's masterhgrant_in_leading_edge := masterhgrant and not masterhgrant_in_r ; if (UNSIGNED(req_state) =UNSIGNED(req_masterhold)) then boolean_1 := '1' ; else boolean_1 := '0' ; end if ; if (UNSIGNED(req_state) =UNSIGNED(req_again) ) then boolean_2 := '1' ; else boolean_2 := '0' ; end if ; if (UNSIGNED(masterhresp)=UNSIGNED(H_RETRY) ) then boolean_3 := '1' ; else boolean_3 := '0' ; end if ; if (UNSIGNED(masterhresp)=UNSIGNED(H_SPLIT) ) then boolean_4 := '1' ; else boolean_4 := '0' ; end if ; if (conv_integer(length) > 1 ) then boolean_5 := '1' ; else boolean_5 := '0' ; end if ; first_masterhtrans_out_r <= (addr_ack or ((((masterhgrant_in_leading_edge or (masterhgrant and new_grant)) and masterhready) and (not masterhwrite_out_r)) and (boolean_1 or boolean_2)) or ((masterhgrant_in_leading_edge or (masterhgrant and new_grant)) and (masterhready and masterhwrite_out_r) and (boolean_1 or boolean_2) ) or ((data_bus_owned and masterhready) and (boolean_3 or boolean_4))) or (((address_bus_owned and masterhready) and (not first_beat)) and (break_wrap and boolean_5)); end process updatefirst_masterhtrans_out_r ; -- +------------------------------------------------------+ -- | The only time masterhtrans_out_r changes is when | -- | masterhready is negated is during reset or after | -- | the first cycle of a two-cyle error response. | -- | Otherwise, masterhtrans_out_r can only change when | -- | masterhgrant and masterhready are asserted. | -- +------------------------------------------------------+ updatemasterhtrans_out_r : process ( masterhclk, reset ) begin if ( ( masterhclk'event and masterhclk='1') or ( reset'event and reset='1' ) ) then if (reset='1') then masterhtrans_out_r <= H_IDLE; elsif ( data_bus_owned = '1' and masterhready /= '1' and UNSIGNED(masterhresp)/=UNSIGNED(H_OKAY) and continue_after_error /= '1' ) then -- ERROR'ed transactions cancelled masterhtrans_out_r <= H_IDLE; elsif ( data_bus_owned = '1' and masterhready /= '1' and UNSIGNED(masterhresp)/= UNSIGNED(H_OKAY) and UNSIGNED(masterhresp)/= UNSIGNED(H_ERROR) and continue_after_error = '1' ) then -- ERROR'ed transactions not cancelled masterhtrans_out_r <= H_IDLE; elsif ( masterhgrant='1' and masterhready='1') then case masterhtrans_out_r is when H_IDLE => if (first_masterhtrans_out_r='1') then masterhtrans_out_r <= H_NONSEQ; else masterhtrans_out_r <= H_IDLE; end if ; when H_NONSEQ | H_SEQ => if (first_masterhtrans_out_r='1') then masterhtrans_out_r <= H_NONSEQ; elsif ((UNSIGNED(masterhburst_out_r)=UNSIGNED(H_SINGLE)) or (conv_integer(address_length) <= 1) ) then -- Last beat masterhtrans_out_r <= H_IDLE; elsif (go_busy = '1') then masterhtrans_out_r <= H_BUSY; else masterhtrans_out_r <= H_SEQ; end if ; when H_BUSY => if (first_masterhtrans_out_r='1') then masterhtrans_out_r <= H_NONSEQ; elsif (go_busy='1') then masterhtrans_out_r <= H_BUSY; else masterhtrans_out_r <= H_SEQ; end if ; when others => assert false report "error in masterhtrans_out_r" severity warning; end case ; elsif (masterhready='1' and masterhgrant/='1') then masterhtrans_out_r <= H_IDLE; end if ; end if ; end process updatemasterhtrans_out_r ; -- +------------------------------------------------------+ -- | One of reading or writing is asserted during any | -- | data beat for which we are actively using the bus. | -- +------------------------------------------------------+ updatereadingwriting : process (masterhclk, reset) begin if ( ( masterhclk'event and masterhclk='1') or ( reset'event and reset='1' ) ) then if (reset='1') then reading <= '0' ; writing <= '0' ; elsif (masterhready = '1') then if ( masterhwrite_out_r /= '1' and address_bus_owned = '1' and UNSIGNED(masterhtrans_out_r)/= UNSIGNED(H_IDLE) and UNSIGNED(masterhtrans_out_r)/= UNSIGNED(H_BUSY) ) then reading <= '1' ; else reading <= '0' ; end if ; if ( masterhwrite_out_r = '1' and address_bus_owned = '1' and UNSIGNED(masterhtrans_out_r) /= UNSIGNED(H_IDLE) and UNSIGNED(masterhtrans_out_r )/= UNSIGNED(H_BUSY) ) then writing <= '1' ; else writing <= '0' ; end if ; end if ; end if ; end process updatereadingwriting ; -- +----------------------------------------------------------+ -- | Burst size | -- | | -- | first_beat is used to keep masterhburst_out_r unchanged | -- | when the first beat is to be replayed. It alse controls | -- | the bus request. A transaction that is split or retried | -- | on any other beat will be replayed as INCR and | -- | masterhbusreq_out must be held asserted. | -- | | -- | Tmasterhis means that a defined length read that us | -- | interrupted mid-burst will complete as an undefined INCR | -- | and may pre-fetch past the end of the defined length | -- | (unless, of course, no_prefetch is asserted). | -- +----------------------------------------------------------+ burst_beat : process (masterhclk, reset) begin if ( ( masterhclk'event and masterhclk='1') or ( reset'event and reset='1' ) ) then if (reset='1') then first_beat <= '0' ; elsif (addr_ack='1') then first_beat <= '1' ; elsif (data_bus_owned='1' and (reading='1' or writing='1') and masterhready='1' and UNSIGNED(masterhresp)=UNSIGNED(H_OKAY)) then first_beat <= '0' ; end if ; end if ; end process burst_beat ; burst_burst_out : process (masterhclk, reset) begin if ( ( masterhclk'event and masterhclk='1') or ( reset'event and reset='1' ) ) then if (reset='1') then masterhburst_out_r <= "000" ; elsif (addr_ack='1') then masterhburst_out_r <= burst ; elsif (first_masterhtrans_out_r='1' and first_beat/='1') then masterhburst_out_r <= H_INCR; end if ; end if ; end process burst_burst_out ; -- +------------+ -- | need_retry | -- +------------+ burst_need_retry : process (masterhclk, reset) begin if ( ( masterhclk'event and masterhclk='1') or ( reset'event and reset='1' ) ) then if (reset='1') then need_retry <= '0' ; elsif ( data_bus_owned='1' and masterhready /='1' and (UNSIGNED(masterhresp)=UNSIGNED(H_RETRY) or UNSIGNED(masterhresp)=UNSIGNED(H_SPLIT)) ) then need_retry <= '1' ; elsif ( data_bus_owned='1' and masterhready ='1' and (reading='1' or writing='1') and (UNSIGNED(masterhresp)=UNSIGNED(H_OKAY) or UNSIGNED(masterhresp) = UNSIGNED(H_ERROR)) ) then need_retry <= '0' ; end if ; end if ; end process burst_need_retry ; burst_wraps : process (masterhclk, reset) begin if ( ( masterhclk'event and masterhclk='1') or ( reset'event and reset='1' ) ) then if (reset = '1') then wrap <= '0' ; original_burst <= "000" ; replay_wrap <= "000" ; elsif (addr_ack = '1') then if (UNSIGNED(burst)=UNSIGNED(H_WRAP4) or UNSIGNED(burst)=UNSIGNED(H_WRAP8) or UNSIGNED(burst)=UNSIGNED(H_WRAP16)) then wrap <= '1' ; else wrap <= '0' ; end if ; original_burst <= burst; replay_wrap <= "000" ; elsif ( data_bus_owned ='1' and masterhready /='1' and wrap ='1' and (UNSIGNED(masterhresp)=UNSIGNED(H_RETRY) or UNSIGNED(masterhresp)=UNSIGNED(H_SPLIT)) ) then replay_wrap <= "001" ; end if ; end if ; end process burst_wraps ; -- +===========================================================+ -- | Compute Wrap Mask and Bound bit processes | -- | | -- | Used to modify next_masterhaddr_out_r during wrapping | -- | bursts. First case statement forms a mask based on the | -- | transfer size. This is then shifted left with '1's | -- | inserted to form the final mask. | -- | E.g. masterhsize_outl == word (3'b010) wrapped at a four | -- | beat boundary results in wrap_mask set to 10'b0000001111 | -- | allowing the four lsbs of the address to increment and | -- | wrap addressing sixteen bytes in total. | -- +===========================================================+ computeinitwrapmask : process ( masterhsize_outl ) begin case masterhsize_outl is when "000" => init_wrap_mask <= "0000000000" ; when "001" => init_wrap_mask <= "0000000001" ; when "010" => init_wrap_mask <= "0000000011" ; when "011" => init_wrap_mask <= "0000000111" ; when "100" => init_wrap_mask <= "0000001111" ; when "101" => init_wrap_mask <= "0000011111" ; when "110" => init_wrap_mask <= "0000111111" ; when "111" => init_wrap_mask <= "0001111111" ; when others => init_wrap_mask <= "0000000000" ; assert false report "error in masterhsize_outl" severity warning; end case ; end process computeinitwrapmask ; computewrapmask : process ( original_burst, init_wrap_mask ) begin case original_burst is when H_WRAP4 => wrap_mask(9 downto 2) <= init_wrap_mask(7 downto 0) ; wrap_mask(1 downto 0) <= "11" ; when H_WRAP8 => wrap_mask(9 downto 3) <= init_wrap_mask(6 downto 0) ; wrap_mask(2 downto 0) <= "111" ; when H_WRAP16 => wrap_mask(9 downto 4) <= init_wrap_mask(5 downto 0) ; wrap_mask(3 downto 0) <= "1111" ; when others => wrap_mask <= "0000000000" ; end case ; end process computewrapmask ; computeinitwrapbound : process ( masterhsize_outl ) begin case masterhsize_outl is when "000" => init_wrap_boundary_bit <= "00000001" ; when "001" => init_wrap_boundary_bit <= "00000010" ; when "010" => init_wrap_boundary_bit <= "00000100" ; when "011" => init_wrap_boundary_bit <= "00001000" ; when "100" => init_wrap_boundary_bit <= "00010000" ; when "101" => init_wrap_boundary_bit <= "00100000" ; when "110" => init_wrap_boundary_bit <= "01000000" ; when "111" => init_wrap_boundary_bit <= "10000000" ; when others => init_wrap_boundary_bit <= "00000000" ; assert false report "error in masterhsize_outl" severity warning; end case ; end process computeinitwrapbound ; computewrapbound : process ( original_burst, init_wrap_boundary_bit ) begin case original_burst is when H_WRAP4 => wrap_boundary_bit(9 downto 2) <= init_wrap_boundary_bit ; wrap_boundary_bit(1 downto 0) <= "00" ; when H_WRAP8 => wrap_boundary_bit(9 downto 3) <= init_wrap_boundary_bit(6 downto 0) ; wrap_boundary_bit(2 downto 0) <= "000" ; when H_WRAP16 => wrap_boundary_bit(9 downto 4) <= init_wrap_boundary_bit(5 downto 0) ; wrap_boundary_bit(3 downto 0) <= "0000" ; when others => wrap_boundary_bit <= "00000000000" ; end case ; end process computewrapbound ; -- +============================================================+ -- | CALCULATE ADDRESS processes | -- +============================================================+ -- +------------------------------------------------------------+ -- | Compute address increment | -- | | -- | This code allows for all possibilities by inferring | -- | a 3-to-8 decoder on the transfer size. AHB spec is | -- | unclear how a burst with a transfer size greater | -- | than the bus width should be handled. | -- +------------------------------------------------------------+ computeaddressincrement : process ( masterhsize_outl ) begin masterhaddr_out_r_inc <= "00000000" ; masterhaddr_out_r_inc(conv_integer(masterhsize_outl)) <= '1' ; end process computeaddressincrement ; -- +------------------------------------------------------------+ -- | Compute next address | -- | | -- | Next address is based on the increment computed from the | -- | transfer size, and the burst type, which may tell us to | -- | wrap. Wrapping is achieved by preserving some of the upper | -- | bits through use of wrap_mask. | -- | | -- | If beat n is retried, we're already putting out the | -- | address for beat n+1 so we need to decrement. | -- +------------------------------------------------------------+ computeinitnextaddress : process (data_bus_owned, masterhresp, masterhready, masterhaddr_out_r, masterhaddr_out_r_inc ) variable temp_init_next_masterhaddr_out_r : std_logic_vector (10 downto 0) ; begin temp_init_next_masterhaddr_out_r(10) := '1' ; temp_init_next_masterhaddr_out_r(9 downto 0) := masterhaddr_out_r(9 downto 0) ; if (data_bus_owned='1' and ((UNSIGNED(masterhresp)=UNSIGNED(H_RETRY)) or (UNSIGNED(masterhresp)=UNSIGNED(H_SPLIT)))) then init_next_masterhaddr_out_r <= temp_init_next_masterhaddr_out_r - masterhaddr_out_r_inc; else init_next_masterhaddr_out_r <= temp_init_next_masterhaddr_out_r + masterhaddr_out_r_inc; end if ; end process computeinitnextaddress ; computenextaddress : process (original_burst, wrap_mask, masterhaddr_out_r, init_next_masterhaddr_out_r ) begin if ( (UNSIGNED(original_burst)=UNSIGNED(H_WRAP4) ) or (UNSIGNED(original_burst)=UNSIGNED(H_WRAP8) ) or (UNSIGNED(original_burst)=UNSIGNED(H_WRAP16)) ) then next_masterhaddr_out_r <= (wrap_mask and init_next_masterhaddr_out_r(9 downto 0)) or (not wrap_mask and masterhaddr_out_r(9 downto 0)) ; else next_masterhaddr_out_r <= init_next_masterhaddr_out_r (9 downto 0) ; end if ; end process computenextaddress ; break_wrap <= replay_wrap(1) and ( ur_OR(init_next_masterhaddr_out_r and wrap_boundary_bit) xor ur_OR(masterhaddr_out_r(10 downto 0) and wrap_boundary_bit) ) ; -- +------------------------------------------------------------+ -- | Address Generation | -- | | -- | AHB address has to track the changing address during | -- | bursts. next_masterhaddr_out_r computes the next address. | -- | | -- | NOTE: It is incumbent upon the command file not to attempt | -- | a transaction that would cross a 1Kbyte address boundary. | -- | | -- | Address is normally updated after each address phase. It | -- | is also updated during the second cycle of a two cycle | -- | retry or split response to rewind the address and allow | -- | the transaction to be replayed. | -- +------------------------------------------------------------+ addressgeneration : process (masterhclk, reset) begin if ( ( masterhclk'event and masterhclk='1') or ( reset'event and reset='1' ) ) then if (reset='1') then masterhaddr_out_r <= (OTHERS => '0' ) ; elsif (addr_ack='1') then masterhaddr_out_r <= start_address ; elsif ( data_bus_owned ='1' and masterhready ='1' and (UNSIGNED(masterhresp)=UNSIGNED(H_RETRY) or UNSIGNED(masterhresp)=UNSIGNED(H_SPLIT)) ) then masterhaddr_out_r(9 downto 0) <= next_masterhaddr_out_r ; elsif ( address_bus_owned ='1' and masterhready ='1' and (UNSIGNED(masterhtrans_out_r)=UNSIGNED(H_NONSEQ) or UNSIGNED(masterhtrans_out_r)=UNSIGNED(H_SEQ)) ) then masterhaddr_out_r(9 downto 0) <= next_masterhaddr_out_r ; end if ; end if; end process addressgeneration ; -- +============================================================+ -- | WRITEDATA processes | -- | | -- | If generate_data is negated then initial data is taken | -- | from data input. If generate_data is asserted then data is | -- | generated from the address offset to match that expected | -- | by the checkers. | -- | | -- | The expected data and the transaction number follow the | -- | write data. | -- | | -- | At the end of a burst data is set to X so we can ensure | -- | nothing is relying on invalid data. | -- +============================================================+ writedatapipeandretry: process (masterhclk) begin if ( masterhclk'event and masterhclk='1') then if ( data_bus_owned ='1' and masterhready /='1' and (UNSIGNED(masterhresp)=UNSIGNED(H_RETRY) or UNSIGNED(masterhresp)=UNSIGNED(H_SPLIT)) ) then masterhwdata_out_r_retry <= masterhwdata_out_r ; elsif (addr_ack='1' or data_ack='1') then masterhwdata_out_r_pipe <= data ; end if ; end if ; end process writedatapipeandretry ; addr_offset(7 downto 2) <= masterhaddr_out_r (7 downto 2) ; addr_offset(1 downto 0) <= "00" ; writedata: process (masterhclk, reset) begin if ( ( masterhclk'event and masterhclk='1') or ( reset'event and reset='1' ) ) then if (reset='1') then masterhwdata_out_r <= (OTHERS=> '0') ; elsif (address_bus_owned /='1' and masterhready='1') then masterhwdata_out_r <= (OTHERS=> '0') ; elsif (masterhready='1' and generate_data /='1') then if (address_bus_owned='1' and masterhwrite_out_r='1' and need_retry='1' and trans_end/='1') then masterhwdata_out_r <= masterhwdata_out_r_retry; elsif (address_bus_owned='1' and masterhwrite_out_r='1' and UNSIGNED(masterhtrans_out_r)=UNSIGNED(H_NONSEQ)) then masterhwdata_out_r <= masterhwdata_out_r_pipe ; elsif (UNSIGNED(length) = 0 ) then masterhwdata_out_r <= (OTHERS=> '0') ; elsif (address_bus_owned='1' and masterhwrite_out_r='1' and UNSIGNED(masterhtrans_out_r)=UNSIGNED(H_SEQ)) then masterhwdata_out_r <= masterhwdata_out_r_pipe; else masterhwdata_out_r <= (OTHERS=> '0') ; end if ; elsif (masterhready='1' and generate_data='1') then if (address_bus_owned='1' and masterhwrite_out_r='1' and UNSIGNED(masterhtrans_out_r)=UNSIGNED(H_NONSEQ)) then masterhwdata_out_r (31 downto 24) <= addr_offset ; masterhwdata_out_r (23 downto 16) <= addr_offset ; masterhwdata_out_r (15 downto 8) <= addr_offset ; masterhwdata_out_r ( 7 downto 0) <= addr_offset ; elsif (UNSIGNED(length) = 0 ) then masterhwdata_out_r <= (OTHERS=> '0') ; elsif (address_bus_owned='1' and masterhwrite_out_r='1' and UNSIGNED(masterhtrans_out_r)=UNSIGNED(H_SEQ)) then masterhwdata_out_r (31 downto 24) <= addr_offset ; masterhwdata_out_r (23 downto 16) <= addr_offset ; masterhwdata_out_r (15 downto 8) <= addr_offset ; masterhwdata_out_r ( 7 downto 0) <= addr_offset ; end if ; end if ; end if ; end process writedata ; -- +================================================================+ -- | Transaction Details processes | -- | | -- | The transactor pipeline consists of four stages | -- | | -- | nextTrans - the next transaction from the store | -- | controlTrans - the current control / address stage transaction | -- | dataTrans - the data stage transaction | -- | reportTrans - the completed stage for reporting | -- | | -- | controlTrans is updated from nextTrans when a new transaction | -- | begins or from dataTrans in the case of split/retry | -- +================================================================+ transdetails : process (masterhclk) begin if ( masterhclk'event and masterhclk='1') then if ( data_bus_owned ='1' and masterhready /='1' and (UNSIGNED(masterhresp)=UNSIGNED(H_RETRY) or UNSIGNED(masterhresp)=UNSIGNED(H_SPLIT)) ) then retryTrans <= dataTrans ; elsif (addr_ack='1' or data_ack='1') then controlTrans <= nextTrans ; end if ; end if ; end process transdetails ; setdatatransdetails : process (masterhclk, reset) begin if ( ( masterhclk'event and masterhclk='1') or ( reset'event and reset='1' ) ) then if ( address_bus_owned = '1' and masterhready = '1' and reset /= '1' and (need_retry/='1' or trans_end='1') ) then dataTrans <= controlTrans ; dataTrans (Trns_ADDR_b downto Trns_ADDR_l ) <= masterhaddr_out_r ; dataTrans (Trns_WRITE ) <= masterhwrite_out_r ; dataTrans (Trns_LOCK ) <= masterhlock_out ; dataTrans (Trns_TRANSTYPE_b downto Trns_TRANSTYPE_l) <= masterhtrans_out_r ; dataTrans (Trns_BURSTTYPE_b downto Trns_BURSTTYPE_l) <= masterhburst_out_r ; dataTrans (Trns_SIZE_b downto Trns_SIZE_l ) <= masterhsize_outl ; elsif ( address_bus_owned = '1' and masterhready = '1' and reset /='1' and need_retry ='1' ) then dataTrans <= retryTrans ; dataTrans (Trns_ADDR_b downto Trns_ADDR_l ) <= masterhaddr_out_r ; dataTrans (Trns_WRITE ) <= masterhwrite_out_r ; dataTrans (Trns_LOCK ) <= masterhlock_out ; dataTrans (Trns_TRANSTYPE_b downto Trns_TRANSTYPE_l) <= masterhtrans_out_r ; dataTrans (Trns_BURSTTYPE_b downto Trns_BURSTTYPE_l) <= masterhburst_out_r ; dataTrans (Trns_SIZE_b downto Trns_SIZE_l ) <= masterhsize_outl ; elsif ( (address_bus_owned /= '1' and masterhready='1') or reset='1') then dataTrans <= idleTrans ; end if ; end if ; end process setdatatransdetails ; setreporttransdetails : process (masterhclk) begin if ( masterhclk'event and masterhclk='1') then if (trans_end='1' and need_retry /='1') then reportTrans (Trns_RESP_b downto Trns_RESP_l) <= masterhresp; reportTrans (Trns_READ_b downto Trns_READ_l) <= masterhrdata; reportTrans (Trns_BUSY downto 0 ) <= dataTrans(Trns_BUSY downto 0); elsif (trans_end='1' and need_retry = '1') then reportTrans (Trns_RESP_b downto Trns_RESP_l) <= masterhresp; reportTrans (Trns_READ_b downto Trns_READ_l) <= masterhrdata; reportTrans (Trns_BUSY downto 0 ) <= retryTrans(Trns_BUSY downto 0); else reportTrans <= idleTrans; end if ; end if ; end process setreporttransdetails ; -- +------------------+ -- | masterhlock_out | -- +------------------+ masterhlock_out <= '0' ; -- +--------------------------------------------------------------------+ -- +--------------------------------------------------------------------+ end behaviour ; -- alt_exc_upcore