Back to examples

Memory Deep Dive

Implementing a 256x8 RAM module with synchronous write and asynchronous read. Understanding memory design patterns in hardware.

Memory RAM Sync Write Async Read

Ruby Implementation

The Memory DSL provides a declarative way to define RAM modules. Include RHDL::DSL::Memory to access memory, sync_write, and async_read.

ram.rb
class RAM256x8 < RHDL::Sim::Component
  include RHDL::DSL::Memory

  input  :clk, :we        # clock and write enable
  input  :addr, width: 8  # 8-bit address = 256 locations
  input  :din,  width: 8  # 8-bit data input
  output :dout, width: 8  # 8-bit data output

  # Declare memory array: 256 entries x 8 bits
  memory :mem, depth: 256, width: 8

  # Write on rising clock edge when we=1
  sync_write  :mem,
    clock: :clk, enable: :we,
    addr:  :addr, data: :din

  # Read is combinational (no clock needed)
  async_read  :dout,
    from: :mem, addr: :addr
end

Generated Verilog

ram.v Generated Verilog
module RAM256x8 (
  input        clk,
  input        we,
  input  [7:0] addr,
  input  [7:0] din,
  output [7:0] dout
);

reg [7:0] mem [0:255];

assign dout = mem[addr];

always @(posedge clk) begin
  if (we)
    mem[addr] <= din;
end

endmodule

Read/Write Timing

OperationTimingBehavior
Async ReadCombinationalOutput reflects mem[addr] immediately when addr changes
Sync WritePosedge clkWhen we=1, din is written to mem[addr] on rising edge
Read-During-WriteSame cycleRead returns the old value (write-after-read semantics)

Integration Patterns

Connect memory to a CPU by wiring address, data, and control signals with address decoding.

memory_system.rb
class MemorySystem < RHDL::Sim::Component
  include RHDL::DSL::Memory

  input  :clk, :rst
  input  :cpu_addr, width: 16
  input  :cpu_data, width: 8
  input  :cpu_rw
  output :data_out, width: 8

  component :main_ram, RAM256x8
  component :rom, ROM,
    depth: 16384, width: 8

  behavior do
    is_rom = cpu_addr[15] & cpu_addr[14]
    data_out <= mux(is_rom,
      rom.dout, main_ram.dout)
  end
end