// ============================================================================ // f74.v — 54F/74F74 Dual D-Type Positive Edge-Triggered Flip-Flop // // Fairchild FAST (Advanced Schottky TTL) // Source: docs/devices/54F74F74.txt (1980 Fairchild FAST Data Book, // pages 4-12 ... 4-13) // // Each half: D transferred to Q on the rising edge of CP. Direct Clear // (CD_n) and Direct Set (SD_n) are asynchronous and active LOW; a LOW on // CD_n forces Q LOW, a LOW on SD_n forces Q HIGH, independent of clock. // Simultaneous LOW on CD_n and SD_n makes BOTH Q and Q_n HIGH. // // Timing values from the data sheet AC Characteristics table, // 54F/74F column (T_A = +25 C, V_CC = +5.0 V, C_L = 15 pF), min:typ:max ns. // The data sheet also lists faster typ-only values for CD_n/SD_n when // V_CP <= 0.8 V; this model uses the specified V_CP >= 2.0 V values. // // Ports are scalar and named after the data sheet pin names: Icarus Verilog // does not fully support multi-bit (parallel) specify path connections, so // vector ports would get incorrect per-bit delays. // ============================================================================ `timescale 1ns/100ps module f74 ( input wire cd1_n, // direct clear 1 (active LOW) input wire d1, // data 1 input wire cp1, // clock pulse 1 (active rising edge) input wire sd1_n, // direct set 1 (active LOW) output reg q1, // output 1 output reg q1_n, // complementary output 1 input wire cd2_n, // direct clear 2 (active LOW) input wire d2, // data 2 input wire cp2, // clock pulse 2 (active rising edge) input wire sd2_n, // direct set 2 (active LOW) output reg q2, // output 2 output reg q2_n // complementary output 2 ); // Clocked/asynchronous state, one bit per half. The output stage is // level sensitive so that simultaneous LOW on CD_n and SD_n drives // BOTH Q and Q_n HIGH (per data sheet) and releasing one input // restores the state demanded by the input still held LOW. reg state1, state2; always @(posedge cp1 or negedge cd1_n or negedge sd1_n) begin if (!cd1_n) state1 <= 1'b0; else if (!sd1_n) state1 <= 1'b1; else state1 <= d1; end always @(posedge cp2 or negedge cd2_n or negedge sd2_n) begin if (!cd2_n) state2 <= 1'b0; else if (!sd2_n) state2 <= 1'b1; else state2 <= d2; end always @(*) begin if (!cd1_n && !sd1_n) begin q1 = 1'b1; q1_n = 1'b1; end else if (!cd1_n) begin q1 = 1'b0; q1_n = 1'b1; end else if (!sd1_n) begin q1 = 1'b1; q1_n = 1'b0; end else begin q1 = state1; q1_n = ~state1; end end always @(*) begin if (!cd2_n && !sd2_n) begin q2 = 1'b1; q2_n = 1'b1; end else if (!cd2_n) begin q2 = 1'b0; q2_n = 1'b1; end else if (!sd2_n) begin q2 = 1'b1; q2_n = 1'b0; end else begin q2 = state2; q2_n = ~state2; end end specify // Propagation delay CP to Q or Q_n (data sheet: 2.0/4.4/6.0, // 2.0/5.2/7.0 ns) specparam tlh_cp_q = 2.0:4.4:6.0; specparam thl_cp_q = 2.0:5.2:7.0; // Propagation delay CD_n or SD_n to Q or Q_n, V_CP >= 2.0 V // (data sheet: 2.0/3.6/5.5, 2.0/6.5/8.0 ns) specparam tlh_csd_q = 2.0:3.6:5.5; specparam thl_csd_q = 2.0:6.5:8.0; (cp1 => q1) = (tlh_cp_q, thl_cp_q); (cp1 => q1_n) = (tlh_cp_q, thl_cp_q); (cd1_n => q1) = (tlh_csd_q, thl_csd_q); (sd1_n => q1) = (tlh_csd_q, thl_csd_q); (cd1_n => q1_n) = (tlh_csd_q, thl_csd_q); (sd1_n => q1_n) = (tlh_csd_q, thl_csd_q); (cp2 => q2) = (tlh_cp_q, thl_cp_q); (cp2 => q2_n) = (tlh_cp_q, thl_cp_q); (cd2_n => q2) = (tlh_csd_q, thl_csd_q); (sd2_n => q2) = (tlh_csd_q, thl_csd_q); (cd2_n => q2_n) = (tlh_csd_q, thl_csd_q); (sd2_n => q2_n) = (tlh_csd_q, thl_csd_q); // AC operating requirements (data sheet, +25 C 5.0 V minima): // ts(H) 2.0, ts(L) 3.0, th(H) 1.0, th(L) 1.0, tw(H) CP 4.0, // tw(L) CP 5.0, tw(L) CD_n/SD_n 4.0, trec 2.0 ns. // Icarus Verilog does not support timing checks; kept (guarded) // for simulators that do. `ifndef __ICARUS__ specparam ts_h = 2.0; specparam ts_l = 3.0; specparam th_h = 1.0; specparam th_l = 1.0; specparam tw_cp_h = 4.0; specparam tw_cp_l = 5.0; specparam tw_csd_l = 4.0; specparam trec = 2.0; // The sheet gives different setup minima for Dn HIGH and Dn LOW, so // the two arrival edges are checked separately. th(H) and th(L) are // both 1.0, so one unqualified $hold covers th_h and th_l alike. $setup(posedge d1, posedge cp1, ts_h); $setup(negedge d1, posedge cp1, ts_l); $setup(posedge d2, posedge cp2, ts_h); $setup(negedge d2, posedge cp2, ts_l); $hold(posedge cp1, d1, th_h); $hold(posedge cp2, d2, th_h); $width(posedge cp1, tw_cp_h); $width(posedge cp2, tw_cp_h); $width(negedge cp1, tw_cp_l); $width(negedge cp2, tw_cp_l); $width(negedge cd1_n, tw_csd_l); $width(negedge cd2_n, tw_csd_l); $width(negedge sd1_n, tw_csd_l); $width(negedge sd2_n, tw_csd_l); $recovery(posedge cd1_n, posedge cp1, trec); $recovery(posedge cd2_n, posedge cp2, trec); $recovery(posedge sd1_n, posedge cp1, trec); $recovery(posedge sd2_n, posedge cp2, trec); `endif endspecify endmodule