存储器组织
实验原理
假设CPU的主存空间为2K×8,实验中的基本存储模块为256×4位,采用字位扩展方式构成1K×8的存储器,位于整个2K主存空间的较低1K空间,原理图如图 1所示,8个256×4位的存储芯片采用字位扩展方式构成1K×8的存储器。 ADDR为地址输入端,高两位地址通过译码产生片选信号,低8位地址与存储芯片的地址端相连,DATA为数据输入端,存储芯片的数据输出端与总线DB相连。
图 1. 主存储器组织实验原理图
RAM模块设计
模拟一般的静态RAM芯片的引脚,RAM模块的端口设计有地址输入(ADDR)、数据输入(DIN)、数据输出(DOUT)、写使能(WR)、读使能(RD)、片选(CS)。和普通SRAM芯片不同的是,FPGA内部的RAM模块设计为同步存储器,还有一个时钟输入(CLK)端口。设计代码见清单 1。片选信号控制“芯片”是否工作,片选无效时,不能进行读写操作,DOUT输出为高阻态;片选有效时,允许写入和读出。
清单 1. 256×4位的RAM模块
module RAM
#(parameter ADDR_SIZE = 8, parameter DATA_SIZE = 4)
(
output wire [DATA_SIZE-1:0] DOUT,
input wire [DATA_SIZE-1:0] DIN,
input wire [ADDR_SIZE-1:0] ADDR,
input wire CLK,
input wire CS,
input wire RD,
input wire WR
);
localparam MEM_DEPTH = 1 << ADDR_SIZE;
reg [DATA_SIZE-1:0] mem [0 : MEM_DEPTH-1];
reg [ADDR_SIZE-1:0] read_addr;
always @(posedge CLK)
begin
read_addr <= ADDR; //有这句读地址锁存,Altera综合工具才能推断为 Single Port RAM 块。
if (CS & WR)
mem[ADDR] = DIN;
end
assign DOUT = (CS & RD) ? mem[read_addr] : {DATA_SIZE{1'bz}};
endmodule
虚拟实验板模块
清单 2. 存储器组织
//输入端口赋值给内部信号
wire CLK = PB[0];
wire [7:0] DATA = S[7:0];
wire [10:0] ADDR = S[18:8];
wire WR = S[19];
wire RD = S[20];
wire MEM = S[21];
wire DATAoe = S[22];
//总线缓冲
wire [7:0] DB = DATAoe ? DATA : 8'bzzzzzzzz;
//译码器的使能信号
logic en;
assign en = MEM & ~ADDR[10];
//高2位地址经过2-4译码器产生各RAM块的片选信号
logic [3:0] Y;
always_comb
begin
if (en)
case(ADDR[9:8])
0: Y = 4'b0001;
1: Y = ; (1)
2: Y = ;
3: Y = ; (2)
default: Y = 4'bxxxx;
endcase
else
Y = 4'b0000;
end
//模块实例, 256x4位扩展为 1Kx8
RAM #(8,4) U0(.CS(Y[0]), .WR(WR), .RD(RD), .CLK(CLK), .ADDR(ADDR[7:0]), .DIN(DB[3:0]), .DOUT(DB[3:0]));
RAM #(8,4) U1(.CS(Y[0]), .WR(WR), .RD(RD), .CLK(CLK), .ADDR(ADDR[7:0]), .DIN(DB[7:4]), .DOUT(DB[7:4]));
RAM #(8,4) U2(.CS( ), .WR(WR), .RD(RD), .CLK(CLK), .ADDR( ), .DIN( ), .DOUT( )); (3)
RAM #(8,4) U3(.CS( ), .WR(WR), .RD(RD), .CLK(CLK), .ADDR( ), .DIN( ), .DOUT( ));
RAM #(8,4) U4(.CS( ), .WR(WR), .RD(RD), .CLK(CLK), .ADDR( ), .DIN( ), .DOUT( ));
RAM #(8,4) U5(.CS( ), .WR(WR), .RD(RD), .CLK(CLK), .ADDR( ), .DIN( ), .DOUT( ));
RAM #(8,4) U6(.CS( ), .WR(WR), .RD(RD), .CLK(CLK), .ADDR( ), .DIN( ), .DOUT( ));
RAM #(8,4) U7(.CS( ), .WR(WR), .RD(RD), .CLK(CLK), .ADDR( ), .DIN( ), .DOUT( )); (4)
//内部信号赋值给输出端口(指示灯)观察
assign L[7:0] = DB ;
assign L[21:18]= Y;
assign L[17] = en;