///////////////////////////////////////////////////////////////////////////////// // // ECE 554 // // Matt King // matthewking@wisc.edu // ///////////////////////////////////////////////////////////////////////////////// // // Verilog model of SRAM including timing characteristics // simulates behavior of the AS7C4096-15 // // Initial memory contents are placed in mem.txt in hex in the format: // @address data_word // @address data_word // ... // // memory contents are dumped to mem.out at the positive edge of the reset signal // in the same format as the mem.dat file. (in order to dump memory at the end of a // simulation there must be a manually generated positive edge to the reset signal) // only a select number of addresses are dumped, they must be set manually in this // file (on line 199). // // This module will also issue warnings (printed in the command window of Modelsim) // if setup and cycle time constraints for the SRAM are violated. While violating // these constraints will not damage the SRAM, data integrity cannot be insured // if they are violated. // // If you have any questions about this module please email: matthewking@wisc.edu // ///////////////////////////////////////////////////////////////////////////////// // // For the purposes of using this module to verify your memory controller, // do not use a data value of FF in your simulations. This module drives // a value of FF on the databus when the SRAM is in an unknown (low Z) state. // Because of this, if you drive a value of FF on the databus while the SRAM // is in a low Z state, you will not see a conflit (X's) on the bus, when in // fact there may be contention. // ///////////////////////////////////////////////////////////////////////////////// `timescale 1 ns / 1 ns module SRAM (reset, data, address, WE_BAR, CE_BAR, OE_BAR) ; inout [15:0] data ; //bi-directional memory databus input [18:0] address ; //address supplied to memory input WE_BAR ; //write enable (active low) input CE_BAR ; //chip enable (active low) input OE_BAR ; //output enable (active low) input reset; //reset signal (for dumping memory contents) // file I/O variables integer dumpfile; integer i; reg [15:0] memory [0:524287]; // storage space reg unknown; // indicates output is in unknown state reg read; // indicates a read is occuring // output assignment based on conditions set by signal transitions assign data = (read == 1'b1) ? memory[address] : (unknown == 1'b1) ? 16'hFFFF: 16'bz; //initialize some memory values for testing purposes initial begin read <= 1'b0; unknown <= 1'b0; $readmemh ("mem.txt", memory); end // force read to wait after cycling address always @(address) begin if ((WE_BAR) && (~OE_BAR) && (~CE_BAR)) begin unknown <= 1'b1; read <= 1'b0; read <= #1 1'b0; read <= #2 1'b0; read <= #3 1'b0; read <= #4 1'b0; read <= #5 1'b0; read <= #6 1'b0; read <= #7 1'b0; read <= #8 1'b0; read <= #9 1'b0; read <= #10 1'b0; read <= #11 1'b0; read <= #12 1'b0; read <= #13 1'b0; read <= #14 1'b0; //allow read unknown <= #15 1'b0; read <= #15 ((WE_BAR) && (~OE_BAR) && (~CE_BAR))? 1'b1: 1'b0; end end // store data if this ends a write cycle always @(posedge WE_BAR) begin read <= #3 1'b0; unknown <= #3 1'b0; if (~CE_BAR) memory[address] <= data; end // store data if this ends a write cycle always @(posedge CE_BAR) begin read <= #4 1'b0; unknown <= #4 1'b0; if (~WE_BAR) memory[address] <= data; end // force output into high Z after some delay always @(posedge OE_BAR) begin read <= #4 1'b0; unknown <= #4 1'b0; end // if this begins a read, allow it to proceed after a delay always @(negedge CE_BAR) begin unknown <= 1'b1; if ((WE_BAR) && (~OE_BAR)) read <= #15 1'b1; end // force output into high Z after some delay when WE goes low always @(negedge WE_BAR) begin read <= #7 1'b0; unknown <= #7 1'b0; end // allow read after some delay when OE goes low always @(negedge OE_BAR) begin unknown <= 1'b1; if ((WE_BAR) && (~CE_BAR)) read <= #7 1'b1; end ////////////////////////////////////////////////////////////////////////////// // make sure no setup or cycle time constraints are violated on input signals // // violating these setup and cycle times will not damage the SRAM, but your // data integrity is not insured ////////////////////////////////////////////////////////////////////////////// specify $width (negedge WE_BAR, 15); $width (negedge CE_BAR, 15); $width (negedge OE_BAR, 15); $setup (data, posedge WE_BAR &&& ~CE_BAR, 7); $setup (address, posedge WE_BAR &&& ~CE_BAR, 10); $setup (data, posedge CE_BAR &&& ~WE_BAR, 7); $setup (address, posedge CE_BAR &&& ~WE_BAR, 10); $width (posedge address[0] &&& ~CE_BAR, 15); $width (negedge address[0] &&& ~CE_BAR, 15); $width (posedge address[1] &&& ~CE_BAR, 15); $width (negedge address[1] &&& ~CE_BAR, 15); $width (posedge address[2] &&& ~CE_BAR, 15); $width (negedge address[2] &&& ~CE_BAR, 15); $width (posedge address[3] &&& ~CE_BAR, 15); $width (negedge address[3] &&& ~CE_BAR, 15); $width (posedge address[4] &&& ~CE_BAR, 15); $width (negedge address[4] &&& ~CE_BAR, 15); $width (posedge address[5] &&& ~CE_BAR, 15); $width (negedge address[5] &&& ~CE_BAR, 15); $width (posedge address[6] &&& ~CE_BAR, 15); $width (negedge address[6] &&& ~CE_BAR, 15); $width (posedge address[7] &&& ~CE_BAR, 15); $width (negedge address[7] &&& ~CE_BAR, 15); $width (posedge address[8] &&& ~CE_BAR, 15); $width (negedge address[8] &&& ~CE_BAR, 15); $width (posedge address[9] &&& ~CE_BAR, 15); $width (negedge address[9] &&& ~CE_BAR, 15); $width (posedge address[10] &&& ~CE_BAR, 15); $width (negedge address[10] &&& ~CE_BAR, 15); $width (posedge address[11] &&& ~CE_BAR, 15); $width (negedge address[11] &&& ~CE_BAR, 15); $width (posedge address[12] &&& ~CE_BAR, 15); $width (negedge address[12] &&& ~CE_BAR, 15); $width (posedge address[13] &&& ~CE_BAR, 15); $width (negedge address[13] &&& ~CE_BAR, 15); $width (posedge address[14] &&& ~CE_BAR, 15); $width (negedge address[14] &&& ~CE_BAR, 15); $width (posedge address[15] &&& ~CE_BAR, 15); $width (negedge address[15] &&& ~CE_BAR, 15); $width (posedge address[16] &&& ~CE_BAR, 15); $width (negedge address[16] &&& ~CE_BAR, 15); $width (posedge address[17] &&& ~CE_BAR, 15); $width (negedge address[17] &&& ~CE_BAR, 15); $width (posedge address[18] &&& ~CE_BAR, 15); $width (negedge address[18] &&& ~CE_BAR, 15); endspecify ///////////////////////////////////////////////////////////////// // write selected memory contents to a file ///////////////////////////////////////////////////////////////// always @ (posedge reset) begin /////// change range on i to select memory addresses to output /////// dumpfile = $fopen ("mem.out"); for (i = 'h20000; i < 'h21000; i = i + 1) begin $fwrite (dumpfile, "@"); $fwriteh (dumpfile, i); $fwrite (dumpfile, " "); $fdisplayh (dumpfile, memory[i]); end $fclose (dumpfile); end endmodule