fpga && verilog

如何用 verilog 写一个 ALU

2019-11-04  本文已影响0人  madao756

前言:之前也写过一个 toy_vm,里面也涉及到四个标志位的更新,ALU 的难点也是这个四个标志位的更新,我每次都会忘这四个标志位如何更新的,每次都要搜索半天,这篇博客主要给出四个标志位的更新规则,以及相应的 verilog 代码!

0X00 哪四个标志位

有这四个标志位,在 ALU 中非常重要:

0X01 四个标志位更新的规则

以下标志位的更新只有关于:

ADD、ADDU、SUB、SUBU、AND、OR、XOR、NOR、LUI(至高位立即数)、SLT(有符号比较)、SLTU(无符号比较)、SRA(算数右移)、SLL/SLR(逻辑、算数左移)、SRL(算数右移)

zero 标志位更新规则

carry 标志位更新规则

negative 标志位更新规则

overflow 标志位更新规则

0X02 Carry vs Overflow

Carry 和 Overflow 很容易搞混,我来说说这两者的区别。

0X03 相应代码

zero 与 negative 标志位好判断,主要关注 carry 和 overflow

module ADDU(
    input [31:0] a,
    input [31:0] b,
    output reg [31:0] r,

    output reg zero,
    output reg carry,
    output reg negative,
    output reg overflow
);
    parameter WIDTH = 32;
    parameter MSB   = WIDTH - 1;

    reg extra;
    always @(*) begin
        // 计算
        {extra, r} = a + b;
        // 更新 flag
        zero = r ? 0 : 1;
        carry = extra;
        negative = r[MSB];
    end
    
endmodule

carry 只需多保留一位。如果进位,这一位为 1,不进位为 0。与 carry 标志位特点一致

module ADD(
    input [31:0] a,
    input [31:0] b,
    output reg [31:0] r,

    output reg zero,
    output reg carry,
    output reg negative,
    output reg overflow
);
    parameter WIDTH = 32;
    parameter MSB   = WIDTH - 1;

    reg extra;
    always @(*) begin
        // 计算
        {extra, r} = {a[MSB], a} + {b[MSB], b};
        // 更新 flag
        zero = r ? 0 : 1;
        negative = r[MSB];
        overflow  = ({extra, r[MSB]} == 2'b01) ||  ({extra, r[MSB]} == 2'b10);
    end
endmodule

overflow 判断的方法来自:https://stackoverflow.com/questions/24586842/signed-multiplication-overflow-detection-in-verilog/24587824#24587824

最后的 ALU 代码,我会整理以后,在 GitHub 中放出。

上一篇下一篇

猜你喜欢

热点阅读