- 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
- 在第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
- 在第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
從波形上可以看出,在時鐘上升沿,如果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
- 第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
- 第1個時鐘上升沿,
we_a=0, a1=0, d1=0,a
口讀取ram[0],q1=ram[0]=x
,we_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]=0x10
,we_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]=0xff
,we_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]=0xfe
,we_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]=x
,we_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]=0xff
,we_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]=0xfc
,we_b=1, a2累加, d2=0xfc,b
口寫ram[a2]=0xfc,q2=ram[a2]=0xfc
雙時鐘簡雙口SSRAM(同步SRAM)
雙時鐘簡雙口SSRAM和單時鐘相似,都是a口寫,b口讀,唯一不同的是雙時鐘每個口都有自己的時鐘訊號驅動,所以需要兩個時鐘訊號clk_a
和clk_b
。clk_a
時鐘週期是10ns
,clk_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
- 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_a
和clk_b
。clk_a
時鐘週期是10ns
,clk_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
- 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]
。