verilog 中實現 sram 程式碼

糊涂二蛋發表於2024-06-14

目錄
  • verilog/systemverilog中sram的實現
    • sram的基本知識
    • verilog/systemverilog中sram的實現
      • 單口SSRAM(同步SRAM)
      • 單時鐘簡雙口SSRAM(同步SRAM)
      • 單時鐘真雙口SSRAM(同步SRAM)
      • 雙時鐘簡雙口SSRAM(同步SRAM)
      • 雙時鐘真雙口SSRAM(同步SRAM)
      • 多bank SRAM

verilog/systemverilog中sram的實現

sram的基本知識

SRAM 即靜態隨機存取儲存器,它是隨機存取儲存器的一種。所謂的“靜態”,是指這種儲存器只要保持通電,裡面儲存的資料就可以一直保持。
在IC設計中,常用SRAM在各個block中實現儲存單元,用這些儲存單元來快取資料,交換資料,從而實現block的功能。

verilog/systemverilog中sram的實現

在verilog中,我們可以用變數陣列來描述sram,一般每一bit都將綜合成一個觸發器。比如下面的程式碼,將定義一個寬度為8,深度為256的sram。
logic [7:0] sram[256]
根據讀寫控制的不同,我們可以把sram的實現分類為,單口sram,單時鐘簡雙口sram,單時鐘真雙口sram,雙時鐘簡雙口sram,雙時鐘真雙口sram,下面分別來學習這幾種sram的verilog實現。

單口SSRAM(同步SRAM)

下面是同步先讀模式的單口SRAM程式碼,如果we=1,會並行讀寫ram[addr]中的值,所以這時qout中儲存的是寫之前的值。
檔名稱 code4_18.v

`timescale 1ns/1ps
module TestMem;
    logic clk = 1'b0;

    initial begin
        $display("start a clock pulse");
        $dumpfile("testmem.vcd"); 
        $dumpvars(0, TestMem); 
        #300 $finish;
    end

    always begin
        #5 clk = ~clk;
    end

    logic [7:0] a=0,d=0,q;
    logic  we=0;
    initial begin
        #10 we <=1; a<=8'h01; d<=8'h10;
        #10 a<=8'h03; d<=8'h30;
        #10 a<=8'h06; d<=8'h60;  
        #10 a<=8'h0a; d<=8'ha0;   
        #10 a<=8'h0f; d<=8'hf0;      
        #10 we<=0;a<=8'h00; d<=8'h00;

        forever #10 begin
            a++;
        end                
    end

    SpRamRf #(.DW(8), .DEPTH(256)) the_spramrf(.clk(clk),.addr(a),.we(we),.din(d),.qout(q));

    
endmodule

//simple port ram read first
module SpRamRf #(parameter  DW=8, DEPTH=256) (
    input wire clk,
    input wire [$clog2(DEPTH)-1:0] addr,
    input wire we,
    input wire [DW-1:0] din,
    output logic  [DW-1:0] qout
);
    logic [DW-1:0] ram[DEPTH];

    always_ff @(posedge clk) begin
        if(we) ram[addr] <= din;
        qout <= ram[addr];

    end

endmodule

在vscode中,使用下面命令編譯,執行程式碼,然後用gtkwave 開啟波形檔案:

iverilog -o myrun -g 2012 -s TestMem code4_18.v
vvp myrun
gtkwave testmem.vcd

image

  • 在第1個時鐘上升沿,we=0,a=0,會讀取ram[0],由於ram初始值為x,所以此時q值為x。
  • 在第2個時鐘上升沿,we=1,a=1,會並行讀寫ram[1],ram[1]=0x10,由於讀優先,所以此時q值讀取的仍是之前ram[1]中之前的值x。
  • 在第3個時鐘上升沿,we=1,a=3,會並行讀寫ram[3],ram[3]=0x30,由於讀優先,所以此時q值讀取的仍是之前ram[3]中之前的值x。
  • 在第4個時鐘上升沿,we=1,a=6,會並行讀寫ram[6],ram[6]=0x60,由於讀優先,所以此時q值讀取的仍是之前ram[6]中之前的值x。
  • 在第5個時鐘上升沿,we=1,a=10,會並行讀寫ram[10],ram[10]=0xa0,由於讀優先,所以此時q值讀取的仍是之前ram[10]中之前的值x。
  • 在第6個時鐘上升沿,we=1,a=15,會並行讀寫ram[15],ram[0]=0xf0,由於讀優先,所以此時q值讀取的仍是之前ram[15]中之前的值x。
  • 在第7個時鐘上升沿,we=0,a=0,會讀取ram[0],ram[0]=x。
  • 從第8個時鐘上升沿開始,we=0, 地址a累積增加,依次讀取ram[1],ram[2],...

我們也可以在同步單口sram讀寫控制模組中加上覆位訊號,來初始化ram的值為0。加上覆位訊號的程式碼如下:
檔名稱 code4_19.v

`timescale 1ns/1ps
module TestMem;
    logic clk = 1'b0;
    logic rst = 1'b0;

    initial begin
        $display("start a clock pulse");
        $dumpfile("testmem.vcd"); 
        $dumpvars(0, TestMem); 
        #300 $finish;
    end

    always begin
        #5 clk = ~clk;
    end

    logic [7:0] a=0,d=0,q;
    logic  we=0;
    initial begin
        #10 rst=1'b1;
        #30 rst=1'b0;
        #10 we <=1; a<=8'h01; d<=8'h10;
        #10 a<=8'h03; d<=8'h30;
        #10 a<=8'h06; d<=8'h60;  
        #10 a<=8'h0a; d<=8'ha0;   
        #10 a<=8'h0f; d<=8'hf0;      
        #10 we<=0;a<=8'h00; d<=8'h00;

        forever #10 begin
            a++;
        end                
    end

    SpRamRf #(.DW(8), .DEPTH(256)) the_spramrf(.clk(clk),.rst(rst),.addr(a),.we(we),.din(d),.qout(q));

    
