用Verilog实现,两个16位输入,一个32位输出的四则运算模块,这里我是使用的调用IP核的方式,毕竟人家官方推出的要比我们自个写的要稳定一点,这里调用了加法器,减法器,乘法器,触发器的IP核。
代码如下:
module jisuan(
//input pin;
Clk,
Rst_n,
data_A,
data_B,
mode, //+,-,*,/.
start,
//output pin;
data_C
);
//input pin define;
input Clk;
input Rst_n;
input [1 : 0]mode;
input [15 : 0]data_A;
input [15 : 0]data_B;
input start;
//output pin define;
output reg[31 : 0]data_C;
localparam
add = 2'b00,
min = 2'b01,
mul = 2'b10,
did = 2'b11;
wire [15 : 0]result1;
wire [15 : 0]result2;
wire [31 : 0]result3;
reg add_sub;
wire cout;
reg clken_subormin;
reg clken_chufa;
reg clken_chengfa;
reg aclr;
subormin subormin1(
.aclr(aclr),
.add_sub(add_sub),
.clken(clken_subormin),
.clock(Clk),
.dataa(data_A),
.datab(data_B),
.result(result1)
);
chufa chufa1(
.aclr(aclr),
.clken(clken_chufa),
.clock(Clk),
.denom(data_B),
.numer(data_A),
.quotient(result2),
.remain()
);
chengfa chengfa1(
.aclr(aclr),
.clken(clken_chengfa),
.clock(Clk),
.dataa(data_A),
.datab(data_B),
.result(result3)
);
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
clken_subormin <= 1'b0;
clken_chengfa <= 1'b0;
clken_chufa <= 1'b0;
add_sub <= 1'b0;
aclr <= 1'b1; //清零
end
else if(start) begin
aclr <= 1'b0;
case(mode)
add : begin add_sub <= 1'b1; clken_subormin <= 1'b1; end
min : begin add_sub <= 1'b0; clken_subormin <= 1'b1; end
mul : clken_chengfa <= 1'b1;
did : clken_chufa <= 1'b1;
default: ;
endcase
end
else begin
clken_subormin <= 1'b0;
clken_chengfa <= 1'b0;
clken_chufa <= 1'b0;
aclr <= 1'b1;
end
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
data_C <= 32'd0;
else if(start)
case(mode)
add : data_C[15 : 0] <= result1;
min : data_C[15 : 0] <= result1;
did : data_C[15 : 0] <= result2;
mul : data_C <= result3;
default : data_C <= 32'd0;
endcase
else
data_C <= 32'd0;
endmodule
模块使用方法:输入data_A,data_B,确定mode(加,减,乘,除),然后Start=1,开始进行计算,四个时钟周期后,data_C上的值就是运算结果。至于为什么要等待四个时钟周期呢,这是因为做运算是需要时间的吗,不可能刚给个输入数据,就直接可以得到输出数据。这个时间是怎么来的呢?通过仿真得来的,经过时序仿真,发现第四个时钟沿的时候数据是稳定的。
仿真代码如下:
`timescale 1ns / 1ns
`define clk_period 20
module jisuan_tb();
//input pin define;
reg Clk;
reg Rst_n;
reg [1 : 0]mode;
reg [31 : 0]data_A;
reg [31 : 0]data_B;
reg start;
//output pin define;
wire [31 : 0]data_C;
wire done;
initial Clk = 1;
always #(`clk_period / 2) Clk = ~Clk;
jisuan u1(
//input pin;
.Clk(Clk),
.Rst_n(Rst_n),
.data_A(data_A),
.data_B(data_B),
.mode(mode), //+,-,*,/.
.start(start),
//output pin;
.data_C(data_C)
);
initial begin
mode = 0;
Rst_n = 0;
start = 0;
#(20 * `clk_period);
Rst_n = 1;
#(20 * `clk_period);
repeat(10)begin
data_A = {$random} % 100;
data_B = {$random} % 100;
mode = mode + 1;
start = 1;
#(20 * `clk_period);
start = 0;
#(20 * `clk_period);
end
$stop;
end
endmodule
这里还有个问题,就是这个IP核是怎么调用的呢?这个问题也困扰了我好久,有些IP核我们听都没听过,我们怎么知道什么时候可以用IP核,以及IP核的调用格式呢?这里我分享一个关于altera IP核的电子书:
链接:https://pan.baidu.com/s/1P7y-ZCWhs0Ay6bLFZF3t5A
提取码:k6js