-- -- -- 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 SN54LS112 is -- ARCHITECTURE DECLARATIVE REGION constant generic_times : times := (tplh_clk_q, tplh_pr_q, tplh_clr_q, tphl_clk_q, tphl_pr_q, tphl_clr_q, tsu, th, tw_clk_lo, tw_clk_hi, tw_poc_lo) ; constant generic_loads : loads := (tld_P5, tld_P6, tld_P7, tld_P9 ); 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 clock1,jin1,kin1,preset1,clear1 : logic_mv := 'U' ; signal clock2,jin2,kin2,preset2,clear2 : logic_mv := 'U' ; signal qout1,qout2 : logic_mv := 'U' ; signal qbout1,qbout2 : logic_mv := 'U' ; -- Global signals signal violate : violate_flags ; signal clear1_last : time ; signal preset1_last : time ; signal clear2_last : time ; signal preset2_last : time ; signal clock1_last : time ; signal clock2_last : time ; signal init_qout : logic_mv_vector(1 to 2) ; -- ARCHITECTURE FUNCTIONAL REGION begin -- assign pin values to internal signals after wire delay -- 'H' is to be treated as a '1', and 'L' is to be treated as '0' clock1 <= transport Filter2(CLK1) after twd_P1 ; kin1 <= transport Filter2(K1) after twd_P2 ; jin1 <= transport Filter2(J1) after twd_P3 ; preset1 <= transport Filter2(PR1) after twd_P4 ; clear1 <= transport Filter2(CLR1) after twd_P15 ; clock2 <= transport Filter2(CLK2) after twd_P13 ; kin2 <= transport Filter2(K2) after twd_P12 ; jin2 <= transport Filter2(J2) after twd_P11 ; preset2 <= transport Filter2(PR2) after twd_P10 ; clear2 <= transport Filter2(CLR2) after twd_P14 ; -- Assign internal values to output pins Q2 <= qout2 ; QB2 <= qbout2 ; Q1 <= qout1 ; QB1 <= qbout1 ; -- Check for invalid inputs on control input ports assert not (CLK1'event and ((CLK1 = 'U') or (CLK1 = 'X') or (CLK1 = 'Z') or (CLK1 = 'W'))) report "{" & ref & "} " & enum_to_char(CLK1) & " STATE ON CLK1 INPUT" severity warning ; assert not (PR1'event and ((PR1 = 'U') or (PR1 = 'X') or (PR1 = 'Z') or (PR1 = 'W'))) report "{" & ref & "} " & enum_to_char(PR1) & " STATE ON PR1 INPUT" severity warning ; assert not (CLR1'event and ((CLR1 = 'U') or (CLR1 = 'X') or (CLR1 = 'Z') or (CLK1 = 'W'))) report "{" & ref & "} " & enum_to_char(CLR1) & " STATE ON CLR1 INPUT" severity warning ; assert not (CLK2'event and ((CLK2 = 'U') or (CLK2 = 'X') or (CLK2 = 'Z') or (CLK2 = 'W'))) report "{" & ref & "} " & enum_to_char(CLK2) & " STATE ON CLK2 INPUT" severity warning ; assert not (PR2'event and ((PR2 = 'U') or (PR2 = 'X') or (PR2 = 'Z') or (PR2 = 'W'))) report "{" & ref & "} " & enum_to_char(PR2) & " STATE ON PR2 INPUT" severity warning ; assert not (CLR2'event and ((CLR2 = 'U') or (CLR2 = 'X') or (CLR2 = 'Z') or (CLR2 = 'W'))) report "{" & ref & "} " & enum_to_char(CLR2) & " STATE ON CLR2 INPUT" severity warning ; -- Timing Violation Processes ------------------------------------------------------------------------- CLK1_PULSE_CHECK : process variable clk1_violate : boolean ; begin wait on clock1 until ( do_timing and (preset1= '1') and (clear1='1') and (posedge(clock1) or negedge(clock1))) ; if clock1 = '0' then clk1_violate := PULSE_CHECK(clock1_last,model_times.prop_delays.tw_clk_hi,ref, "PULSE CHECK WARNING: CLK1 - HIGH",warning) ; else clk1_violate := PULSE_CHECK(clock1_last,model_times.prop_delays.tw_clk_lo,ref, "PULSE CHECK WARNING: CLK1 - LOW",warning) ; end if ; violate.clock1 <= clk1_violate and model_times.error_flags.x_out ; wait for 0 ns ; violate.clock1 <= FALSE ; end process CLK1_PULSE_CHECK ; ------------------------------------------------------------------------- CLK2_PULSE_CHECK : process variable clk2_violate : boolean ; begin wait on clock2 until ( do_timing and (preset2= '1') and (clear2='1') and (posedge(clock2) or negedge(clock2))) ; if clock2 = '0' then clk2_violate := PULSE_CHECK(clock2_last,model_times.prop_delays.tw_clk_hi,ref, "PULSE CHECK WARNING: CLK2 - HIGH",warning) ; else clk2_violate := PULSE_CHECK(clock2_last,model_times.prop_delays.tw_clk_lo,ref, "PULSE CHECK WARNING: CLK2 - LOW",warning) ; end if ; violate.clock2 <= clk2_violate and model_times.error_flags.x_out ; wait for 0 ns ; violate.clock2 <= FALSE ; end process CLK2_PULSE_CHECK ; ------------------------------------------------------------------------- CLR1_PULSE_CHECK : process variable clr1_violate : boolean ; begin wait on clear1 until ( do_timing and (preset1= '1') and (clear1='1') and posedge(clear1)) ; clr1_violate := PULSE_CHECK(clear1_last,model_times.prop_delays.tw_poc_lo,ref, "PULSE CHECK WARNING: CLR1 - LOW",warning) ; violate.clear1 <= clr1_violate and model_times.error_flags.x_out ; wait for 0 ns ; violate.clear1 <= FALSE ; end process CLR1_PULSE_CHECK ; ------------------------------------------------------------------------- CLR2_PULSE_CHECK : process variable clr2_violate : boolean ; begin wait on clear2 until ( do_timing and (preset2= '1') and (clear2='1') and posedge(clear2)) ; clr2_violate := PULSE_CHECK(clear2_last,model_times.prop_delays.tw_poc_lo,ref, "PULSE CHECK WARNING: CLR2 - LOW",warning) ; violate.clear2 <= clr2_violate and model_times.error_flags.x_out ; wait for 0 ns ; violate.clear2 <= FALSE ; end process CLR2_PULSE_CHECK ; ------------------------------------------------------------------------- PR1_PULSE_CHECK : process variable pr1_violate : boolean ; begin wait on preset1 until ( do_timing and (preset1= '1') and (clear1='1') and posedge(preset1)) ; pr1_violate := PULSE_CHECK(preset1_last,model_times.prop_delays.tw_poc_lo,ref, "PULSE CHECK WARNING: PR1 - LOW",warning) ; violate.preset1 <= pr1_violate and model_times.error_flags.x_out ; wait for 0 ns ; violate.preset1 <= FALSE ; end process PR1_PULSE_CHECK ; ------------------------------------------------------------------------- PR2_PULSE_CHECK : process variable pr2_violate : boolean ; begin wait on preset2 until ( do_timing and (preset2= '1') and (clear2='1') and posedge(preset2)) ; pr2_violate := PULSE_CHECK(preset2_last,model_times.prop_delays.tw_poc_lo,ref, "PULSE CHECK WARNING: PR2 - LOW",warning) ; violate.preset2 <= pr2_violate and model_times.error_flags.x_out ; wait for 0 ns ; violate.preset2 <= FALSE ; end process PR2_PULSE_CHECK ; ------------------------------------------------------------------------- JK1_SETUP_CHECK : process variable setup_jin1_violate : boolean ; variable setup_kin1_violate : boolean ; begin wait on clock1 until ( do_timing and (preset1= '1') and (clear1='1') and negedge(clock1)) ; if jin1 = '1' then setup_jin1_violate := SETUP_CHECK(jin1'last_event, model_times.prop_delays.tsu,ref, "SETUP CHECK WARNING: J1 - HIGH", warning) ; elsif jin1 = '0' then setup_jin1_violate := SETUP_CHECK(jin1'last_event, model_times.prop_delays.tsu,ref, "SETUP CHECK WARNING: J1 - LOW", warning) ; else null; -- do nothing end if ; if kin1 = '1' then setup_kin1_violate := SETUP_CHECK(kin1'last_event, model_times.prop_delays.tsu,ref, "SETUP CHECK WARNING: K1 - HIGH", warning) ; elsif kin1 = '0' then setup_kin1_violate := SETUP_CHECK(kin1'last_event, model_times.prop_delays.tsu,ref, "SETUP CHECK WARNING: K1 - LOW", warning) ; else null; -- do nothing end if ; violate.setup1 <= (setup_jin1_violate or setup_kin1_violate) and model_times.error_flags.x_out ; wait for 0 ns ; violate.setup1 <= FALSE ; end process JK1_SETUP_CHECK ; ------------------------------------------------------------------------- JK2_SETUP_CHECK : process variable setup_jin2_violate : boolean ; variable setup_kin2_violate : boolean ; begin wait on clock2 until ( do_timing and (preset2= '1') and (clear2='1') and negedge(clock2)) ; if jin2 = '1' then setup_jin2_violate := SETUP_CHECK(jin2'last_event, model_times.prop_delays.tsu,ref, "SETUP CHECK WARNING: J2 - HIGH", warning) ; elsif jin2 = '0' then setup_jin2_violate := SETUP_CHECK(jin2'last_event, model_times.prop_delays.tsu,ref, "SETUP CHECK WARNING: J2 - LOW", warning) ; else null; -- do nothing end if ; if kin2 = '1' then setup_kin2_violate := SETUP_CHECK(kin2'last_event, model_times.prop_delays.tsu,ref, "SETUP CHECK WARNING: K2 - HIGH", warning) ; elsif kin2 = '0' then setup_kin2_violate := SETUP_CHECK(kin2'last_event, model_times.prop_delays.tsu,ref, "SETUP CHECK WARNING: K2 - LOW", warning) ; else null; -- do nothing end if ; violate.setup2 <= (setup_jin2_violate or setup_kin2_violate) and model_times.error_flags.x_out ; wait for 0 ns ; violate.setup2 <= FALSE ; end process JK2_SETUP_CHECK ; ------------------------------------------------------------------------- J1_HOLD_CHECK : process variable hold_jin1_violate : boolean ; begin wait on jin1 until ( do_timing and (preset1= '1') and (clear1='1') and (clock1'last_value = '1') and (clock1 = '0')); hold_jin1_violate := HOLD_CHECK(clock1'last_event, model_times.prop_delays.th,ref, "HOLD CHECK WARNING: J1",warning) ; violate.j1_hold <= hold_jin1_violate and model_times.error_flags.x_out ; wait for 0 ns ; violate.j1_hold <= FALSE ; end process J1_HOLD_CHECK ; ------------------------------------------------------------------------- J2_HOLD_CHECK : process variable hold_jin2_violate : boolean ; begin wait on jin2 until ( do_timing and (preset2= '1') and (clear2='1') and (clock2'last_value = '1') and (clock2 = '0')); hold_jin2_violate := HOLD_CHECK(clock2'last_event, model_times.prop_delays.th,ref, "HOLD CHECK WARNING: J2",warning) ; violate.j2_hold <= hold_jin2_violate and model_times.error_flags.x_out ; wait for 0 ns ; violate.j2_hold <= FALSE ; end process J2_HOLD_CHECK ; ------------------------------------------------------------------------- K1_HOLD_CHECK : process variable hold_kin1_violate : boolean ; begin wait on kin1 until ( do_timing and (preset1= '1') and (clear1='1') and (clock1'last_value = '1') and (clock1 = '0')); hold_kin1_violate := HOLD_CHECK(clock1'last_event, model_times.prop_delays.th,ref, "HOLD CHECK WARNING: K1",warning) ; violate.k1_hold <= hold_kin1_violate and model_times.error_flags.x_out ; wait for 0 ns ; violate.k1_hold <= FALSE ; end process K1_HOLD_CHECK ; ------------------------------------------------------------------------- K2_HOLD_CHECK : process variable hold_kin2_violate : boolean ; begin wait on kin2 until ( do_timing and (preset2= '1') and (clear2='1') and (clock2'last_value = '1') and (clock2 = '0')); hold_kin2_violate := HOLD_CHECK(clock2'last_event, model_times.prop_delays.th,ref, "HOLD CHECK WARNING: K2",warning) ; violate.k2_hold <= hold_kin2_violate and model_times.error_flags.x_out ; wait for 0 ns ; violate.k2_hold <= FALSE ; end process K2_HOLD_CHECK ; ------------------------------------------------------------------------------ JK1 : process variable ffmode : modetype; begin wait on clear1, preset1, clock1, violate ; if (clear1'event = TRUE) then clear1_last <= now ; end if ; if (preset1'event = TRUE) then preset1_last <= now ; end if ; if (clock1'event = TRUE) then clock1_last <= now ; end if ; if (violate.clock1 or violate.clear1 or violate.preset1 or violate.setup1 or violate.j1_hold or violate.k1_hold) then ffmode := ERROR; elsif (clear1 = '0') then ffmode := CLEAR; elsif (preset1 = '0') then ffmode := PRESET; elsif (jin1 = '0' and kin1 = '0' and clear1 = '1' and preset1 = '1') then ffmode := PASS; elsif (jin1 = '1' and kin1 = '0' and clear1 = '1' and preset1 = '1') then ffmode := SET; elsif (jin1 = '0' and kin1 = '1' and clear1 = '1' and preset1 = '1') then ffmode := RESET; elsif (jin1 = '1' and kin1 = '1' and clear1 = '1' and preset1 = '1') then ffmode := TOGGLE; else ffmode := ERROR; end if; case ffmode is when ERROR => if (clear1 = 'U' or preset1 = 'U' or clock1 = 'U' or jin1 = 'U' or kin1 = 'U') then qout1 <= 'U' ; qbout1 <= 'U' ; else qout1 <= 'X' ; qbout1 <= 'X' ; end if ; when CLEAR => qbout1 <= transport '1' after model_times.prop_delays.tplh_clr_q ; if (preset1 = '1') then qout1 <= transport '0' after model_times.prop_delays.tphl_clr_q ; elsif (preset1 = '0') then qout1 <= transport '1' after model_times.prop_delays.tplh_clr_q ; elsif (preset1 = 'U' or clock1 = 'U' or jin1 = 'U' or kin1 = 'U') then qout1 <= 'U' ; else qout1 <= 'X' ; end if; when PRESET => qout1 <= transport '1' after model_times.prop_delays.tplh_pr_q; if (clear1 = '1') then qbout1 <= transport '0' after model_times.prop_delays.tphl_pr_q ; elsif (clear1 = '0') then qbout1 <= transport '1' after model_times.prop_delays.tplh_pr_q ; elsif (clear1 = 'U' or clock1 = 'U' or jin1 = 'U' or kin1 = 'U') then qbout1 <= 'U' ; else qbout1 <= 'X' ; end if; when PASS => if (negedge(clock1)) then null; -- do nothing end if; when SET => if (negedge(clock1)) then qout1 <= transport '1' after model_times.prop_delays.tplh_clk_q ; qbout1 <= transport '0' after model_times.prop_delays.tphl_clk_q ; elsif (clock1 = 'U' or (clock1 = 'X' and (jin1 = 'U' or kin1 = 'U'))) then if (qout1 /= '1') then qout1 <= 'U' ; end if ; if (qbout1 /= '0') then qbout1 <= 'U' ; end if ; elsif (clock1 = 'X') then if (qout1 /= '1') then qout1 <= 'X' ; end if ; if (qbout1 /= '0') then qbout1 <= 'X' ; end if ; end if; when RESET => if (negedge(clock1)) then qout1 <= transport '0' after model_times.prop_delays.tphl_clk_q; qbout1 <= transport '1' after model_times.prop_delays.tplh_clk_q ; elsif (clock1 = 'U' or (clock1 = 'X' and (jin1 = 'U' or kin1 = 'U'))) then if (qout1 /= '0') then qout1 <= 'U' ; end if ; if (qbout1 /= '1') then qbout1 <= 'U' ; end if ; elsif (clock1 = 'X') then if (qout1 /= '0') then qout1 <= 'X' ; end if ; if (qbout1 /= '1') then qbout1 <= 'X' ; end if ; end if; when TOGGLE => if (negedge(clock1)) then if (qout1 = '1') then qout1 <= transport '0' after model_times.prop_delays.tphl_clk_q ; qbout1 <= transport '1' after model_times.prop_delays.tplh_clk_q ; elsif (qout1 = '0') then qout1 <= transport '1' after model_times.prop_delays.tplh_clk_q ; qbout1 <= transport '0' after model_times.prop_delays.tphl_clk_q ; elsif (qout1 = 'U') then qout1 <= 'U' ; qbout1 <= 'U' ; else qout1 <= 'X' ; qbout1 <= 'X' ; end if ; elsif (clock1 = 'U') then qout1 <= 'U' ; qbout1 <= 'U' ; elsif (clock1 = 'X') then qout1 <= 'X' ; qbout1 <= 'X' ; end if; end case; end process JK1 ; ------------------------------------------------------------------------- JK2: process variable ffmode : modetype; begin wait on clear2, preset2, clock2, violate ; if (clear2'event = TRUE) then clear2_last <= now ; end if ; if (preset2'event = TRUE) then preset2_last <= now ; end if ; if (clock2'event = TRUE) then clock2_last <= now ; end if ; if (violate.clock2 or violate.clear2 or violate.preset2 or violate.setup2 or violate.j2_hold or violate.k2_hold) then ffmode := ERROR; elsif (clear2 = '0') then ffmode := CLEAR; elsif (preset2 = '0') then ffmode := PRESET; elsif (jin2 = '0' and kin2 = '0' and clear2 = '1' and preset2 = '1') then ffmode := PASS; elsif (jin2 = '1' and kin2 = '0' and clear2 = '1' and preset2 = '1') then ffmode := SET; elsif (jin2 = '0' and kin2 = '1' and clear2 = '1' and preset2 = '1') then ffmode := RESET; elsif (jin2 = '1' and kin2 = '1' and clear2 = '1' and preset2 = '1') then ffmode := TOGGLE; else ffmode := ERROR; end if; case ffmode is when ERROR => if (clear2 = 'U' or preset2 = 'U' or clock2 = 'U' or jin2 = 'U' or kin2 = 'U') then qout2 <= 'U' ; qbout2 <= 'U' ; else qout2 <= 'X' ; qbout2 <= 'X' ; end if ; when CLEAR => qbout2 <= transport '1' after model_times.prop_delays.tplh_clr_q ; if (preset2 = '1') then qout2 <= transport '0' after model_times.prop_delays.tphl_clr_q ; elsif (preset2 = '0') then qout2 <= transport '1' after model_times.prop_delays.tplh_clr_q ; elsif (preset2 = 'U' or clock2 = 'U' or jin2 = 'U' or kin2 = 'U') then qout2 <= 'U' ; else qout2 <= 'X' ; end if; when PRESET => qout2 <= transport '1' after model_times.prop_delays.tplh_pr_q; if (clear2 = '1') then qbout2 <= transport '0' after model_times.prop_delays.tphl_pr_q ; elsif (clear2 = '0') then qbout2 <= transport '1' after model_times.prop_delays.tplh_pr_q ; elsif (clear2 = 'U' or clock2 = 'U' or jin2 = 'U' or kin2 = 'U') then qbout2 <= 'U' ; else qbout2 <= 'X' ; end if; when PASS => if (negedge(clock2)) then null; -- do nothing end if; when SET => if (negedge(clock2)) then qout2 <= transport '1' after model_times.prop_delays.tplh_clk_q ; qbout2 <= transport '0' after model_times.prop_delays.tphl_clk_q ; elsif (clock2 = 'U' or (clock2 = 'X' and (jin2 = 'U' or kin2 = 'U'))) then if (qout2 /= '1') then qout2 <= 'U' ; end if ; if (qbout2 /= '0') then qbout2 <= 'U' ; end if ; elsif (clock2 = 'X') then if (qout2 /= '1') then qout2 <= 'X' ; end if ; if (qbout2 /= '0') then qbout2 <= 'X' ; end if ; end if; when RESET => if (negedge(clock2)) then qout2 <= transport '0' after model_times.prop_delays.tphl_clk_q; qbout2 <= transport '1' after model_times.prop_delays.tplh_clk_q ; elsif (clock2 = 'U' or (clock2 = 'X' and (jin2 = 'U' or kin2 = 'U'))) then if (qout2 /= '0') then qout2 <= 'U' ; end if ; if (qbout2 /= '1') then qbout2 <= 'U' ; end if ; elsif (clock2 = 'X') then if (qout2 /= '0') then qout2 <= 'X' ; end if ; if (qbout2 /= '1') then qbout2 <= 'X' ; end if ; end if; when TOGGLE => if (negedge(clock2)) then if (qout2 = '1') then qout2 <= transport '0' after model_times.prop_delays.tphl_clk_q ; qbout2 <= transport '1' after model_times.prop_delays.tplh_clk_q ; elsif (qout2 = '0') then qout2 <= transport '1' after model_times.prop_delays.tplh_clk_q ; qbout2 <= transport '0' after model_times.prop_delays.tphl_clk_q ; elsif (qout2 = 'U') then qout2 <= 'U' ; qbout2 <= 'U' ; else qout2 <= 'X' ; qbout2 <= 'X' ; end if ; elsif (clock2 = 'U') then qout2 <= 'U' ; qbout2 <= 'U' ; elsif (clock2 = 'X') then qout2 <= 'X' ; qbout2 <= 'X' ; end if; end case; end process JK2 ; END BEHAVIORAL;