endmodule

//simple port ram read first
module SpRamRf #(parameter  DW=8, DEPTH=256) (
    input wire clk,
    input wire rst,
    input wire [$clog2(DEPTH)-1:0] addr,
    input wire we,
    input wire [DW-1:0] din,
    output logic  [DW-1:0] qout
);
    logic [DW-1:0] ram[DEPTH];

    always_ff @(posedge clk) begin
        //同步復位
        if(rst) begin
            for(integer i = 0; i< DEPTH; i=i+1)
                ram[i] <= '0;
        end
        else begin
            if(we) ram[addr] <= din;
            qout <= ram[addr];
        end
    end

endmodule

在vscode中,使用下面命令編譯,執行程式碼,然後用gtkwave 開啟波形檔案:

iverilog -o myrun -g 2012 -s TestMem code4_19.v
vvp myrun
gtkwave testmem.vcd

image

  • 在第1個時鐘上升沿,rst=0,we=0,a=0,會讀取ram[0],由於ram初始值為x,所以此時q值為x。
  • 在第2個時鐘上升沿,rst=1, we=0,a=0,此時會初始化ram中的值為0,q保持之前的值x。
  • 在第3個時鐘上升沿,rst=1, we=0,a=0,此時會初始化ram中的值為0,q保持之前的值x。
  • 在第4個時鐘上升沿,rst=1, we=0,a=0,此時會初始化ram中的值為0,q保持之前的值x。
  • 在第5個時鐘上升沿,rst=0, we=0,a=0,會讀取ram[0],由於rst訊號已經初始化ram,所以此時q值讀取的是0。
  • 在第6個時鐘上升沿,rst=1,we=1,a=15,會並行讀寫ram[1],ram[1]=0x10,由於讀優先,所以此時q值讀取的仍是之前ram[1]中之前的值0。
  • 在第7個時鐘上升沿,rst=1,we=1,a=3,會並行讀寫ram[3],ram[3]=0x30,由於讀優先,所以此時q值讀取的仍是之前ram[3]中之前的值0。
  • 在第8個時鐘上升沿,rst=1,we=1,a=6,會並行讀寫ram[6],ram[6]=0x60,由於讀優先,所以此時q值讀取的仍是之前ram[6]中之前的值0。
  • 在第9個時鐘上升沿,rst=1,we=1,a=10,會並行讀寫ram[10],ram[10]=0xa0,由於讀優先,所以此時q值讀取的仍是之前ram[10]中之前的值0。
  • 在第10個時鐘上升沿,rst=1,we=1,a=15,會並行讀寫ram[15],ram[15]=0xf0,由於讀優先,所以此時q值讀取的仍是之前ram[15]中之前的值0。
  • 在第11個時鐘上升沿,rst=1,we=0,a=0,會讀取ram[0],ram[0]=0。
  • 從第12個時鐘上升沿開始,we=0, 地址a累積增加,依次讀取ram[1],ram[2],...

