RAM is Random Access Memory. Memory has size which is the number of memory locations, and width which is the number of bits used to represent the data at each memory location. Memory can also have ports. Each port allows a memory read or write to occur. So, dual port memory will allow two parallel reads or writes, and single port memory will allow only one read or write at any given time.


Below is a Verilog behavioural model for an 8-bit wide single port RAM of variable size. The size is determined by the ADDRESS_SIZE_BITS parameter. By default the memory size is 256 bytes (= 28). The only tricky detail in the code is the tri-state data lines. These are are dealt with by the continuous assignment (assign) which forces them either to be output (odata) or high impedance (8'bz).

module ram (data, addr, en, wr, clk);
   parameter ADDRESS_SIZE_BITS = 8;   
   inout [7:0]                   data;   // Data bus.
   input [ADDRESS_SIZE_BITS-1:0] addr;   // Address bus.
   input 			 clk;    // We perform action on +ve edge of this clock.
   input 			 en;     // Device enable
   input 			 wr;     // wr = 1 => write, wr = 0 => read.      
   wire [7:0] 			 odata;  // Used to drive the data bus.
   reg [7:0] 			 memory[0:(1 << (ADDRESS_SIZE_BITS - 1) - 1)];

   assign odata = memory[addr];		  
   assign data = (en && !wr) ? odata : 8'bz;
   always @(posedge clk) 
        if(en && wr)
	     memory[addr] <= data;		  

The following waveform shows an initial read from address 0A (hex), then a write to that address of value A5 (hex), and then a read from the same address which gives us the value we wrote. We then see the RAM disabled and a read from the original address, then a write to this address of value 5A (hex) and an attempt to read what we just wrote. Because the RAM is disabled, this does not work. Note that the initial read shows an undefined value in the RAM (XX) because the contents were not initialised.