Verilog實現加減乘除運算

漫步人生只為尋你發表於2019-01-09

用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 
 

相關文章