前面的同步單口sram程式碼中,是讀優先的,我們可以對程式碼做一點改動,成為寫優先。對於寫優先,如果we=1,則 ram[addr] <= din; qout <= din;
如果we=0,則 qout <= ram[addr];
檔名稱code4_20.v

`timescale 1ns/1ps
module TestMem;
    logic clk = 1'b0;

    initial begin
        $display("start a clock pulse");
        $dumpfile("testmem.vcd"); 
        $dumpvars(0, TestMem); 
        #300 $finish;
    end

    always begin
        #5 clk = ~clk;
    end

    logic [7:0] a=0,d=0,q;
    logic  we=0;
    initial begin
        #10 we <=1; a<=8'h01; d<=8'h10;
        #10 a<=8'h03; d<=8'h30;
        #10 a<=8'h06; d<=8'h60;  
        #10 a<=8'h0a; d<=8'ha0;   
        #10 a<=8'h0f; d<=8'hf0;      
        #10 we<=0;a<=8'h00; d<=8'h00;

        forever #10 begin
            a++;
        end                
    end

    SpRamWf #(.DW(8), .DEPTH(256)) the_spramwf(.clk(clk),.addr(a),.we(we),.din(d),.qout(q));

    
endmodule

//simple port ram write first
module SpRamWf #(parameter  DW=8, DEPTH=256) (
    input wire clk,
    input wire [$clog2(DEPTH)-1:0] addr,
    input wire we,
    input wire [DW-1:0] din,
    output logic  [DW-1:0] qout
);
    logic [DW-1:0] ram[DEPTH];

    always_ff @(posedge clk) begin
        if(we) begin
            ram[addr] <= din;
            qout <= din;
        end
        else 
            qout <= ram[addr];
    end

endmodule

在vscode中,使用下面命令編譯,執行程式碼,然後用gtkwave 開啟波形檔案:

iverilog -o myrun -g 2012 -s TestMem code4_20.v
vvp myrun
gtkwave testmem.vcd

image

從波形上可以看出,在時鐘上升沿,如果we=1,q的輸出即為寫入的值d。

單時鐘簡雙口SSRAM(同步SRAM)

單時鐘同步簡雙口SRAM有兩個輸入地址addr_a, addr_b,但一個時鐘週期上升沿只有addr_a可以寫SRAM,而addr_b用來讀SRAM。訊號we_a用來控制addr_a寫SRAM,如果we_a=0,則地址addr_a不會寫SRAM。
如果讀寫相同地址,且we_a=0,則是讀優先模式,讀取的是ram中之前儲存的值。
檔名稱code4_21.v

`timescale 1ns/1ps
module TestMem;
    logic clk = 1'b0;

    initial begin
        $display("start a clock pulse");
        $dumpfile("testmem.vcd"); 
        $dumpvars(0, TestMem); 
         #300 $finish;
    end

    always begin
        #5 clk = ~clk;
    end

    logic [7:0] a1=0,a2=0,d1=0,q1,d2=0,q2;
    logic  we_a=0,we_b=0;
    initial begin
        #10 we_a =1; a1=8'h01; d1=8'h10; a2=8'h00;
        #10 a1=8'h03; d1=8'h30; a2=8'h03;
        #10 a1=8'h06; d1=8'h60; a2=8'h01;  
        #10 a1=8'h0a; d1=8'ha0; a2=8'h06;   
        #10 a1=8'h0f; d1=8'hf0; a2=8'h0a;      
        #10 we_a=0; a2 = 8'h00;

        forever #10 begin
            a1++; a2++;
        end                
    end

    SdpRamRf #(.DW(8), .DEPTH(256)) the_sdpramrf(.clk(clk),.addr_a(a1),.we_a(we_a),.din_a(d1),.addr_b(a2),.qout(q1));

    
