一、 实验目的
1.学习如何使用ISE的IP核
2.学习使用Xilinx FPGA内的RAM资源
a)例化一个简单双端口的RAM(32bitx64)
b)使用coe文件对RAM进行初始化
二、 实验要求
1.综合利用三次实验的结果,完成以下功能:
a)从ram中0地址和1地址读取两个数, 分别赋给reg0和reg1
b)利用第二次实验的结果(ALU+Regfile)进行斐波拉契运算,运算结果保存在对应的寄存器
c)运算结果同时保存在对应的ram地址中,即ram[0]<----->reg0,ram[1]<----->reg1,
ram[2]<----->reg2,……
2.实现一个control模块,完成整个运算的控制。
3.实现一个顶层模块Top
a)调用Ram
b)调用RegFile
c)调用ALU完成运算
d)调用control模块,完成运算控制
三、 实验内容
1.生成IP核
模块参数如下:
2.主要代码分析
module top(
input clk,
output[31:0] writein,
output[31:0] readout1,
output[31:0] readout2
);
reg[5:0] readaddr=5'd0;
wire[31:0] readout;
wire[5:0] addrb;
wire[5:0] addra;
wire writeenable;
wire[31:0] doutb;
//例化模块如下,其中ram和regfile使用同一个使能writeenable、同一个写入地址//addra和同一个写入内容writein,ram的两个端口使能保持为1
ram ra(clk,1'b1,writeenable,addra,writein,clk,1'b1,addrb,doutb);
regfilere(clk,1'b1,readaddr,readout,addra,writein,writeenable);
alu al(readout1,readout2,5'd1,writein);
controlcon(clk,doutb,writeenable,readout1,readout2,addra,addrb);
endmodule
********************************************************************************************
module control(
input clk,
input [31:0] doutb,
output reg writeenable,
output reg[31:0] readout1,
output reg[31:0] readout2,
output reg[5:0] addra,
output reg[5:0] addrb
);
reg[2:0] count = 3'd0;
reg flag = 1'b0;
always@(negedgeclk) //control部分,利用标记数count来
//进行步骤的循环,每次循环里面有
//四个步骤,分别在下降沿执行,修改
//在上升沿的执行的regfile的参数
begin
if(flag== 1'b0) //如果flag=0,先进行初始化,即先
begin //将ram【0】、ram【1】里的内容都
if(count==3'd0) //复制存储到regfile中
begin
addrb<= 1'b0;
count<= count+1'b1;
writeenable<=1'b0;
end
else if(count==3'd1)
begin
count <= count + 1'b1;
readout1 <= doutb;
readout2 <= 1'b0;
addra <= addrb;
addrb <= addrb + 1'b1;
writeenable <=1'b1;
end
else if(count==3'd2)
begin
count <= count + 1'b1;
readout1 <= doutb;
readout2 <= 1'b0;
addra <= addrb-1'b1;
addrb <= addrb + 1'b1;
writeenable <=1'b1;
end
else if(count==3'd3) //初始化复制完成,flag赋值为1
begin //count等数值归零
count<= 1'b0;
addrb <= 1'b0;
flag <= 1'b1;
end
end
else
begin
if(count==3'd0)
begin
count <= count + 1'b1;
writeenable <=1'b0;
end
elseif(count==3'd1) //修改操作数2读取地址
begin
count <= count + 1'b1;
readout1 <= doutb;
addrb <= addrb + 1'b1;
writeenable <=1'b0;
end
elseif(count==3'd2)
begin
count <= count + 1'b1;
readout2 <= doutb;
writeenable <=1'b0;
end
else if(count==3'd3) //修改写入addra地址和write使能
begin
writeenable <=1'b1;
addra <= addrb + 1'b1;
count <= 3'd0;
end
end
end
endmodule
******************************************************************************************
Alu和regfile模块见前两次实验报告,此处略去
3.coe文件编写
如图:
4.仿真
(可以发现下降沿修改时,结果即时发生变化,但是在上升沿写入寄存器的结果是斐波那契数列的正确结果,4,6,10,16,26,42,68,110,178……每次写入是正确的,可知读取的也是正确的。
打开观察ram中的内容可以验证正确。)
四、 实验分析和总结
本实验regfile、alu均调用之前实验的编写结果,关键在于control部分的逻辑要清晰。
在对regfile和ALU进行control时,考虑到regfile模块是时钟上升沿敏感的,所以在下降沿对实例化的参数进行修改,这样充分利用了每个时钟周期,而且不会导致冲突。
Ram可以当作一个普通模块调用,有相应的输出输出接口,可以在generate的时候设置ram的相关参数,例如ram的深度宽度,端口的宽度等等。Ram初始化要使用coe文件。