【FPGA学习】- 存储器设计
只读存储器
只读存储器:Read-Only Memory(ROM),是一种极为重要的时序逻辑存储电路。逻辑功能是在地址信号的选择下,从指定的存储单元中读出相应的数据。特点是ROM只能进行数据的读取,而不能修改或者写入新的数据。
16×8位的只读存储器设计如下。输入信号为地址选择信号addr,使能端en;输出信号为数据输出端data。
ROM设计如下。
module rom(en, addr, data); input en; input [3:0] addr; output reg [7:0] data; //中间变量,传值给data reg [7:0] data1[15:0]; always @(*) begin data1[0] = 8'b1010_1001; data1[1] = 8'b1111_1101; data1[2] = 8'b1110_1001; data1[3] = 8'b1101_1100; data1[4] = 8'b1011_0010; data1[5] = 8'b1100_1001; data1[6] = 8'b1100_0101; data1[7] = 8'b0000_0100; data1[8] = 8'b1110_1100; data1[9] = 8'b1100_1001; data1[10] = 8'b1010_0111; data1[11] = 8'b0011_0100; data1[12] = 8'b1100_0001; data1[13] = 8'b1001_1111; data1[14] = 8'b1010_0101; data1[15] = 8'b0101_1100; if(en) data[7:0] = data1[addr]; else data[7:0] = 8'bzzzz_zzzz; end endmodule
testbench。
`timescale 1ms/1ms module rom_testbench; reg en; reg [3:0] addr; wire [7:0] data; rom r1(en, addr, data); initial begin en = 0; #2 en = 1; addr = 4'd0; #2 en = 1; addr = 4'd1; #2 en = 1; addr = 4'd2; #2 en = 1; addr = 4'd3; #2 en = 1; addr = 4'd4; #2 en = 1; addr = 4'd5; #2 en = 1; addr = 4'd6; #2 en = 1; addr = 4'd7; #2 en = 0; addr = 4'd8; #2 en = 1; addr = 4'd9; #2 en = 0; addr = 4'd10; #2 en = 0; addr = 4'd11; #2 en = 1; addr = 4'd12; #5 $stop; end initial begin $monitor($time,"\ten = %b, addr = %d, data = %b\t",en, addr, data); end endmodule
仿真结果。当使能端为1时,data输出数据;否则,data端为高阻态。
随机存储器
随机存储器:Random Access Memory(RAM),逻辑功能是在地址信号的选取下,对指定的存储单元的数据进行读或写操作,所以随机存储器常用于动态数据的存储。
32×8位的的RAM设计如下图。输入信号为地址选择信号addr,写信号wr,读信号rd,片选信号cs,数据写入端datain;输出信号为dataout。
设计如下
module ram(addr, wr, rd, cs, datain, dataout); input wr, rd, cs; input [4:0] addr; input [7:0] datain; output reg [7:0] dataout; reg [7:0] data_space[31:0]; //写操作 always @(*) begin if(cs == 0) begin if(wr) data_space[addr] = datain; else dataout = 1'bz; end else dataout = 1'bz; end //读操作 always @(*) begin if(cs == 0) begin if(rd) dataout = data_space[addr]; else dataout = 1'bz; end else dataout = 1'bz; end endmodule
testbench。
`timescale 1ms/1ms module ram_testbench; reg wr, rd, cs; reg [4:0] addr; reg [7:0] datain; wire [7:0] dataout; ram r1(addr, wr, rd, cs, datain, dataout); initial begin cs = 1'b1; #2 cs = 1'b0; addr = 5'd0; rd = 1'b0; wr = 1'b1; datain = 8'd15; #2 cs = 1'b0; addr = 5'd1; rd = 1'b0; wr = 1'b1; datain = 8'd10; #2 cs = 1'b0; addr = 5'd2; rd = 1'b0; wr = 1'b1; datain = 8'd32; #2 cs = 1'b0; addr = 5'd3; rd = 1'b0; wr = 1'b1; datain = 8'd97; #2 cs = 1'b1; #2 cs = 1'b0; addr = 5'd2; rd = 1'b1; wr = 1'b0; #2 cs = 1'b0; addr = 5'd3; rd = 1'b1; wr = 1'b0; #2 cs = 1'b0; addr = 5'd1; rd = 1'b1; wr = 1'b0; #5 $stop; end initial begin $monitor($time, "\twr = %d, rd = %d, addr = %d, dataout = %d\t", wr, rd, addr, dataout); end endmodule
测试结果。写信号有效时,可以写入数据;读信号有效时,可以读出数据;当片选信号无效时,输出为高阻态。
堆栈
堆栈:堆栈是一种执行先入后出的存储器。数据逐个存入的过程叫做压栈(push),数据逐个取出的过程称为出栈(pop)。最开始放入数据的单元称为栈底,最后存入数据的单元称为栈顶。
8B的堆栈设计如下图。输入信号为清零信号clr,时钟信号clk,压栈信号push,出栈信号pop,输入端din;输出信号为栈空信empty,栈满信号full和输出端dout。
设计如下。
module stack( input clr, input push, input pop, input clk, input [7:0] din, output empty, output full, output [7:0] dout ); reg empty, full; reg [7:0] dout; reg[7:0] stack[8:0]; reg[3:0] cnt; always @(posedge clk) begin if(clr) begin //clear dout <= 0; full <= 0; cnt <= 0; end else if(push && (!pop) && (cnt != 'b1000)) begin //push empty <= 0; stack[cnt] <= din; cnt <= cnt + 1; end else if(pop && (!push) && (cnt != 'b0)) begin //pop full <= 0; cnt <= cnt - 1; dout <= stack[cnt]; end else if(cnt == 'b0) begin empty <= 1; dout <= 'b0; end else if(cnt == 'b1000) full <= 1; end endmodule
FIFO
FIFO:先入先出存储器。是一种单向的数据传输的物理器件,只允许数据从输入端流向输出端。特点在于不需要地址线,而只需要数据线与读/写控制线。
8B的FIFO如下。输入信号为时钟信号clk,清零端clr,写信号wr,读信号rd,数据写入端din;输出信号为数据读出端dout[7:0],存储器空信号empty,存储器满信号full。