endmodule

//simple double port ram read first
//單時鐘簡雙口, 一個口讀,一個口寫
module SdpRamRf #(parameter  DW=8, DEPTH=256) (
    input wire clk,
    input wire [$clog2(DEPTH)-1:0] addr_a,
    input wire we_a,
    input wire [DW-1:0] din_a,
    input wire [$clog2(DEPTH)-1:0] addr_b,
    output logic  [DW-1:0] qout
);
    logic [DW-1:0] ram[DEPTH];

    always_ff @(posedge clk) begin
        if(we_a) ram[addr_a] <= din_a;
    end
    always_ff @(posedge clk) begin
        qout <= ram[addr_b];
    end
endmodule

在vscode中,使用下面命令編譯,執行程式碼,然後用gtkwave 開啟波形檔案:

iverilog -o myrun -g 2012 -s TestMem code4_21.v
vvp myrun
gtkwave testmem.vcd

image

  • 第1個時鐘上升沿,we_a=0, a1=0, a2=0, d1=0, 讀取ram[0],q1=ram[0]=x
  • 第2個時鐘上升沿,we_a=1, a1=1, a2=0, d1=0x10,ram[1]=0x10,讀取ram[0],q1=ram[0]=x
  • 第3個時鐘上升沿,we_a=1, a1=3, a2=3, d1=0x30,ram[3]=0x30,讀取ram[3],q1=ram[3]=x,因為是讀優先模式,所以q1中讀取的是ram[3]中之前的值x
  • 第4個時鐘上升沿,we_a=1, a1=6, a2=1, d1=0x60,ram[6]=0x60,讀取ram[1],q1=ram[1]=0x10
  • 第5個時鐘上升沿,we_a=1, a1=10, a2=6, d1=0xa0,ram[10]=0xa0,讀取ram[6],q1=ram[6]=0x60
  • 第6個時鐘上升沿,we_a=1, a1=15, a2=10, d1=0xf0,ram[15]=0xf0,讀取ram[10],q1=ram[10]=0xa0
  • 第7個時鐘上升沿,we_a=0, a1=15, a2=0, d1=0xf0, 沒有寫操作,讀取ram[0],q1=ram[0]=x
  • 第8個時鐘上升沿,從這兒開始,a2 累加,讀取q1=ram[a2]

單時鐘真雙口SSRAM(同步SRAM)

單時鐘真雙口SSRAM verilog實現中,是口內先寫,口間先讀。如果兩口同時寫同一個地址不同資料,會產生未知結果。
檔名稱code4_22.v

