// ============================================================================ // f289.v — 54F/74F289 64-Bit Random Access Memory (16 words x 4 bits, // Open-Collector Inverting Outputs) // // Fairchild FAST (Advanced Schottky TTL) // Source: docs/devices/54F74F289.txt (1980 Fairchild FAST Data Book, // pages 4-91 ... 4-93) — PRELIMINARY data sheet. // // Function table (data sheet): // CS_n WE_n | Operation | Outputs // ----+-----+-----------+-------------------------- // L L | Write | Off (HIGH via pull-up) // L H | Read | Complement of Stored Data // H X | Inhibit | Off (HIGH via pull-up) // // Open-collector outputs: the chip drives only LOW actively; the off state // is high impedance and requires an external pull-up (the data sheet AC // figures are specified with R_L = 280 ohm). Modeled here as // `drive-low-or-Z`; a testbench/pull-up resolves the off state to HIGH. // // 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, R_L = 280 ohm). // 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 f289 ( 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 (open collector) ); // 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 logic diagram ("data buffers gated by a NAND of WE and CS"). always @(*) if (!cs_n && !we_n) mem[{a3, a2, a1, a0}] <= din; // Read: outputs active only in Read mode (CS_n LOW, WE_n HIGH) and // carry the COMPLEMENT of the stored data. Open collector: actively // pulls LOW only when the stored bit is 1 (output complement = 0); // otherwise the output is off (Z, pulled HIGH externally). wire read = !cs_n && we_n; assign o1_n = (read && mem[{a3, a2, a1, a0}][0]) ? 1'b0 : 1'bz; assign o2_n = (read && mem[{a3, a2, a1, a0}][1]) ? 1'b0 : 1'bz; assign o3_n = (read && mem[{a3, a2, a1, a0}][2]) ? 1'b0 : 1'bz; assign o4_n = (read && mem[{a3, a2, a1, a0}][3]) ? 1'b0 : 1'bz; specify // Access time, address to output (data sheet: tPLH 20, tPHL 20 ns, // typ only — preliminary sheet, Min/Max blank; R_L = 280 ohm), // Fig. 2-17, 2-23. On an open-collector output a "rise" is a // release to Z (pulled HIGH externally); for the 2-delay form that // 0->Z transition uses min(tPLH, tPHL), which equals tPLH here. specparam tlh_a_o = 20; specparam thl_a_o = 20; // CS_n to output (data sheet typ only: tPHL access 12 ns [drive // LOW on select], tPLH disable 12 ns [release on deselect]), // Fig. 2-17, 2-19. specparam tlh_cs_o = 12; // tPLH (release to off/HIGH) specparam thl_cs_o = 12; // tPHL (drive LOW) // WE_n to output (data sheet typ only: tPHL recovery 12 ns [drive // LOW when read resumes], tPLH disable 12 ns [release when write // begins]), Fig. 2-17, 2-18. specparam tlh_we_o = 12; // tPLH (release to off/HIGH) specparam thl_we_o = 12; // tPHL (drive LOW) (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); (cs_n => o2_n) = (tlh_cs_o, thl_cs_o); (cs_n => o3_n) = (tlh_cs_o, thl_cs_o); (cs_n => o4_n) = (tlh_cs_o, thl_cs_o); (we_n => o1_n) = (tlh_we_o, thl_we_o); (we_n => o2_n) = (tlh_we_o, thl_we_o); (we_n => o3_n) = (tlh_we_o, thl_we_o); (we_n => o4_n) = (tlh_we_o, thl_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