Storing data in your FPGA - the foundation of real systems
FPGAs have THREE types of memory resources:
| Type | Source | Size | Use Case |
|---|---|---|---|
| Flip-Flops | Logic cells | Small (1 bit each) | Registers, state machines |
| Distributed RAM | LUTs as RAM | Small arrays | FIFOs, small buffers |
| Block RAM (BRAM) | Dedicated blocks | Large (KB) | Frame buffers, data storage |
For small amounts of data, use a register array:
// 16-entry x 8-bit register file // Fast but uses lots of logic resources module register_file ( input clk, input [3:0] write_addr, input [3:0] read_addr, input [7:0] write_data, input write_enable, output [7:0] read_data ); // Array of 16 registers, each 8 bits wide reg [7:0] registers [0:15]; integer i; // Write operation always @(posedge clk) begin if (write_enable) registers[write_addr] <= write_data; end // Read operation (combinational) assign read_data = registers[read_addr]; endmodule
For larger memory, use Block RAM. It's free - dedicated hardware that doesn't consume logic resources.
// 256-byte single-port RAM // One port for both read and write module single_port_ram ( input clk, input [7:0] addr, // 8-bit address = 256 locations input [7:0] write_data, input write_enable, output reg [7:0] read_data ); // Memory array - synthesis tool will infer BRAM reg [7:0] memory [0:255]; always @(posedge clk) begin if (write_enable) memory[addr] <= write_data; read_data <= memory[addr]; // Registered read end endmodule
Read and write simultaneously on different ports:
// True dual-port RAM // Can read from one address while writing to another module dual_port_ram ( input clk, // Port A (write port) input [9:0] addr_a, input [7:0] data_a, input we_a, // Port B (read port) input [9:0] addr_b, output reg [7:0] data_b ); reg [7:0] memory [0:1023]; // 1KB RAM // Port A: Write always @(posedge clk) begin if (we_a) memory[addr_a] <= data_a; end // Port B: Read always @(posedge clk) begin data_b <= memory[addr_b]; end endmodule
You can pre-load memory with data from a file:
// RAM with initialization from file module rom_with_init ( input clk, input [7:0] addr, output reg [7:0] data ); reg [7:0] memory [0:255]; // Initialize from file initial begin $readmemh("init_data.hex", memory); end always @(posedge clk) begin data <= memory[addr]; end endmodule
FF
A5
00
42
FIFOs are essential for data streaming between clock domains:
// Simple synchronous FIFO // 16-entry deep, 8-bit wide module fifo_sync ( input clk, input rst, // Write interface input [7:0] write_data, input write_en, output full, // Read interface output [7:0] read_data, input read_en, output empty ); reg [7:0] memory [0:15]; reg [4:0] write_ptr, read_ptr; reg [4:0] count; assign full = (count == 16); assign empty = (count == 0); assign read_data = memory[read_ptr[3:0]]; // Write operation always @(posedge clk) begin if (rst) begin write_ptr <= 0; end else if (write_en && !full) begin memory[write_ptr[3:0]] <= write_data; write_ptr <= write_ptr + 1; end end // Read operation always @(posedge clk) begin if (rst) begin read_ptr <= 0; end else if (read_en && !empty) begin read_ptr <= read_ptr + 1; end end // Count tracking always @(posedge clk) begin if (rst) count <= 0; else begin case({write_en && !full, read_en && !empty}) 2'b10: count <= count + 1; // Write only 2'b01: count <= count - 1; // Read only default: count <= count; // Both or neither endcase end end endmodule
For production, use the vendor IP Core Generator:
| Application | Memory Size | Type |
|---|---|---|
| State machine variables | < 32 bits | Flip-flops |
| Small lookup table | < 256 bytes | Distributed RAM |
| Video line buffer (640px RGB) | 1920 bytes | Block RAM |
| Audio buffer (1s @ 44.1kHz) | 88 KB | Block RAM |
| Frame buffer (640x480 RGB) | 900 KB | External SDRAM |