`timescale 1ns/1ps
module TestMem;
    logic clk = 1'b0;

    initial begin
        $display("start a clock pulse");
        $dumpfile("testmem.vcd"); 
        $dumpvars(0, TestMem); 
         #300 $finish;
    end

    always begin
        #5 clk = ~clk;
    end

    logic [7:0] a1=0,a2=0,d1=0,q1,d2=0,q2;
    logic  we_a=0,we_b=0;
    initial begin
        #10 we_a =1; a1=8'h01; d1=8'h10; we_b=1;a2=8'h00;d2=8'hff;
        #10 we_a =0; a1=8'h00;  a2=8'h02; d2=8'hfe;
        #10 we_a =0; a1=8'h02;  a2=8'h03; d2=8'hfc;  
        #10 we_a =1; a1=8'h0a; d1=8'ha0; we_a=0; a2=8'h01;  
        #10 we_a =0; a1=8'h00;  we_a=0; a2=8'h01;  
        forever #10 begin
            a1++; a2++;
        end                
    end

在vscode中,使用下面命令編譯,執行程式碼,然後用gtkwave 開啟波形檔案:

iverilog -o myrun -g 2012 -s TestMem code4_22.v
vvp myrun
gtkwave testmem.vcd

image

  • 第1個時鐘上升沿,we_a=0, a1=0, d1=0,a口讀取ram[0],q1=ram[0]=xwe_b=0, a2=0, d2=0,b口讀取ram[0],q2=ram[0]=x
  • 第2個時鐘上升沿,we_a=1, a1=1, d1=0x10,a口寫ram[1]=0x10,q1=ram[1]=0x10we_b=1, a2=0, d2=0xff,b口寫ram[0]=0xff,q2=ram[0]=0xff
  • 第3個時鐘上升沿,we_a=0, a1=0, d1=0x10,a口讀ram[0],q1=ram[0]=0xffwe_b=1, a2=2, d2=0xfe,b口寫ram[2]=0xfe,q2=ram[2]=0xfe
  • 第4個時鐘上升沿,we_a=0, a1=2, d1=0x10,a口讀ram[2],q1=ram[2]=0xfewe_b=1, a2=3, d2=0xfc,b口寫ram[3]=0xfc,q2=ram[3]=0xfc
  • 第5個時鐘上升沿,we_a=0, a1=10, d1=0xa0,a口讀ram[10],q1=ram[10]=xwe_b=1, a2=1, d2=0xfc,b口寫ram[1]=0xfc,q2=ram[1]=0xfc
  • 第6個時鐘上升沿,we_a=0, a1=0, d1=0xa0,a口讀ram[0],q1=ram[0]=0xffwe_b=1, a2=1, d2=0xfc,b口寫ram[1]=0xfc,q2=ram[1]=0xfc
  • 第7個時鐘上升沿,從第7個時鐘上升沿開始,we_a=0, a1累加, d1=0xa0,a口讀ram[a1],q1=ram[a1]=0xfcwe_b=1, a2累加, d2=0xfc,b口寫ram[a2]=0xfc,q2=ram[a2]=0xfc

雙時鐘簡雙口SSRAM(同步SRAM)

雙時鐘簡雙口SSRAM和單時鐘相似,都是a口寫,b口讀,唯一不同的是雙時鐘每個口都有自己的時鐘訊號驅動,所以需要兩個時鐘訊號clk_aclk_bclk_a時鐘週期是10nsclk_b時鐘週期是16ns
檔名稱code4_23.v

`timescale 1ns/1ps
module TestMem;
    logic clk_a = 1'b0;
    logic clk_b = 1'b0;

    initial begin
        $display("start a clock pulse");
        $dumpfile("testmem.vcd"); 
        $dumpvars(0, TestMem); 
         #300 $finish;
    end

    always begin
        #5 clk_a = ~clk_a;
    end
    always begin
        #8 clk_b = ~clk_b;
    end

    logic [7:0] a1=0,a2=0,d1=0,q1,d2=0,q2;
    logic  we_a=0,we_b=0;
    initial begin
        #10 we_a =1; a1=8'h01; d1=8'h10; a2=8'h00;
        #10 a1=8'h03; d1=8'h30; a2=8'h01;
        #10 a1=8'h06; d1=8'h60; a2=8'h03;  
        #10 a1=8'h0a; d1=8'ha0; a2=8'h06;   
        #10 a1=8'h0f; d1=8'hf0; a2=8'h0a;      
        #10 we_a=0; a2 = 8'h00;

        forever #10 begin
            a1++; a2++;
        end                
    end

    SdcRam #(.DW(8), .DEPTH(256)) the_sdcram(.clk_a(clk_a),.addr_a(a1),.we_a(we_a),.din_a(d1),.clk_b(clk_b),.addr_b(a2),.qout(q1));

    
