本文是基于altera系列fifo和ram和FPGA学习笔记之IP核调用的补充,
(第二篇可以参照:Quartus基本IP核调用及仿真)
本次使用的FPGA型号是: 10CLO16YU484C8G
25M时钟:GCLK引脚G2,,
module test_ram(
input clk,//25M时钟
input rst_n
);
parameter CNT_256 = 256 ;
parameter CNT_32 = 32 ;
reg [7:0] data;
wire [4:0] rdaddress;
wire [4:0] wraddress;
wire [7:0] ram_q;
reg rden;
reg wren;
reg [8:0] cnt_256 ;
wire add_cnt_256 ;
wire end_cnt_256 ;
reg [4:0] cnt_32 ;
wire add_cnt_32 ;
wire end_cnt_32 ;
reg [4:0] cnt_32_r ;
wire add_cnt_32_r ;
wire end_cnt_32_r ;
pll pll_inst (
.areset ( ~rst_n ),
.inclk0 ( clk ),
.c0 ( c0 ),
.locked ( locked )
);
//assign c0 = clk;
//
RAM_2_PORT RAM_2_PORT_inst (
.data ( data ),
.rd_aclr (~rst_n ),
.rdaddress ( rdaddress ),
.rdclock ( clk ),
.rden ( rden ),
.wraddress ( wraddress ),
.wrclock ( c0 ),
.wren ( wren ),
.q ( ram_q )
);
//计数器cnt_256
always@(negedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_256 <= 0;
end
else if(add_cnt_256) begin
if(end_cnt_256)begin
cnt_256 <= 0;
end
else begin
cnt_256 <= cnt_256 + 1;
end
end
end
assign add_cnt_256 = 1'b1;//开启条件
assign end_cnt_256 = add_cnt_256 && cnt_256 == CNT_256 - 1;//结束条件
//计数器
always@(negedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_32 <= 0;
end
else if(add_cnt_32) begin
if(end_cnt_32)begin
cnt_32 <= 0;
end
else begin
cnt_32 <= cnt_32 + 1;
end
end
end
assign add_cnt_32 = rden ;//开启条件
assign end_cnt_32 = add_cnt_32 && cnt_32 == CNT_32 - 1;//结束条件
always@(negedge c0 or negedge rst_n)begin
if(!rst_n)begin
cnt_32_r <= 0;
end
else if(add_cnt_32_r) begin
if(end_cnt_32_r)begin
cnt_32_r <= 0;
end
else begin
cnt_32_r <= cnt_32_r + 1;
end
end
end
assign add_cnt_32_r = wren ;//开启条件
assign end_cnt_32_r = add_cnt_32_r && cnt_32_r == CNT_32 - 1;//结束条件
always@(negedge c0 or negedge rst_n)begin
if(!rst_n)begin
data <= 0;
end
else begin
data <= cnt_256;
end
end
assign rdaddress = (rden==1)? cnt_32 :0;
assign wraddress = (wren==1)? cnt_32_r :0;
always@(negedge clk or negedge rst_n)begin
if(!rst_n)begin
wren <= 0;
end
else if(cnt_256 == 6)begin
wren <= 1'b1;
end
else if (end_cnt_32_r)begin
wren <= 1'b0;
end
end
always@(negedge clk or negedge rst_n)begin
if(!rst_n)begin
rden <= 0;
end
else if(cnt_256 == 200)begin
rden <= 1'b1;
end
else if(end_cnt_32)begin
rden <= 1'b0;
end
end
endmodule
`timescale 1ns/1ps
module tb ();
reg clk ;
reg rst_n ;
always #20 clk = ~clk;
integer i = 0 , j =0 ;//用于产生地址,写入数据
initial begin
clk = 1'b1;
rst_n = 1'b1;
#200.1;
rst_n = 1'b0;
#200;
rst_n = 1'b1;
#20000;
$stop;
end
test_ram ram_tb(
.clk (clk ) ,//25M时钟
.rst_n (rst_n )
);
endmodule
module test_ram(
input clk,//25M时钟
// input [7:0] data,
// input [4:0] rdaddress,
// input rdclock,
// input rden,
// input [4:0] wraddress,
// input wrclock.
// input wren,
output [7:0] q,
output rst_n
);
parameter CNT_256 = 256 ;
parameter CNT_32 = 32 ;
reg [7:0] data;
wire [4:0] rdaddress;
wire [4:0] wraddress;
wire [7:0] ram_q;
reg rden;
reg wren;
reg [8:0] cnt_256 ;
wire add_cnt_256 ;
wire end_cnt_256 ;
reg [4:0] cnt_32 ;
wire add_cnt_32 ;
wire end_cnt_32 ;
reg [4:0] cnt_32_r ;
wire add_cnt_32_r ;
wire end_cnt_32_r ;
pll pll_inst (
.inclk0 ( clk ),
.c0 ( c0 ),
.c1 ( c1 ),
.locked ( rst_n )
);
//
RAM_2_PORT RAM_2_PORT_inst (
.data ( data ),
.rd_aclr (~rst_n ),
.rdaddress ( rdaddress ),
.rdclock ( clk ),
.rden ( rden ),
.wraddress ( wraddress ),
.wrclock ( c0 ),
.wren ( wren ),
.q ( ram_q )
);
//计数器cnt_256
always@(negedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_256 <= 0;
end
else if(add_cnt_256) begin
if(end_cnt_256)begin
cnt_256 <= 0;
end
else begin
cnt_256 <= cnt_256 + 1;
end
end
end
assign add_cnt_256 = 1'b1;//开启条件
assign end_cnt_256 = add_cnt_256 && cnt_256 == CNT_256 - 1;//结束条件
//计数器
always@(negedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_32 <= 0;
end
else if(add_cnt_32) begin
if(end_cnt_32)begin
cnt_32 <= 0;
end
else begin
cnt_32 <= cnt_32 + 1;
end
end
end
assign add_cnt_32 = rden ;//开启条件
assign end_cnt_32 = add_cnt_32 && cnt_32 == CNT_32 - 1;//结束条件
always@(negedge c0 or negedge rst_n)begin
if(!rst_n)begin
cnt_32_r <= 0;
end
else if(add_cnt_32_r) begin
if(end_cnt_32_r)begin
cnt_32_r <= 0;
end
else begin
cnt_32_r <= cnt_32_r + 1;
end
end
end
assign add_cnt_32_r = wren ;//开启条件
assign end_cnt_32_r = add_cnt_32_r && cnt_32_r == CNT_32 - 1;//结束条件
always@(negedge c0 or negedge rst_n)begin
if(!rst_n)begin
data <= 0;
end
else begin
data <= (cnt_256>>1) + 2;
end
end
assign rdaddress = cnt_32;
assign wraddress = cnt_32_r;
always@(negedge c0 or negedge rst_n)begin
if(!rst_n)begin
wren <= 0;
end
else if(cnt_256 <= 6)begin
wren <= 1'b1;
end
else if (end_cnt_32_r)begin
wren <= 1'b0;
end
end
always@(negedge clk or negedge rst_n)begin
if(!rst_n)begin
rden <= 0;
end
else if(cnt_256 == 200)begin
rden <= 1'b1;
end
else if(end_cnt_32)begin
rden <= 1'b0;
end
end
endmodule
(1)写数据
由波形图可以看出,写时钟(wrclk)上升沿寄存值,下降沿改变写地址(wradress)和数据(data)的值。
地址1放的值为7,地址2值为9,以此类推。
(2)读数据
可以看出由于寄存了输出q的值,故输出延迟了一个读时钟(rdclk)周期。
(1)写入数据
地址 | 存放数据 |
---|---|
0 | 2 |
1 | 3 |
… | … |
31 | 33 |
(2)读取数据
可以看出由于寄存了q的值,相比于未寄存q的输出晚了一个rdclock
(1)写数据同上
地址1放的值为7,地址2值为9,以此类推。
(2)读数据
可以看出没有寄存输出q的值,直接输出,无延时。地址1输出的值q为7,地址2输出的值q为9,以此类推
(1)写入数据
地址 | 存放数据 |
---|---|
0 | 2 |
1 | 3 |
… | … |
31 | 33 |
(2)读取数据
module test_fifo(
input clk,//25M时钟
input rst_n
);
parameter CNT_512 = 512 ;
parameter CNT_128 = 128 ;
reg [7:0] data ;
reg rdreq;
reg wrreq;
wire [7:0] q ;
wire rdempty;
wire rdfull ;
wire [6:0] rdusedw;
wire wrempty;
wire wrfull ;
wire [6:0] wrusedw;
reg [9:0] cnt_512 ;
wire add_cnt_512 ;
wire end_cnt_512 ;
reg [6:0] cnt_128 ;
wire add_cnt_128 ;
wire end_cnt_128 ;
pll pll_inst (
.areset ( ~rst_n ),
.inclk0 ( clk ),
.c0 ( c0 ),
.locked ( locked )
);
//assign c0 = clk;
//
FIFO FIFO_inst (
.aclr ( ~rst_n ),
.data ( data ),
.rdclk ( clk ),
.rdreq ( rdreq ),
.wrclk ( c0 ),
.wrreq ( wrreq ),
.q ( q ),
.rdempty ( rdempty ),
.rdfull ( rdfull ),
.rdusedw ( rdusedw ),
.wrempty ( wrempty ),
.wrfull ( wrfull ),
.wrusedw ( wrusedw )
);
//计数器cnt_512
always@(negedge c0 or negedge rst_n)begin
if(!rst_n)begin
cnt_512 <= 0;
end
else if(add_cnt_512) begin
if(end_cnt_512)begin
cnt_512 <= 0;
end
else begin
cnt_512 <= cnt_512 + 1;
end
end
end
assign add_cnt_512 = 1'b1;//开启条件
assign end_cnt_512 = add_cnt_512 && cnt_512 == CNT_512 - 1;//结束条件
always@(negedge c0 or negedge rst_n)begin
if(!rst_n)begin
data <= 0;
end
else begin
data <= cnt_512;
end
end
always@(negedge c0 or negedge rst_n )begin
if(!rst_n)begin
wrreq <= 0;
end
else if(cnt_512 == 2)begin
wrreq <= 1'b1;
end
else if (cnt_512 == 300)begin
wrreq <= 1'b0;
end
end
always@(negedge clk or negedge rst_n)begin
if(!rst_n)begin
rdreq <= 0;
end
else if(cnt_512 == 350)begin
rdreq <= 1'b1;
end
else if(end_cnt_128)begin
rdreq <= 1'b0;
end
end
//计数器
always@(negedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_128 <= 0;
end
else if(add_cnt_128) begin
if(end_cnt_128)begin
cnt_128 <= 0;
end
else begin
cnt_128 <= cnt_128 + 1;
end
end
end
assign add_cnt_128 = rdreq ;//开启条件
assign end_cnt_128 = add_cnt_128 && cnt_128 == CNT_128 - 1;//结束条件
endmodule
`timescale 1ns/1ps
module tb ();
reg clk ;
reg rst_n ;
always #20 clk = ~clk;
integer i = 0 , j =0 ;//用于产生地址,写入数据
initial begin
clk = 1'b1;
rst_n = 1'b1;
#200.1;
rst_n = 1'b0;
#200;
rst_n = 1'b1;
#50000;
$stop;
end
test_fifo fifo_tb(
.clk (clk ) ,//25M时钟
.rst_n (rst_n )
);
endmodule
module test_fifo(
input clk,//25M时钟
// input rst_n,
// input [7:0] data ,
// input rdreq ,
// input wrreq ,
output [7:0] q ,
output rdempty,
output rdfull ,
output [6:0] rdusedw,
output wrempty,
output wrfull ,
output [6:0] wrusedw,
output rst_n
);
parameter CNT_512 = 512 ;
parameter CNT_128 = 128 ;
reg [7:0] data ;
reg rdreq;
reg wrreq;
wire c1 ;
wire c0 ;
// reg c0;
// wire [7:0] q ;
// wire rdempty;
// wire rdfull ;
// wire [6:0] rdusedw;
// wire wrempty;
// wire wrfull ;
// wire [6:0] wrusedw;
reg [9:0] cnt_512 ;
wire add_cnt_512 ;
wire end_cnt_512 ;
reg [6:0] cnt_128 ;
wire add_cnt_128 ;
wire end_cnt_128 ;
pll pll_inst (
.inclk0 ( clk ),
.c0 ( c0 ),
.c1 ( c1 ),
.locked ( rst_n )
);
//assign c0 = clk;
//
FIFO FIFO_inst (
.aclr ( ~rst_n ),
.data ( data ),
.rdclk ( c1 ),
.rdreq ( rdreq ),
.wrclk ( c0 ),
.wrreq ( wrreq ),
.q ( q ),
.rdempty ( rdempty ),
.rdfull ( rdfull ),
.rdusedw ( rdusedw ),
.wrempty ( wrempty ),
.wrfull ( wrfull ),
.wrusedw ( wrusedw )
);
//计数器cnt_512
always@(negedge c1 or negedge rst_n)begin
if(!rst_n)begin
cnt_512 <= 0;
end
else if(add_cnt_512) begin
if(end_cnt_512)begin
cnt_512 <= 0;
end
else begin
cnt_512 <= cnt_512 + 1;
end
end
end
assign add_cnt_512 = 1'b1;//开启条件
assign end_cnt_512 = add_cnt_512 && cnt_512 == CNT_512 - 1;//结束条件
always@(negedge c0 )begin
data <= cnt_512>>1;
end
always@(negedge c0 or negedge rst_n )begin
if(!rst_n)begin
wrreq <= 0;
end
else if(cnt_512 <= 2)begin
wrreq <= 1'b1;
end
else if (cnt_512>= 300)begin
wrreq <= 1'b0;
end
end
always@(negedge c1 or negedge rst_n)begin
if(!rst_n)begin
rdreq <= 0;
end
else if(cnt_512 == 350)begin
rdreq <= 1'b1;
end
else if(end_cnt_128)begin
rdreq <= 1'b0;
end
end
//计数器
always@(negedge c1 or negedge rst_n)begin
if(!rst_n)begin
cnt_128 <= 0;
end
else if(add_cnt_128) begin
if(end_cnt_128)begin
cnt_128 <= 0;
end
else begin
cnt_128 <= cnt_128 + 1;
end
end
end
assign add_cnt_128 = rdreq ;//开启条件
assign end_cnt_128 = add_cnt_128 && cnt_128 == CNT_128 - 1;//结束条件
endmodule
(1)写入数据
wrreq写请求信号拉高,写时钟(wrclk)上升沿数据写入,下降沿数据改变.开始写入第一个数据,fifo不为空,wrempty由高拉低。
延迟一个时钟周期(wrclk)可以看到写入第一个数据(data=8’d2)完成,此时(wrusedw=wrusedw+1=1)。
数据写满后,wrfull拉高,最后一个数据(data=8’d129)
(2)读数据
开始读完第一个数据后,rdempty由高拉低,rdusedw相较于wrreq延迟(2·wrclk+1·rdclk)个周期。相较于wrusedw延时(1·wrclk+1·rdclk)个周期.
读取的第一个数据(q=8‘d2).可以看出数据有效在wrreq有效之前读出,当wrreq有效后读出第二个数据data=8’d3.
读完第一个数据的同时rdfull拉低
读完最后一个数据(q=8’d129),rdempty拉高,数据全部读出
为了方便观察,data +2,第一个数据为2
可以看出在rdreq有效之前已经输出了第一个数据,在wrreq有效·之后已经是从第二个数据开始输出的。
可以看出在rdreq有效后读出数据,读出第一个数据(data=8’d2)
(1)存入第一个数据
(2)存入最后一个数据
(3)读取第一个数据、
(4)读取最后一个数据