我所使用的版本是Quartus II 13.1及Modelsim SE-64 10.4
一、创建新工程
1.点击New Project Wizard创建
2.第一行是工程文件存放位置,第二行是工程的名称,第三行默认和第二行一样为顶层模块
3.点击next,next,然后在simulation处选择仿真方式及编写程序使用的语言
4.然后点击 next,最后finish便完成了一个工程的创建
二、代码编写
1.左上角选择新建file,选择需要的语言文件
2.输入你写的代码,然后ctrl+s保存文件,注意保存时的文件名需要与你的模块名一致,且至少需要有一个模块名为上述提及的顶层模块,我这里的是“Instruction”
3.编写完成之后,点击下述图片的三角进行编译
4.编译正常后我们便可以开始下一步编写测试平台
三、与Modelsim进行联合仿真
1.点击Processing->Start->Start test bench template writer,生成测试平台文件
2.找到.vt文件,进行测试代码的编写
3.接下来设置仿真,点击Tools->Options->EDA Tools Options,选择Modelsim安装目录下的Win64或Win32,若显示找不到modelsim的可以试试多加一个‘\’在末尾
4.然后将你刚刚的.vt文件设置一下,点击Assignments->Settings->Simulation
点击Test Benches->New
第一行是.vt文件的名字,第二行打开你的.vt文件,看看里面的模块名是什么,一定要保持一致,然后在file name下找到你的.vt文件,点击Add,便会出现在下面的框框里,接下来一直点击OK即可
对仿照时间有需要的话,可以自行选择End simulation at:
5. 进行仿真,会跳转到modelsim
6.选择wave文件便可看到波形
四、测试代码
这里仅仅是我随便写的一次作业代码,仅供大家参考运行
module Registers_32(Clk, wr, Ra, Rb, Rw, busW, busA, busB);
parameter n = 32; // 每个寄存器宽度
parameter num = 32; // 寄存器数量
input Clk, wr; // 时钟信号和写使能信号
input [4:0] Ra, Rb, Rw; // 读/写地址
input [n-1:0] busW; // 写入数据总线
output reg [n-1:0] busA, busB; // 读出数据总线
reg [n-1:0] register[num-1:0]; // 寄存器组
integer i;
// 初始化寄存器组
initial begin
for (i = 0; i < num; i = i + 1)
register[i] <= i;
end
// 读操作 (组合逻辑操作)
always @(*) begin
busA = register[Ra]; // 从地址 Ra 对应的寄存器中读数据
busB = register[Rb]; // 从地址 Rb 对应的寄存器中读数据
end
// 写操作 (时序逻辑操作)
always @(negedge Clk) begin
if (wr) begin
register[Rw] <= busW; // 在时钟下降沿,将数据写入地址 Rw 对应的寄存器
end
end
endmodule
module DataMemory(DataIn, Clk, WrEn, Adr, DataOut);
parameter n = 32; // 数据宽度
input WrEn, Clk; // 写使能和时钟信号
input [n-1:0] DataIn; // 写入数据
input [31:0] Adr; // 地址
output reg [n-1:0] DataOut; // 读出数据
reg [n-1:0] MemReg[255:0]; // 256 个 32 位存储单元
integer i;
// 初始化存储器
initial begin
for (i = 0; i < 256; i = i + 1)
MemReg[i] = i;
end
// 写操作 (时序逻辑操作)
always @(negedge Clk) begin
if (WrEn) begin
MemReg[Adr] <= DataIn; // 在时钟下降沿,将数据写入指定地址
end
end
// 读操作 (组合逻辑操作)
always @(*) begin
DataOut = MemReg[Adr]; // 从指定地址读数据
end
endmodule
顶层模块
module Instruction(Clk, RegWrEn, MemWrEn, Ra, Rb, Rw, MemAdr, RegDataIn, MemDataIn, RegDataOutA, RegDataOutB, MemDataOut);
parameter n = 32;
input Clk, RegWrEn, MemWrEn; // 时钟信号和写使能信号
input [4:0] Ra, Rb, Rw; // 寄存器地址
input [31:0] MemAdr; // 存储器地址
input [n-1:0] RegDataIn, MemDataIn; // 写入寄存器和存储器的数据
output [n-1:0] RegDataOutA, RegDataOutB; // 寄存器读出数据
output [n-1:0] MemDataOut; // 存储器读出数据
// 实例化寄存器组模块
Registers_32 registers(
.Clk(Clk),
.wr(RegWrEn),
.Ra(Ra),
.Rb(Rb),
.Rw(Rw),
.busW(RegDataIn),
.busA(RegDataOutA),
.busB(RegDataOutB)
);
// 实例化存储器模块
DataMemory memory(
.DataIn(MemDataIn),
.Clk(Clk),
.WrEn(MemWrEn),
.Adr(MemAdr),
.DataOut(MemDataOut)
);
endmodule
.vt文件
`timescale 1 ps / 1 ps
module Instruction_vlg_tst();
// constants
// general purpose registers
reg [31:0] cycle; // 记录测试循环
// test vector input registers
reg Clk;
reg [31:0] MemAdr;
reg [31:0] MemDataIn;
reg MemWrEn;
reg [4:0] Ra;
reg [4:0] Rb;
reg [31:0] RegDataIn;
reg RegWrEn;
reg [4:0] Rw;
// wires
wire [31:0] MemDataOut;
wire [31:0] RegDataOutA;
wire [31:0] RegDataOutB;
// DUT (Device Under Test)
Instruction i1 (
// port map - connection between master ports and signals/registers
.Clk(Clk),
.MemAdr(MemAdr),
.MemDataIn(MemDataIn),
.MemDataOut(MemDataOut),
.MemWrEn(MemWrEn),
.Ra(Ra),
.Rb(Rb),
.RegDataIn(RegDataIn),
.RegDataOutA(RegDataOutA),
.RegDataOutB(RegDataOutB),
.RegWrEn(RegWrEn),
.Rw(Rw)
);
// 时钟信号生成
initial begin
Clk = 0;
forever #50 Clk = ~Clk; // 时钟周期
end
// 测试逻辑
initial begin
$display("Running testbench...");
cycle = 0;
// 初始化信号
MemAdr = 0; MemDataIn = 0; MemWrEn = 0;
Ra = 0; Rb = 0; Rw = 0;
RegDataIn = 0; RegWrEn = 0;
// 等待复位时间
#200;
// 测试1:寄存器组写操作和读操作
$display("Test 1: Registers_32 Write and Read");
Rw = 5'd2; // 写寄存器2
RegDataIn = 32'hA5A5; // 写入数据 0xA5A5
RegWrEn = 1; // 启用写操作
#100; // 等待一个时钟周期
RegWrEn = 0; // 停止写操作
Ra = 5'd2; // 读取寄存器2
#100; // 等待组合逻辑延迟
if (RegDataOutA == 32'hA5A5) begin
$display("PASS: Register Read/Write");
end else begin
$display("FAIL: Register Read/Write");
end
// 测试2:数据存储器写操作和读操作
$display("Test 2: DataMemory Write and Read");
MemAdr = 32'd100; // 地址 100
MemDataIn = 32'h5A5A; // 写入数据 0x5A5A
MemWrEn = 1; // 启用写操作
#100; // 等待一个时钟周期
MemWrEn = 0; // 停止写操作
MemAdr = 32'd100; // 地址 100
#100; // 等待组合逻辑延迟
if (MemDataOut == 32'h5A5A) begin
$display("PASS: DataMemory Read/Write");
end else begin
$display("FAIL: DataMemory Read/Write");
end
// 测试完成
$display("All tests completed.");
$finish;
end
endmodule
(作者是初学者,文章若是有不对的地方欢迎大家指出,一起学习)