// ============================================================================ // f181.v — 54F/74F181 4-Bit Arithmetic Logic Unit // // Fairchild FAST (Advanced Schottky TTL) // Source: docs/devices/54F74F181.txt (1980 Fairchild FAST Data Book, // pages 4-37 ... 4-40) // // The model follows the structure of the data sheet's Logic Diagram rather // than enumerating the 32 rows of the Function Table. Each bit position // forms a carry-propagate term p and a carry-generate term g from the // operands and the select code; those feed a carry lookahead chain, and // the /F outputs are the half-sum of each stage XORed with its carry: // // A, B = de-inverted operands (active-LOW inputs, so A = ~/A) // p_i = A + /B * /S3 + B * /S2 // g_i = A * (/S1 * /S0 + B * S0 * /S1 + /B * S1 * /S0) // c_0 = Cn * /M (M inhibits all internal carries) // c_i+1 = (g_i + p_i * c_i) * /M // F_i = (p_i * /g_i) xor c_i // /F_i pin = ~F_i // // One pair of per-bit terms reproduces both columns of the Function Table: // with the carries inhibited (M = H) F_i collapses to the half-sum alone // and yields the 16 logic functions, and with them enabled (M = L) the // chain yields the 16 arithmetic functions. Equivalently, each select // code names a pair of operands X, Y that the internal adder sums: // // S3-S0 X Y ARITHMETIC (M = L) LOGIC (M = H) = X xor Y // ----- ------ ------ --------------------- ----------------------- // LLLL A 1111 A minus 1 /A // LLLH A * B 1111 A * B minus 1 /(A * B) // LLHL A * /B 1111 A * /B minus 1 /A + B // LLHH 0000 1111 minus 1 Logic 1 // LHLL A A + /B A plus (A + /B) /(A + B) // LHLH A * B A + /B A * B plus (A + /B) /B // LHHL A /B A minus B minus 1 /(A xor B) // LHHH A + /B 0000 A + /B A + /B // HLLL A A + B A plus (A + B) /A * B // HLLH A B A plus B A xor B // HLHL A * /B A + B A * /B plus (A + B) B // HLHH A + B 0000 A + B A + B // HHLL A A A plus A Logic 0 // HHLH A * B A A * B plus A A * /B // HHHL A * /B A A * /B plus A A * B // HHHH A 0000 A A // // /P is the AND of the four p terms and /G the lookahead generate, so both // are unaffected by Cn, as the data sheet states. Neither they nor Cn+4 // are gated by M — the Logic Diagram routes /M only to the carry gates // feeding the /F outputs — so Cn+4 = G + P * Cn in both modes. // // A = B output: open-collector — Hi-Z when all /F outputs are HIGH, // otherwise driven LOW. An external pull-up is required. // // NOTE on state-dependent timing: // The AC characteristics table lists separate propagation delays for // Sum, Dif, and Logic modes. Icarus Verilog *does* support // state-dependent (conditional) path delays in specify blocks — probed // directly with a two-branch `if (m) .../if (!m) ...` pair driving the // same destination at different delays, which Icarus resolves correctly // to the taken branch's value. M is the one signal here that a path // delay can actually be conditioned on: it is a real, always-available // input, and Logic mode (M = H) is exactly "M is HIGH" — a clean, // mechanical split, the same shape as the probe. So the /A or /B to /F // paths below are conditioned on M: the Logic-mode branch uses the data // sheet's Logic row directly, and the Arithmetic-mode branch (M = L) // uses a conservative merge of just the Sum and Dif rows (Logic no // longer needs to be folded in, since it now has its own branch). // // Sum and Dif are not a signal you can branch on, though, so that merge // is as far as the split can go. They are two specific select codes // Fairchild chose to characterize two different critical paths through // the internal carry lookahead network (an add-like code and a // subtract-like code) — a characterization methodology, not a // functional partition of the 16 arithmetic operations into two classes // covering all of them. There is no signal available at the pins (M, // the select codes, or any combination) that tells you which of the // two characterized paths a given operation's actual delay resembles, // so a further split would mean guessing a S3-S2-S1-S0 grouping the // data sheet never states. The Arithmetic-mode branch therefore stays a // conservative elementwise (min, typ, max) merge of the Sum and Dif // rows, same as before but now Logic-free. // // /G, /P and Cn+4 only ever carry Sum/Dif rows in the AC table (no // Logic row at all), which confirms the header comment above: M gates // only the /F outputs, not the p/g lookahead network, so these three // paths are the same carry-network paths in both modes and have no M // dependency to condition on either. They stay a Sum/Dif merge for the // same characterization-methodology reason as the Arithmetic /F branch // above — an inherent limit of what the data sheet gives, not a tooling // one. // // 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 f181 ( input wire b0_n, // Pin 1 — /B0 operand input (active LOW) input wire a0_n, // Pin 2 — /A0 operand input (active LOW) input wire s3, // Pin 3 — S3 function select 3 input wire s2, // Pin 4 — S2 function select 2 input wire s1, // Pin 5 — S1 function select 1 input wire s0, // Pin 6 — S0 function select 0 input wire cn, // Pin 7 — Cn carry input input wire m, // Pin 8 — M mode control (H=logic, L=arithmetic) output wire f0_n, // Pin 9 — /F0 function output (active LOW) output wire f1_n, // Pin 10 — /F1 function output (active LOW) output wire f2_n, // Pin 11 — /F2 function output (active LOW) output wire f3_n, // Pin 13 — /F3 function output (active LOW) output wire a_eq_b, // Pin 14 — A = B comparator output (open collector) output wire p_n, // Pin 15 — /P carry propagate output (active LOW) output wire cn4, // Pin 16 — Cn+4 carry output output wire g_n, // Pin 17 — /G carry generate output (active LOW) input wire b3_n, // Pin 18 — /B3 operand input (active LOW) input wire a3_n, // Pin 19 — /A3 operand input (active LOW) input wire b2_n, // Pin 20 — /B2 operand input (active LOW) input wire a2_n, // Pin 21 — /A2 operand input (active LOW) input wire b1_n, // Pin 22 — /B1 operand input (active LOW) input wire a1_n // Pin 23 — /A1 operand input (active LOW) ); // ------------------------------------------------------------------ // De-inverted operands (active-LOW inputs, so A = ~/A) // ------------------------------------------------------------------ wire [3:0] a = ~{a3_n, a2_n, a1_n, a0_n}; wire [3:0] b = ~{b3_n, b2_n, b1_n, b0_n}; // ------------------------------------------------------------------ // Per-bit carry propagate and generate terms selected by S3 - S0 // ------------------------------------------------------------------ wire [3:0] p = a | (~b & {4{~s3}}) | (b & {4{~s2}}); wire [3:0] g = a & ( {4{~s1 & ~s0}} | ( b & {4{~s1 & s0}}) | (~b & {4{ s1 & ~s0}}) ); // ------------------------------------------------------------------ // Carry lookahead chain. M HIGH inhibits every internal carry, which // leaves each stage's half-sum standing alone as the logic function. // ------------------------------------------------------------------ wire [3:0] c; assign c[0] = cn & ~m; assign c[1] = (g[0] | (p[0] & c[0])) & ~m; assign c[2] = (g[1] | (p[1] & c[1])) & ~m; assign c[3] = (g[2] | (p[2] & c[2])) & ~m; wire [3:0] f = (p & ~g) ^ c; // ------------------------------------------------------------------ // Group carry lookahead outputs. Not gated by M and, by construction, // independent of Cn. // ------------------------------------------------------------------ wire p_group = &p; wire g_group = g[3] | (p[3] & g[2]) | (p[3] & p[2] & g[1]) | (p[3] & p[2] & p[1] & g[0]); // ------------------------------------------------------------------ // Output pins // ------------------------------------------------------------------ assign f0_n = ~f[0]; assign f1_n = ~f[1]; assign f2_n = ~f[2]; assign f3_n = ~f[3]; assign p_n = ~p_group; assign g_n = ~g_group; assign cn4 = g_group | (p_group & cn); // Open collector: released HIGH only when all four /F outputs are HIGH. assign a_eq_b = (f == 4'b0000) ? 1'bz : 1'b0; // ------------------------------------------------------------------ // Timing // ------------------------------------------------------------------ specify // Propagation delays (ns), from the data sheet AC Characteristics // table, 54F/74F column (T_A = +25 C, V_CC = +5.0 V, C_L = 15 pF). // Values are min:typ:max. // // For /F outputs, M cleanly selects Logic vs Arithmetic mode, so // the paths below are conditioned on M; see the NOTE above. // // For /G and /P (and /A or /B to Cn+4 below), no such split is // available — see the NOTE above — so each figure is the // elementwise (min, typ, max) worst case of the Sum and Dif rows, // computed directly from the data sheet rather than assumed to be // whichever mode looked wider by eye. // Cn to Cn+4 specparam tlh_cn_cn4 = 2.0:5.0:6.5; specparam thl_cn_cn4 = 2.0:5.0:6.5; // /A or /B to Cn+4 — Sum tPLH 6.0:8.5:11.5, tPHL 6.0:9.0:11.5; // Dif tPLH 6.0:9.0:11.5, tPHL 6.0:9.0:11.5. Elementwise merge: specparam tlh_ab_cn4 = 6.0:9.0:11.5; specparam thl_ab_cn4 = 6.0:9.0:11.5; // Cn to /F specparam tlh_cn_f = 2.0:5.0:6.7; specparam thl_cn_f = 2.0:4.5:6.0; // /A or /B to /F, Logic mode (M = H) — taken directly from the // data sheet's Logic row, no merge needed. specparam tlh_ab_f_logic = 3.0:5.0:8.0; specparam thl_ab_f_logic = 3.0:5.0:9.0; // /A or /B to /F, Arithmetic mode (M = L) — elementwise merge of // the Sum and Dif rows only (Logic now has its own branch above). // Each mode has both a same-bit row (/Ai or /Bi to /Fi) and an // any-to-any row (Any /A or /B to any /F); all four feed the merge // since the model does not distinguish same-bit vs cross-bit paths: // Sum same-bit: tPLH 3.0:5.5:8.0, tPHL 3.0:4.5:9.0 // Sum any-any: tPLH 3.0:6.0:10, tPHL 3.0:6.0:10 // Dif same-bit: tPLH 4.0:6.0:10, tPHL 4.0:5.0:10 // Dif any-any: tPLH 3.5:7.0:11, tPHL 3.5:7.0:11 // merge: tPLH 3.0:7.0:11, tPHL 3.0:7.0:11 specparam tlh_ab_f_arith = 3.0:7.0:11; specparam thl_ab_f_arith = 3.0:7.0:11; // /A or /B to /G — Sum tPLH 2.0:4.0:7.0, tPHL 2.0:4.0:7.0; // Dif tPLH 2.0:5.0:7.0, tPHL 2.0:5.0:8.0. Elementwise merge is // NOT simply "take Dif": Dif dominates typ and tPHL's max, but // tPLH's max is 7.0 in both rows, not 8.0 (that 8.0 belongs only // to tPHL/Dif) — so tPLH and tPHL merge to different maxima. specparam tlh_ab_g = 2.0:5.0:7.0; specparam thl_ab_g = 2.0:5.0:8.0; // /A or /B to /P — Sum tPLH 2.0:4.0:6.8, tPHL 2.0:4.0:7.5; // Dif tPLH 3.0:5.0:7.0, tPHL 3.0:5.0:7.5. Elementwise merge: // Sum's min (2.0) is tighter than Dif's (3.0) on both edges, so // the merged min comes from Sum, not Dif, in both rows. specparam tlh_ab_p = 2.0:5.0:7.0; specparam thl_ab_p = 2.0:5.0:7.5; // /A or /B to A = B (Dif mode only) specparam tlh_ab_eq = 8.0:13:16; specparam thl_ab_eq = 6.0:10:12.5; // Carry paths (cn => cn4) = (tlh_cn_cn4, thl_cn_cn4); (cn => f0_n) = (tlh_cn_f, thl_cn_f); (cn => f1_n) = (tlh_cn_f, thl_cn_f); (cn => f2_n) = (tlh_cn_f, thl_cn_f); (cn => f3_n) = (tlh_cn_f, thl_cn_f); // Operand paths — all /A and /B inputs feed all /F outputs, // /G, /P, Cn+4, and A=B through the internal logic. /F is // conditioned on M (see the NOTE above); the rest are not, since // M does not reach the p/g lookahead network. if (m) (a0_n, b0_n, a1_n, b1_n, a2_n, b2_n, a3_n, b3_n => f0_n) = (tlh_ab_f_logic, thl_ab_f_logic); if (!m) (a0_n, b0_n, a1_n, b1_n, a2_n, b2_n, a3_n, b3_n => f0_n) = (tlh_ab_f_arith, thl_ab_f_arith); if (m) (a0_n, b0_n, a1_n, b1_n, a2_n, b2_n, a3_n, b3_n => f1_n) = (tlh_ab_f_logic, thl_ab_f_logic); if (!m) (a0_n, b0_n, a1_n, b1_n, a2_n, b2_n, a3_n, b3_n => f1_n) = (tlh_ab_f_arith, thl_ab_f_arith); if (m) (a0_n, b0_n, a1_n, b1_n, a2_n, b2_n, a3_n, b3_n => f2_n) = (tlh_ab_f_logic, thl_ab_f_logic); if (!m) (a0_n, b0_n, a1_n, b1_n, a2_n, b2_n, a3_n, b3_n => f2_n) = (tlh_ab_f_arith, thl_ab_f_arith); if (m) (a0_n, b0_n, a1_n, b1_n, a2_n, b2_n, a3_n, b3_n => f3_n) = (tlh_ab_f_logic, thl_ab_f_logic); if (!m) (a0_n, b0_n, a1_n, b1_n, a2_n, b2_n, a3_n, b3_n => f3_n) = (tlh_ab_f_arith, thl_ab_f_arith); (a0_n, b0_n, a1_n, b1_n, a2_n, b2_n, a3_n, b3_n => cn4) = (tlh_ab_cn4, thl_ab_cn4); (a0_n, b0_n, a1_n, b1_n, a2_n, b2_n, a3_n, b3_n => g_n) = (tlh_ab_g, thl_ab_g); (a0_n, b0_n, a1_n, b1_n, a2_n, b2_n, a3_n, b3_n => p_n) = (tlh_ab_p, thl_ab_p); (a0_n, b0_n, a1_n, b1_n, a2_n, b2_n, a3_n, b3_n => a_eq_b) = (tlh_ab_eq, thl_ab_eq); endspecify endmodule