endmodule


//雙時鐘,簡雙口,口一寫,口二讀
module SdcRam #(parameter  DW=8, DEPTH=256) (
    input wire clk_a,
    input wire [$clog2(DEPTH)-1:0] addr_a,
    input wire we_a,
    input wire [DW-1:0] din_a,
    input wire clk_b,
    input wire [$clog2(DEPTH)-1:0] addr_b,
    output logic  [DW-1:0] qout
);
    logic [DW-1:0] ram[DEPTH];

    always_ff @(posedge clk_a) begin
        if(we_a) ram[addr_a] <= din_a;
    end
    always_ff @(posedge clk_b) begin
        qout <= ram[addr_b];
    end
endmodule

在vscode中,使用下面命令編譯,執行程式碼,然後用gtkwave 開啟波形檔案:

iverilog -o myrun -g 2012 -s TestMem code4_23.v
vvp myrun
gtkwave testmem.vcd

image

  • clk_a第1個時鐘上升沿,we_a=0, a1=0, d1=0,a口沒有寫操作
  • clk_b第1個時鐘上升沿,a2=0,b口讀取ram[0],q1=ram[0]=x
  • clk_a第2個時鐘上升沿,we_a=1, a1=1, d1=0x10,a口寫ram[1],ram[1]=0x10
  • clk_b第2個時鐘上升沿,a2=1,b口讀取ram[1],q1=ram[1]=0x10
  • clk_a第3個時鐘上升沿,we_a=1, a1=3, d1=0x30,a口寫ram[3],ram[3]=0x30
  • clk_a第3個鐘上升沿,we_a=1, a1=6, d1=0x60,a口寫ram[6],ram[6]=0x60
  • clk_b第3個時鐘上升沿,a2=6,b口讀取ram[6],q1=ram[6]=0x60
  • clk_a第5個時鐘上升沿,we_a=1, a1=10, d1=0xa0,a口寫ram[10],ram[10]=0xa0
  • clk_a第6個鐘上升沿,we_a=1, a1=15, d1=0xf0,a口寫ram[15],ram[15]=0xf0
  • clk_b第4個時鐘上升沿,a2=10,b口讀取ram[10],q1=ram[10]=0xa0
  • clk_a第7個時鐘上升沿,we_a=0, a1=15, d1=0xf0,a口沒有寫操作,之後由於一直we_a=0,所以a口一直沒有寫操作。
  • clk_b第5個時鐘上升沿,a2=1,b口讀取ram[1],q1=ram[1]=0x10,之後a2累加,在每個clk_b的每個時鐘上升沿,一次讀取ram[a2]

雙時鐘真雙口SSRAM(同步SRAM)

雙時鐘真雙口和單時鐘真雙口相似,都是口內寫優先,口間讀優先,唯一不同a口和b口都有自己的時鐘訊號驅動,所以需要兩個時鐘訊號clk_aclk_bclk_a時鐘週期是10nsclk_b時鐘週期是16ns
檔名稱code4_24.v

