Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Industrial programming >> Verilog

Verilog Single-Port RAM Design: Umfassender Leitfaden

Design

Ein synchrones Single-Port-RAM mit gemeinsamer Datenleitung (inout) für Lesen und Schreiben. Die Steuerung erfolgt über Chip-Select (cs), Write-Enable (we) und Output-Enable (oe). Schreib- und Lesezugriff sind beide taktflankensynchron.

module single_port_sync_ram #(
    parameter int ADDR_WIDTH = 4,
    parameter int DATA_WIDTH = 32,
    parameter int DEPTH      = 16
) (
    input  logic                   clk,
    input  logic [ADDR_WIDTH-1:0]  addr,
    inout  tri   [DATA_WIDTH-1:0]  data,
    input  logic                   cs,
    input  logic                   we,
    input  logic                   oe
);

logic [DATA_WIDTH-1:0] tmp_data;
logic [DATA_WIDTH-1:0] mem [DEPTH];

// Schreiboperation
always_ff @(posedge clk) begin
    if (cs && we) begin
        mem[addr] <= data;
    end
end

// Leseoperation (registered output)
always_ff @(posedge clk) begin
    if (cs && !we) begin
        tmp_data <= mem[addr];
    end
end

// Tristate-Treiber für bidirektionale Datenleitung
assign data = (cs && oe && !we) ? tmp_data : 'z;

endmodule

Verilog Single-Port RAM Design: Umfassender Leitfaden

Testbench

Die Testbench schreibt zunächst alle 16 Adressen mit Zufallsdaten und liest sie anschließend sequenziell zurück.

module tb;
    parameter int ADDR_WIDTH = 4;
    parameter int DATA_WIDTH = 16;
    parameter int DEPTH      = 16;

    logic clk, cs, we, oe;
    logic [ADDR_WIDTH-1:0] addr;
    logic [DATA_WIDTH-1:0] data;
    logic [DATA_WIDTH-1:0] tb_data;

    single_port_sync_ram #(
        .ADDR_WIDTH(ADDR_WIDTH),
        .DATA_WIDTH(DATA_WIDTH),
        .DEPTH(DEPTH)
    ) u0 (
        .clk  (clk),
        .addr (addr),
        .data (data),
        .cs   (cs),
        .we   (we),
        .oe   (oe)
    );

    always #10 clk = ~clk;
    assign data = (!oe) ? tb_data : 'z;

    initial begin
        clk = 0; cs = 0; we = 0; oe = 0; addr = '0; tb_data = '0;
        repeat (2) @(posedge clk);

        // Schreibphase
        for (int i = 0; i < 2**ADDR_WIDTH; i++) begin
            @(posedge clk);
            addr    <= i;
            we      <= 1;
            cs      <= 1;
            oe      <= 0;
            tb_data <= $urandom;
        end

        // Lesephase
        for (int i = 0; i < 2**ADDR_WIDTH; i++) begin
            @(posedge clk);
            addr <= i;
            we   <= 0;
            cs   <= 1;
            oe   <= 1;
        end

        #20 $finish;
    end
endmodule

Verilog

  1. Verilog meistern: Komplettes Tutorial für digitales Schaltungsdesign
  2. Verilog Concatenation meistern: Praktischer Leitfaden
  3. Verilog Assignments verstehen: Typen, Syntax und Best Practices
  4. Verilog Blocking vs. Non-Blocking: Wichtige Unterschiede erklärt
  5. Verilog Functions meistern für effizientes RTL-Design
  6. Verilog Tasks verstehen: Functions vs. Tasks, Syntax und Verwendung
  7. Verilog Clock Generator: Design & Implementierungsleitfaden
  8. Verilog Math Functions meistern für effizientes Hardware-Design
  9. Verilog $timeformat meistern: Präzision und Anzeigesteuerung
  10. Verilog Timescales an jedem Scope verstehen und ausgeben