-- -- -- DISCLAIMER -- -- This code is the sole property of the Institute for Technology -- Development (ITD), Jackson, Mississippi, and is distributed for -- the purpose of providing examples of VHDL models written to -- modeling standards. This code may not be used for commercial -- purposes, and may not be redistributed without permission from -- the Institute for Technology Development. ITD assumes no -- responsibility for errors, omissions, uses made, or decisions -- based on its use. No warranties, expressed or implied, are given. -- -- ------------------------------------------------------------------ architecture behavioral of SN54LS161 is -- ARCHITECTURE DECLARATIVE REGION constant generic_loads : loads := (tld_P15, tld_P14, tld_P13, tld_P12, tld_P11) ; constant generic_times : times := (tplh_clk_rco, tplh_clk_qlh, tplh_clk_qll, tplh_en_rco, tphl_clk_rco, tphl_clk_qlh, tphl_clk_qll, tphl_en_rco, tphl_clr_q, tphl_clr_rco, --< not specified in data sheet tw_clk, tw_clr, tsu_data, tsu_enable, tsu_load, th); constant model_times : sim_timing := get_timing(generic_loads,generic_times) ; -- user may turn off timing violation assertions constant do_timing : boolean := ((model_times.sim_messages.tl = ONLY_DISPLAY) or (model_times.sim_messages.tl = FULL_TIM)); -- Local signal declarations signal clock,clear,enablep : logic_mv := 'U' ; signal loadin,enablet : logic_mv := 'U' ; signal ain,bin,cin,din : logic_mv := 'U' ; signal qouta,qoutb,qoutc,qoutd : logic_mv := 'U' ; signal rc_clock, rc_ent : logic_mv := 'U' ; ----------------------------------------------------------------- -- two internal signals, rc_clock and rc_ent, are used to -- implement the delay path to output RCO. This "structural" -- implementation is necessary to produce the correct propagation -- delay from input ENT or CLOCK to output RCO. Consult the 1988 -- TI Data Book, page 2-497 for a structural diagram. ----------------------------------------------------------------- -- Global signals signal violate : violate_flags ; signal clear_last : time ; signal clock_last : time ; -- ARCHITECTURE FUNCTIONAL REGION begin -- assign pin values to internal signals after wire delay clear <= transport Filter2(CLR) after twd_P1 ; clock <= transport Filter2(CLK) after twd_P2 ; ain <= transport Filter2(A) after twd_P3 ; bin <= transport Filter2(B) after twd_P4 ; cin <= transport Filter2(C) after twd_P5 ; din <= transport Filter2(D) after twd_P6 ; loadin <= transport Filter2(LOAD) after twd_P9 ; enablep <= transport Filter2(ENP) after twd_P7 ; enablet <= transport Filter2(ENT) after twd_P10 ; rc_ent <= transport enablet after tp_delay(enablet, model_times.prop_delays.tplh_en_rco, model_times.prop_delays.tphl_en_rco); -- Assign internal values to output pins QA <= qouta ; QB <= qoutb ; QC <= qoutc ; QD <= qoutd ; RC <= rc_clock and rc_ent; -- Check for invalid inputs on control input ports assert not (CLK'event and ((CLK = 'U') or (CLK = 'X') or (CLK = 'Z') or (CLK = 'W'))) report "{" & ref & "} " & enum_to_char(CLK) & " STATE ON CLK INPUT" severity warning ; assert not (CLR'event and ((CLR = 'U') or (CLR = 'X') or (CLR = 'Z') or (CLR = 'W'))) report "{" & ref & "} " & enum_to_char(CLR) & " STATE ON CLR INPUT" severity warning ; assert not (ENP'event and ((ENP = 'U') or (ENP = 'X') or (ENP = 'Z') or (ENP = 'W'))) report "{" & ref & "} " & enum_to_char(ENP) & " STATE ON ENP INPUT" severity warning ; assert not (LOAD'event and ((LOAD = 'U') or (LOAD = 'X') or (LOAD = 'Z') or (LOAD = 'W'))) report "{" & ref & "} " & enum_to_char(LOAD) & " STATE ON LOAD INPUT" severity warning ; assert not (ENT'event and ((ENT = 'U') or (ENT = 'X') or (ENT = 'Z') or (ENT = 'W'))) report "{" & ref & "} " & enum_to_char(ENT) & " STATE ON ENT INPUT" severity warning ; -- Timing Violation Processes ------------------------------------------------------------------------- CLK_PULSE_CHECK : process variable clk_violate : boolean ; begin wait on clock until (do_timing and (clear = '1') and (posedge(clock) or negedge(clock))) ; if clock = '0' then clk_violate := PULSE_CHECK(clock_last,model_times.prop_delays.tw_clk,ref, "PULSE CHECK WARNING: CLK - HIGH",warning) ; else clk_violate := PULSE_CHECK(clock_last,model_times.prop_delays.tw_clk,ref, "PULSE CHECK WARNING: CLK - LOW",warning) ; end if ; violate.clock <= clk_violate and model_times.error_flags.x_out ; wait for 0 ns ; violate.clock <= FALSE ; end process CLK_PULSE_CHECK ; ------------------------------------------------------------------------- CLR_PULSE_CHECK : process variable clr_violate : boolean ; begin wait on clear until (do_timing and posedge(clear)) ; clr_violate := PULSE_CHECK(clear_last,model_times.prop_delays.tw_clr,ref, "PULSE CHECK WARNING: CLR - LOW",warning) ; violate.clear <= clr_violate and model_times.error_flags.x_out ; wait for 0 ns ; violate.clear <= FALSE ; end process CLR_PULSE_CHECK ; ------------------------------------------------------------------------- IN_SETUP_CHECK : process variable setup_ain_violate : boolean ; variable setup_bin_violate : boolean ; variable setup_cin_violate : boolean ; variable setup_din_violate : boolean ; variable setup_enp_violate : boolean ; variable setup_ent_violate : boolean ; variable setup_load_violate : boolean ; begin wait on clock until (do_timing and (clear = '1') and posedge(clock)) ; if loadin = '0' then setup_ain_violate := SETUP_CHECK(ain'last_event, model_times.prop_delays.tsu_data,ref, "SETUP CHECK WARNING: A", warning) ; setup_bin_violate := SETUP_CHECK(bin'last_event, model_times.prop_delays.tsu_data,ref, "SETUP CHECK WARNING: B", warning) ; setup_cin_violate := SETUP_CHECK(cin'last_event, model_times.prop_delays.tsu_data,ref, "SETUP CHECK WARNING: C", warning) ; setup_din_violate := SETUP_CHECK(din'last_event, model_times.prop_delays.tsu_data,ref, "SETUP CHECK WARNING: D", warning) ; end if ; setup_enp_violate := SETUP_CHECK(enablep'last_event, model_times.prop_delays.tsu_enable,ref, "SETUP CHECK WARNING: ENP", warning) ; setup_ent_violate := SETUP_CHECK(enablet'last_event, model_times.prop_delays.tsu_enable,ref, "SETUP CHECK WARNING: ENT", warning) ; setup_load_violate := SETUP_CHECK(loadin'last_event, model_times.prop_delays.tsu_load,ref, "SETUP CHECK WARNING: LOAD", warning) ; violate.ain_setup <= setup_ain_violate and model_times.error_flags.x_out; violate.bin_setup <= setup_bin_violate and model_times.error_flags.x_out; violate.cin_setup <= setup_cin_violate and model_times.error_flags.x_out; violate.din_setup <= setup_din_violate and model_times.error_flags.x_out; violate.enp_setup <= setup_enp_violate and model_times.error_flags.x_out; violate.ent_setup <= setup_ent_violate and model_times.error_flags.x_out; violate.load_setup <= setup_load_violate and model_times.error_flags.x_out; wait for 0 ns ; violate.ain_setup <= FALSE ; violate.bin_setup <= FALSE ; violate.cin_setup <= FALSE ; violate.din_setup <= FALSE ; violate.enp_setup <= FALSE ; violate.ent_setup <= FALSE ; violate.load_setup <= FALSE ; end process IN_SETUP_CHECK ; ------------------------------------------------------------------------- A_HOLD_CHECK : process variable hold_ain_violate : boolean ; begin wait on ain until (do_timing and (clear = '1') and (clock'last_value = '0') and (clock = '1') and loadin = '0') ; hold_ain_violate := HOLD_CHECK(clock'last_event, model_times.prop_delays.th,ref, "HOLD CHECK WARNING: A",warning) ; violate.ain_hold <= hold_ain_violate and model_times.error_flags.x_out; wait for 0 ns ; violate.ain_hold <= FALSE ; end process A_HOLD_CHECK ; ------------------------------------------------------------------------- B_HOLD_CHECK : process variable hold_bin_violate : boolean ; begin wait on bin until (do_timing and (clear = '1') and (clock'last_value = '0') and (clock = '1') and loadin = '0') ; hold_bin_violate := HOLD_CHECK(clock'last_event, model_times.prop_delays.th,ref, "HOLD CHECK WARNING: B",warning) ; violate.bin_hold <= hold_bin_violate and model_times.error_flags.x_out ; wait for 0 ns ; violate.bin_hold <= FALSE ; end process B_HOLD_CHECK ; ------------------------------------------------------------------------- C_HOLD_CHECK : process variable hold_cin_violate : boolean ; begin wait on cin until (do_timing and (clear = '1') and (clock'last_value = '0') and (clock = '1') and loadin = '0') ; hold_cin_violate := HOLD_CHECK(clock'last_event, model_times.prop_delays.th,ref, "HOLD CHECK WARNING: C",warning) ; violate.cin_hold <= hold_cin_violate and model_times.error_flags.x_out ; wait for 0 ns ; violate.cin_hold <= FALSE ; end process C_HOLD_CHECK ; ------------------------------------------------------------------------- D_HOLD_CHECK : process variable hold_din_violate : boolean ; begin wait on din until (do_timing and (clear = '1') and (clock'last_value = '0') and (clock = '1') and loadin = '0') ; hold_din_violate := HOLD_CHECK(clock'last_event, model_times.prop_delays.th,ref, "HOLD CHECK WARNING: D",warning) ; violate.din_hold <= hold_din_violate and model_times.error_flags.x_out ; wait for 0 ns ; violate.din_hold <= FALSE ; end process D_HOLD_CHECK ; ------------------------------------------------------------------------- ENP_HOLD_CHECK : process variable hold_enp_violate : boolean ; begin wait on enablep until (do_timing and (clear = '1') and (clock'last_value = '0') and (clock = '1')) ; hold_enp_violate := HOLD_CHECK(clock'last_event, model_times.prop_delays.th,ref, "HOLD CHECK WARNING: ENP",warning) ; violate.enp_hold <= hold_enp_violate and model_times.error_flags.x_out ; wait for 0 ns ; violate.enp_hold <= FALSE ; end process ENP_HOLD_CHECK ; ------------------------------------------------------------------------- LOAD_HOLD_CHECK : process variable hold_load_violate : boolean ; begin wait on loadin until (do_timing and (clear = '1') and (clock'last_value = '0') and (clock = '1')) ; hold_load_violate := HOLD_CHECK(clock'last_event, model_times.prop_delays.th,ref, "HOLD CHECK WARNING: LOAD",warning) ; violate.load_hold <= hold_load_violate and model_times.error_flags.x_out ; wait for 0 ns ; violate.load_hold <= FALSE ; end process LOAD_HOLD_CHECK ; ------------------------------------------------------------------------- ENT_HOLD_CHECK : process variable hold_ent_violate : boolean ; begin wait on enablet until (do_timing and (clear = '1') and (clock'last_value = '0') and (clock = '1')) ; hold_ent_violate := HOLD_CHECK(clock'last_event, model_times.prop_delays.th,ref, "HOLD CHECK WARNING: ENT",warning) ; violate.ent_hold <= hold_ent_violate and model_times.error_flags.x_out ; wait for 0 ns ; violate.ent_hold <= FALSE ; end process ENT_HOLD_CHECK ; ------------------------------------------------------------------------- CLR_HOLD_CHECK : process variable hold_clr_violate : boolean ; begin wait on clear until (do_timing and (clear = '1') and (clock'last_value = '0') and (clock = '1')) ; hold_clr_violate := HOLD_CHECK(clock'last_event, model_times.prop_delays.th,ref, "HOLD CHECK WARNING: CLR",warning) ; violate.clr_hold <= hold_clr_violate and model_times.error_flags.x_out ; wait for 0 ns ; violate.clr_hold <= FALSE ; end process CLR_HOLD_CHECK ; ------------------------------------------------------------------------- LAST_EVENT : process (clear,clock) begin if (clear'event = TRUE) then clear_last <= NOW ; end if ; if (clock'event = TRUE) then clock_last <= NOW ; end if ; end process LAST_EVENT ; ------------------------------------------------------------------------- COUNT : process variable mode : modetype ; variable carry : logic_mv; variable rc : logic_mv; variable qstate : logic_mv_vector (0 to 3) ; variable unknown : boolean := FALSE ; begin wait on clear,clock,enablep,enablet,loadin,violate; if (violate.clock or violate.clear or violate.ain_setup or violate.bin_setup or violate.cin_setup or violate.din_setup or violate.enp_setup or violate.load_setup or violate.clr_setup or violate.ent_setup or violate.ain_hold or violate.bin_hold or violate.cin_hold or violate.din_hold or violate.clr_hold or violate.enp_hold or violate.ent_hold or violate.load_hold ) then mode := ERROR ; elsif (clear = '0') then mode := CLR_CNTR ; elsif (clear = '1' and load = '0') then mode := LD_CNTR ; elsif (clear = '1' and load = '1' and enablep = '1' and enablet = '1') then mode := CNT ; elsif (bit_unknown(clear)) then mode := ERROR; elsif ( (bit_unknown(load) or bit_unknown(enablep) or bit_unknown(enablet)) and (posedge(clock) or bit_unknown(clock)) ) then mode := ERROR; else mode := HOLD ; end if ; ------------ case mode is when ERROR => if (clear = 'U' or load = 'U' or clock = 'U' or ain = 'U' or bin = 'U' or cin = 'U' or din = 'U' or enablep = 'U' or enablet = 'U') then qouta <= 'U' ; qoutb <= 'U' ; qoutc <= 'U' ; qoutd <= 'U' ; rc_clock <= 'U' ; else qouta <= 'X' ; qoutb <= 'X' ; qoutc <= 'X' ; qoutd <= 'X' ; rc_clock <= 'X' ; end if ; when CLR_CNTR => qouta <= transport '0' after model_times.prop_delays.tphl_clr_q ; qoutb <= transport '0' after model_times.prop_delays.tphl_clr_q ; qoutc <= transport '0' after model_times.prop_delays.tphl_clr_q ; qoutd <= transport '0' after model_times.prop_delays.tphl_clr_q ; rc_clock <= transport '0' after model_times.prop_delays.tphl_clr_q ; when LD_CNTR => if (posedge(clock)) then if (not bit_unknown(ain)) then qouta <= transport ain after tp_delay(ain, model_times.prop_delays.tplh_clk_qll, model_times.prop_delays.tphl_clk_qll) ; elsif (ain = 'U' or enablep = 'U' or enablet = 'U') then qouta <= 'U' ; else qouta <= 'X' ; end if ; if (not bit_unknown(bin)) then qoutb <= transport bin after tp_delay(bin, model_times.prop_delays.tplh_clk_qll, model_times.prop_delays.tphl_clk_qll) ; elsif (bin = 'U' or enablep = 'U' or enablet = 'U') then qoutb <= 'U' ; else qoutb <= 'X' ; end if ; if (not bit_unknown(cin)) then qoutc <= transport cin after tp_delay(cin, model_times.prop_delays.tplh_clk_qll, model_times.prop_delays.tphl_clk_qll) ; elsif (cin = 'U' or enablep = 'U' or enablet = 'U') then qoutc <= 'U' ; else qoutc <= 'X' ; end if ; if (not bit_unknown(din)) then qoutd <= transport din after tp_delay(din, model_times.prop_delays.tplh_clk_qll, model_times.prop_delays.tphl_clk_qll) ; elsif (din = 'U' or enablep = 'U' or enablet = 'U') then qoutd <= 'U' ; else qoutd <= 'X' ; end if ; rc := ain and bin and cin and din ; rc_clock <= transport rc after tp_delay(rc,model_times.prop_delays.tplh_clk_rco, model_times.prop_delays.tphl_clk_rco); elsif (bit_unknown(clock)) then if (ain /= qouta) then if (ain = 'U' or clock = 'U' or enablep = 'U' or enablet = 'U') then qouta <= 'U' ; else qouta <= 'X' ; end if ; end if ; if (bin /= qoutb) then if (bin = 'U' or clock = 'U' or enablep = 'U' or enablet = 'U') then qoutb <= 'U' ; else qoutb <= 'X' ; end if ; end if ; if (cin /= qoutc) then if (cin = 'U' or clock = 'U' or enablep = 'U' or enablet = 'U') then qoutc <= 'U' ; else qoutc <= 'X' ; end if ; end if ; if (din /= qoutd) then if (din = 'U' or clock = 'U' or enablep = 'U' or enablet = 'U') then qoutd <= 'U' ; else qoutd <= 'X' ; end if ; end if ; rc := qouta and qoutb and qoutc and qoutd ; rc_clock <= transport rc after tp_delay(rc,model_times.prop_delays.tplh_clk_rco, model_times.prop_delays.tphl_clk_rco); end if ; when CNT => -- 'H' is to be treated as a '1', and 'L' is to be treated as '0' qstate(0) := FILTER2(qoutd) ; qstate(1) := FILTER2(qoutc) ; qstate(2) := FILTER2(qoutb) ; qstate(3) := FILTER2(qouta) ; if (posedge(clock)) then -- Set the carry to '1' to add one to the LSB, then -- let the carry propagate down through the other digits. carry := '1'; for digit_pos in 3 downto 0 loop case carry is when '0' => if (qstate(digit_pos) = 'X') then carry := 'X'; else carry := '0'; end if; when '1' => carry := qstate(digit_pos); qstate(digit_pos) := not qstate(digit_pos); when 'X' => carry := carry and qstate(digit_pos); qstate(digit_pos) := 'X'; when 'U' => carry := carry and qstate(digit_pos); qstate(digit_pos) := 'U'; when others => end case; end loop; qouta <= transport qstate(3) after tp_delay(qstate(3), model_times.prop_delays.tplh_clk_qlh, model_times.prop_delays.tphl_clk_qlh); qoutb <= transport qstate(2) after tp_delay(qstate(2), model_times.prop_delays.tplh_clk_qlh, model_times.prop_delays.tphl_clk_qlh); qoutc <= transport qstate(1) after tp_delay(qstate(1), model_times.prop_delays.tplh_clk_qlh, model_times.prop_delays.tphl_clk_qlh); qoutd <= transport qstate(0) after tp_delay(qstate(0), model_times.prop_delays.tplh_clk_qlh, model_times.prop_delays.tphl_clk_qlh); rc := qstate(0) and qstate(1) and qstate(2) and qstate(3); rc_clock <= transport rc after tp_delay(rc,model_times.prop_delays.tplh_clk_rco, model_times.prop_delays.tphl_clk_rco); elsif (clock = 'U') then qouta <= 'U' ; qoutb <= 'U' ; qoutc <= 'U' ; qoutd <= 'U' ; rc_clock <= 'U' ; elsif (clock = 'X') then qouta <= 'X' ; qoutb <= 'X' ; qoutc <= 'X' ; qoutd <= 'X' ; rc_clock <= 'X' ; end if ; when HOLD => null; end case ; end process COUNT ; end behavioral ;