`timescale 1ns/1ps
module TestMem;
    logic clk_a = 1'b0;
    logic clk_b = 1'b0;

    initial begin
        $display("start a clock pulse");
        $dumpfile("testmem.vcd"); 
        $dumpvars(0, TestMem); 
         #300 $finish;
    end

    always begin
        #5 clk_a = ~clk_a;
    end

    always begin
        #8 clk_b = ~clk_b;
    end    

    logic [7:0] a1=0,a2=0,d1=0,q1,d2=0,q2;
    logic  we_a=0,we_b=0;
    initial begin
        #10 we_a =1; a1=8'h01; d1=8'h10; we_b=1;a2=8'h00;d2=8'hff;
        #10 we_a =0; a1=8'h00;  a2=8'h02; d2=8'hfe;
        #10 we_a =0; a1=8'h02;  a2=8'h03; d2=8'hfc;  
        #10 we_a =1; a1=8'h0a; d1=8'ha0; we_a=0; a2=8'h01;  
        #10 we_a =0; a1=8'h00;  we_a=0; a2=8'h01;  
        forever #10 begin
            a1++; a2++;
        end                
    end

    DcRam #(.DW(8), .DEPTH(256)) the_dcram(.clk_a(clk_a),.addr_a(a1),.we_a(we_a),.qout_a(q1),
    .din_a(d1),.clk_b(clk_b),.addr_b(a2),.we_b(we_b),.qout_b(q2),.din_b(d2));

    
endmodule

//double port ram 
//雙時鐘真雙口, 每個埠都可以獨立讀寫
module DcRam #(parameter  DW=8, DEPTH=256) (
    input wire clk_a,
    input wire [$clog2(DEPTH)-1:0] addr_a,
    input wire we_a,
    input wire [DW-1:0] din_a,
    output logic  [DW-1:0] qout_a,
    input wire clk_b,
    input wire [$clog2(DEPTH)-1:0] addr_b,
    input wire we_b,
    input wire [DW-1:0] din_b,
    output logic  [DW-1:0] qout_b
);
    logic [DW-1:0] ram[DEPTH];

    always_ff @(posedge clk_a) begin
        if(we_a) begin
            ram[addr_a] <= din_a;
            qout_a <= din_a;
        end
        else qout_a = ram[addr_a];
        
    end
    always_ff @(posedge clk_b) begin
        if(we_b) begin
            ram[addr_b] <= din_b;
            qout_b <= din_b;
        end
        else qout_b = ram[addr_b];
    end
endmodule

在vscode中,使用下面命令編譯,執行程式碼,然後用gtkwave 開啟波形檔案:

iverilog -o myrun -g 2012 -s TestMem code4_24.v
vvp myrun
gtkwave testmem.vcd

image

  • clk_a第1個時鐘上升沿,we_a=0, a1=0, d1=0,a口讀取ram[0],q1=ram[0]=x
  • clk_b第1個時鐘上升沿,we_b=0, a2=0, d2=0,b口讀取ram[0],q2=ram[0]=x
  • clk_a第2個時鐘上升沿,we_a=1, a1=1, d1=0x10,a口寫ram[1],ram[1]=0x10,q1=0x10
  • clk_b第2個時鐘上升沿,we_b=1, a2=2, d2=0xfe,b口寫ram[2],ram[2]=0xfe,q2=ram[2]=0xfe
  • clk_a第3個時鐘上升沿,we_a=0, a1=0, d1=0x10,a口讀ram[0],q1=x
  • clk_a第4個時鐘上升沿,we_a=0, a1=2, d1=0x10,a口讀ram[2],q1=ram[2]=0xfe
  • clk_b第3個時鐘上升沿,we_b=1, a2=1, d2=0xfc,b口寫ram[1],ram[1]=0xfc,q2=ram[1]=0xfc。之後,a2累加,在clk_b的每個時鐘上升沿,寫ram[a2]=0xfc,q2=0xfc
  • clk_a第5個時鐘上升沿,we_a=0, a1=10, d1=0x10,a口讀ram[10],q1=ram[10]=x
  • clk_a第6個時鐘上升沿,we_a=0, a1=0, d1=0x10,a口讀ram[0],q1=ram[0]=x。之後a1累加,a口讀取ram[a1],q1=ram[a1]

多bank SRAM

相關文章