// ============================================================================ // f109.v — 54F/74F109 Dual JK-bar Positive Edge-Triggered Flip-Flop // // Fairchild FAST (Advanced Schottky TTL) // Source: docs/devices/54F74F109.txt (1980 Fairchild FAST Data Book, // pages 4-14 ... 4-15; preliminary data sheet) // // Each half: on the rising edge of CP, the state advances per the data // sheet truth table (note: the K input pin is active LOW, named K-bar): // J=L, K_n=H -> no change J=L, K_n=L -> Q=L // J=H, K_n=H -> Q=H J=H, K_n=L -> toggle // Direct Clear (CD_n) and Direct Set (SD_n) are asynchronous and active // LOW, 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). // The preliminary data sheet gives TYPICAL values only (Min/Max columns // left blank), so each specparam carries just the typ value. // The data sheet also lists faster typ-only values for CD_n/SD_n when // V_CP <= 0.8 V (tPLH 2.8, tPHL 5.5 ns); this model uses the specified // V_CP >= 2.0 V values (tPLH 3.6, tPHL 6.5 ns). // // 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 f109 ( input wire cd1_n, // direct clear 1 (active LOW) input wire j1, // data input J1 input wire k1_n, // data input K-bar 1 (active LOW) 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 j2, // data input J2 input wire k2_n, // data input K-bar 2 (active LOW) 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: simultaneous LOW on CD_n and SD_n drives BOTH Q and // Q_n HIGH (per data sheet), and while either async input is held LOW // it alone dictates the outputs, so 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 case ({j1, k1_n}) 2'b01: ; // J=L, K_n=H: no change 2'b00: state1 <= 1'b0; // J=L, K_n=L: Q=L 2'b11: state1 <= 1'b1; // J=H, K_n=H: Q=H 2'b10: state1 <= ~state1; // J=H, K_n=L: toggle endcase 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 case ({j2, k2_n}) 2'b01: ; // J=L, K_n=H: no change 2'b00: state2 <= 1'b0; // J=L, K_n=L: Q=L 2'b11: state2 <= 1'b1; // J=H, K_n=H: Q=H 2'b10: state2 <= ~state2; // J=H, K_n=L: toggle endcase 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 typ only: // tPLH 4.4, tPHL 5.2 ns; min/max blank on preliminary sheet) specparam tlh_cp_q = 4.4; specparam thl_cp_q = 5.2; // Propagation delay CD_n or SD_n to Q or Q_n, V_CP >= 2.0 V // (data sheet typ only: tPLH 3.6, tPHL 6.5 ns) specparam tlh_csd_q = 3.6; specparam thl_csd_q = 6.5; (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. // (fmax 125 MHz typ per the AC Characteristics table.) // 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 the J/K inputs HIGH and // LOW, so the two arrival edges are checked separately (the level on // the pin is what ts(H)/ts(L) select, regardless of K_n's active-LOW // name). th(H) and th(L) are both 1.0, so one unqualified $hold // covers th_h and th_l alike. $setup(posedge j1, posedge cp1, ts_h); $setup(negedge j1, posedge cp1, ts_l); $setup(posedge k1_n, posedge cp1, ts_h); $setup(negedge k1_n, posedge cp1, ts_l); $setup(posedge j2, posedge cp2, ts_h); $setup(negedge j2, posedge cp2, ts_l); $setup(posedge k2_n, posedge cp2, ts_h); $setup(negedge k2_n, posedge cp2, ts_l); $hold(posedge cp1, j1, th_h); $hold(posedge cp1, k1_n, th_h); $hold(posedge cp2, j2, th_h); $hold(posedge cp2, k2_n, 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