实验7、Macro应用-存储器
教程
我们介绍几种常见的块状存储器:
register file(简称RegFile,一般翻译为寄存器堆或寄存器文件)
random-access memory (RAM,一般翻译为随机访问存储器)
RAM with synchronous read (同步读出)
RAM with asynchronous read (异步读出)
1、RegFile
一个dual-port(双读写口)的RegFile:
module RegisterFile #(
parameter DataWidth = 32,
parameter NumRegs = 32,
parameter IndexWidth = $clog2(NumRegs)
) (
input clk,
input writeEn,
input [IndexWidth-1:0] writeAddr,
input [ DataWidth-1:0] writeData,
input [IndexWidth-1:0] readAddr1,
input [IndexWidth-1:0] readAddr2,
output [ DataWidth-1:0] readData1,
output [ DataWidth-1:0] readData2
);
logic [DataWidth-1:0] regs[NumRegs];
always_ff @(posedge clk) begin
if (writeEn) begin
regs[writeAddr] <= writeData;
end
end
assign readData1 = regs[readAddr1];
assign readData2 = regs[readAddr2];
endmodule
寄存器文件一般就是用DFF直接堆成的,将寄存器们堆成像文件一样,可同时读写(读是Q端读、写是D端写)。上面的32bit的寄存器文件,就是常见的32位CPU中数据通路中用到的片上32位寄存器文件。但是,我们平常用到的主存可不一样,主存一般来说是RAM(见下方)。
2、RAM with sync read
一般的RAM都是通过全定制芯片设计流程设计的,这里我们给出的只是behavioral model,也就是“行为模型”(端口、行为和正常的一模一样,但它只是基于Verilog的行为描述,一般来说不是由DFF而是由RAM bitcell组成):
module ram_sr #
(parameter DATA_WIDTH = 8, ADDR_WIDTH = 8)
(
clk , // Clock Input
address , // Address Input
d , // Data input
q , // Data output
cs , // Chip Select
web , // Write Enable/Read Enable, low active
oe // Output Enable
);
localparam RAM_DEPTH = 1 << ADDR_WIDTH;
//--------------Input Ports-----------------------
input clk;
input [ADDR_WIDTH-1:0] address;
input cs;
input web;
input oe;
//--------------Inout Ports-----------------------
input [DATA_WIDTH-1:0] d;
output [DATA_WIDTH-1:0] q;
//--------------Internal variables----------------
reg [DATA_WIDTH-1:0] data_out;
reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];
//--------------Core Function---------------------
// Tri-State Buffer control
// output : When web = 1, oe = 1, cs = 1
assign q = (cs && oe && web) ? data_out : 'bz;
// Memory Write Block
// Write Operation : When web = 0, cs = 1
always @ (posedge clk)
begin : MEM_WRITE
if ( cs && ~web ) begin
mem[address] = d;
end
end
// Memory Read Block
// Read Operation : When web = 1, oe = 1, cs = 1
always @ (posedge clk)
begin : MEM_READ
if (cs && web && oe) begin
data_out = mem[address];
end
end
endmodule
3、RAM with async read
一般的RAM都是手动做的,这里我们给出的只是behavioral model,也就是“行为模型”(端口、行为和正常的一模一样,但它只是基于Verilog的行为描述):
module ram_ar #
(parameter DATA_WIDTH = 8, ADDR_WIDTH = 8)
(
clk , // Clock Input
address , // Address Input
d , // Data input
q , // Data output
cs , // Chip Select
web , // Write Enable/Read Enable, low active
oe // Output Enable
);
localparam RAM_DEPTH = 1 << ADDR_WIDTH;
//--------------Input Ports-----------------------
input clk;
input [ADDR_WIDTH-1:0] address;
input cs;
input web;
input oe;
//--------------Inout Ports-----------------------
input [DATA_WIDTH-1:0] d;
output [DATA_WIDTH-1:0] q;
//--------------Internal variables----------------
reg [DATA_WIDTH-1:0] data_out;
reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];
//--------------Core Function---------------------
// Tri-State Buffer control
// output : When web = 1, oe = 1, cs = 1
assign q = (cs && oe && web) ? data_out : 'bz;
// Memory Write Block
// Write Operation : When web = 0, cs = 1
always @ (posedge clk)
begin : MEM_WRITE
if ( cs && ~web ) begin
mem[address] = d;
end
end
// Memory Read Block
// Read Operation : When web = 1, oe = 1, cs = 1
always @ (address or cs or web or oe)
begin : MEM_READ
if (cs && web && oe) begin
data_out = mem[address];
end
end
endmodule
4、Testbench
我们用同一套testbench测试上述两种RAM:
`timescale 1ns/1ns
module tb;
reg clk;
reg [7:0] addr;
reg [15:0] d;
reg cs;
reg web;
reg oe;
wire [15:0] q;
integer i;
initial begin
$dumpfile("wave.vcd");
$dumpvars(0);
$monitor("time=%4t, clk=%1b, web=%1b, d=%2h, q=%2h",$time,clk,web,d,q);
end
initial
begin
clk = 0;
forever #1 clk = ~clk;
end
initial
begin
cs = 1;
oe = 1;
// test write
for(i=0;i<(1<<4);i=i+1) begin
#2 web=0;
addr = i;
d = i;
end
// test read
for(i=0;i<(1<<4);i=i+1) begin
#2 web=1;
addr = i;
d = $random;
end
#10 $finish;
end
//这里需要改成想要实例化的ram_ar或者ram_sr
ram #(.DATA_WIDTH(16), .ADDR_WIDTH(8)) u0 (
.clk( clk )
,.address ( addr )
,.d ( d )
,.q ( q )
,.cs ( cs )
,.web ( web )
,.oe ( oe )
);
endmodule
然后在terminal里用iverilog+gtkwave来验证读、写功能:
iverilog -o wave a.v
vvp -n wave
gtkwave wave.vcd
练习
基础概念分辨
Note
[问题1] 请设计一个testbench测试一下上述regfil的设计,请提交波形图并用箭头标出相关的功能;另外,请总结regfile与RAM的主要区别。
Note
[问题2] 请结合波形图,说明async read与sync read的区别。
基于RAM的FIFO
FIFO是first in first out的首字母缩写,
Note
[问题3] 请基于RAM with sync read(实例化)包装出一个新的FIFO memory出来,并设计testbench测试一下,提交波形图截图并标记说明其功能。
FIFO是一种这样的功能模块:
请使用下方module商品定义:
module fifo (
input clk , // Clock input
input rstb , // Reset all function, low active
input rd , // Pop one datum out
input wr , // Push one datum in
input [15:0] data_in , // Data input port
output [15:0] data_out , // Data output port
output empty , // FIFO empty indicator, high active
output full // FIFO full indicator, low active
);