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

posted on 2024-06-14 08:08  糊涂二蛋  阅读(46)  评论(0编辑  收藏  举报