// ============================================================================ // f189.v — 54F/74F189 64-Bit Random Access Memory (16 words x 4 bits, // 3-State Inverting Outputs) // // Fairchild FAST (Advanced Schottky TTL) // Source: docs/devices/54F74F189.txt (1980 Fairchild FAST Data Book, // pages 4-45 ... 4-47) — PRELIMINARY data sheet. // // Function table (data sheet): // CS_n WE_n | Operation | Outputs // ----+-----+-----------+-------------------------- // L L | Write | High Impedance // L H | Read | Complement of Stored Data // H X | Inhibit | High Impedance // // The write is level sensitive: the data buffers are gated by (CS_n LOW and // WE_n LOW), so the addressed word follows D while both are LOW and holds // whatever was present when WE_n (or CS_n) returns HIGH. This matches the // data sheet operating requirements, which specify setup/hold of A and D // with respect to WE_n (address ts/th = 0 ns). // // 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 // sheet gives TYP values ONLY (Min/Max columns blank); each specparam below // is a single typ value, noted per row. // // 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 f189 ( input wire a0, a1, a2, a3, // address inputs input wire cs_n, // chip select (active LOW) input wire we_n, // write enable (active LOW) input wire d1, d2, d3, d4, // data inputs output wire o1_n, o2_n, o3_n, o4_n // inverted data outputs (3-state) ); // 16 words x 4 bits; bit 0 of each word is D1/O1_n, bit 3 is D4/O4_n. reg [3:0] mem [0:15]; wire [3:0] din = {d4, d3, d2, d1}; // Level-sensitive write, gated by (CS_n LOW & WE_n LOW) per the data // sheet block diagram ("data buffers gated by (WE . CS)"). always @(*) if (!cs_n && !we_n) mem[{a3, a2, a1, a0}] <= din; // 3-state read: outputs active only in Read mode (CS_n LOW, WE_n HIGH) // and carry the COMPLEMENT of the stored data. wire read = !cs_n && we_n; assign o1_n = read ? ~mem[{a3, a2, a1, a0}][0] : 1'bz; assign o2_n = read ? ~mem[{a3, a2, a1, a0}][1] : 1'bz; assign o3_n = read ? ~mem[{a3, a2, a1, a0}][2] : 1'bz; assign o4_n = read ? ~mem[{a3, a2, a1, a0}][3] : 1'bz; specify // Access time, address to output (data sheet: tPLH 20, tPHL 20 ns, // typ only — preliminary sheet, Min/Max blank), Fig. 2-17, 2-23. specparam tlh_a_o = 20; specparam thl_a_o = 20; // Enable/disable, CS_n to output (data sheet typ only: tPZH 12, // tPZL 12, tPHZ 12, tPLZ 12 ns), Fig. 2-25 ... 2-27. // Direct 0->1 / 1->0 transitions cannot occur via CS_n (the output // always passes through Z); those slots reuse tPZH / tPZL. specparam tlh_cs_o = 12; // (unreachable 0->1 slot, = tPZH) specparam thl_cs_o = 12; // (unreachable 1->0 slot, = tPZL) specparam tlz_cs_o = 12; // tPLZ (0->Z) specparam tzh_cs_o = 12; // tPZH (Z->1) specparam thz_cs_o = 12; // tPHZ (1->Z) specparam tzl_cs_o = 12; // tPZL (Z->0) // Enable/disable, WE_n to output (data sheet typ only: tPZH 12, // tPZL 12, tPHZ 12, tPLZ 12 ns), Fig. 2-25 ... 2-27. specparam tlh_we_o = 12; // (unreachable 0->1 slot, = tPZH) specparam thl_we_o = 12; // (unreachable 1->0 slot, = tPZL) specparam tlz_we_o = 12; // tPLZ (0->Z) specparam tzh_we_o = 12; // tPZH (Z->1) specparam thz_we_o = 12; // tPHZ (1->Z) specparam tzl_we_o = 12; // tPZL (Z->0) (a0, a1, a2, a3 => o1_n) = (tlh_a_o, thl_a_o); (a0, a1, a2, a3 => o2_n) = (tlh_a_o, thl_a_o); (a0, a1, a2, a3 => o3_n) = (tlh_a_o, thl_a_o); (a0, a1, a2, a3 => o4_n) = (tlh_a_o, thl_a_o); (cs_n => o1_n) = (tlh_cs_o, thl_cs_o, tlz_cs_o, tzh_cs_o, thz_cs_o, tzl_cs_o); (cs_n => o2_n) = (tlh_cs_o, thl_cs_o, tlz_cs_o, tzh_cs_o, thz_cs_o, tzl_cs_o); (cs_n => o3_n) = (tlh_cs_o, thl_cs_o, tlz_cs_o, tzh_cs_o, thz_cs_o, tzl_cs_o); (cs_n => o4_n) = (tlh_cs_o, thl_cs_o, tlz_cs_o, tzh_cs_o, thz_cs_o, tzl_cs_o); (we_n => o1_n) = (tlh_we_o, thl_we_o, tlz_we_o, tzh_we_o, thz_we_o, tzl_we_o); (we_n => o2_n) = (tlh_we_o, thl_we_o, tlz_we_o, tzh_we_o, thz_we_o, tzl_we_o); (we_n => o3_n) = (tlh_we_o, thl_we_o, tlz_we_o, tzh_we_o, thz_we_o, tzl_we_o); (we_n => o4_n) = (tlh_we_o, thl_we_o, tlz_we_o, tzh_we_o, thz_we_o, tzl_we_o); // AC operating requirements (data sheet, +25 C 5.0 V minima): // ts(H/L) A to WE_n 0, th(H/L) A to WE_n 0, ts(H/L) D to WE_n 20, // th(H/L) D to WE_n 0, tw(L) WE_n 20 ns. The ts(L)/th(L) CS_n to // WE_n rows are blank on the data sheet and are omitted. // Icarus Verilog does not support timing checks; kept (guarded) // for simulators that do. `ifndef __ICARUS__ specparam ts_a = 0; // ts(H) and ts(L), A_n to WE_n specparam th_a = 0; // th(H) and th(L), A_n to WE_n specparam ts_d = 20; // ts(H) and ts(L), D_n to WE_n specparam th_d = 0; // th(H) and th(L), D_n to WE_n specparam tw_we_l = 20; // tw(L) WE_n pulse width $setup(a0, posedge we_n, ts_a); $setup(a1, posedge we_n, ts_a); $setup(a2, posedge we_n, ts_a); $setup(a3, posedge we_n, ts_a); $hold(posedge we_n, a0, th_a); $hold(posedge we_n, a1, th_a); $hold(posedge we_n, a2, th_a); $hold(posedge we_n, a3, th_a); $setup(d1, posedge we_n, ts_d); $setup(d2, posedge we_n, ts_d); $setup(d3, posedge we_n, ts_d); $setup(d4, posedge we_n, ts_d); $hold(posedge we_n, d1, th_d); $hold(posedge we_n, d2, th_d); $hold(posedge we_n, d3, th_d); $hold(posedge we_n, d4, th_d); $width(negedge we_n, tw_we_l); `endif endspecify endmodule