fpga系列 HDL:Relu激活函数实现与仿真

  • 代码实现对OUTPUT_NODES个32位浮点数进行RELU操作。
  • 32位浮点数的二进制表示遵循 IEEE 754 标准,通常称为单精度浮点数。这个标准定义了浮点数的表示方法,具体分为三个部分:
    • 符号位 (1 bit): 用于表示浮点数的正负。( 0 表示正数,1 表示负数)
    • 指数位 (8 bits): 用于表示指数部分,并采用偏移量 (bias) 编码。
    • 尾数 (或称为有效数字, 23 bits): 用于表示浮点数的有效数字部分。

Module

// https://github.com/omarelhedaby/CNN-FPGA/blob/master/Final%20Code%20Files/Part%205-%20Integration/activationFunction.v
module activationFunction(clk, reset, en, input_fc, output_fc);
    // 模块定义,名称为 activationFunction
    // 输入信号:
    // - clk: 时钟信号
    // - reset: 复位信号
    // - en: 使能信号
    // - input_fc: 输入数据,宽度为 DATA_WIDTH*OUTPUT_NODES
    // 输出信号:
    // - output_fc: 输出数据,宽度为 DATA_WIDTH*OUTPUT_NODES

    // 参数定义
    parameter DATA_WIDTH = 32;       // 数据宽度,默认为 32 位
    parameter OUTPUT_NODES = 32;     // 输出节点数,默认为 32 个

    // 输入信号定义
    input clk, reset, en;                        // 时钟信号、复位信号和使能信号
    input [DATA_WIDTH*OUTPUT_NODES-1:0] input_fc; // 输入数据,总宽度为 DATA_WIDTH*OUTPUT_NODES
    output reg [DATA_WIDTH*OUTPUT_NODES-1:0] output_fc; // 输出数据,总宽度同样为 DATA_WIDTH*OUTPUT_NODES

    // 内部变量声明
    integer i;  // 循环变量 i

    // 在时钟负边沿或复位信号正边沿触发的过程块
    always @ (negedge clk or posedge reset) begin
        // 检查复位信号
        if (reset == 1'b1) begin
            // 如果复位信号为高电平(1),则将输出数据清零
            output_fc = 0;
        end else begin
            // 如果不是复位状态,则检查使能信号
            if (en == 1'b1) begin
                // 如果使能信号为高电平(1),则处理输入数据
                for (i = 0; i < OUTPUT_NODES; i = i + 1) begin
                    // 对每一个输出节点执行以下操作
                    // 检查输入数据中对应数据位的符号位(最高位)
                    if (input_fc[DATA_WIDTH*i + DATA_WIDTH - 1] == 1'b1) begin
                        // 如果符号位为 1,表示该数据为负数或需要置为 0
                        // 对应的输出数据设置为 0
                        output_fc[DATA_WIDTH*i +: DATA_WIDTH] = 0;
                    end else begin
                        // 否则,将输入数据直接赋值给输出数据
                        output_fc[DATA_WIDTH*i +: DATA_WIDTH] = input_fc[DATA_WIDTH*i +: DATA_WIDTH];
                    end
                end
            end
        end
    end

endmodule

TestBench

// Code your testbench here
// or browse Examples
`timescale 1ns / 1ps

module tb_activationFunction;

    // 参数定义
    parameter DATA_WIDTH = 32;
    parameter OUTPUT_NODES = 32;

    // 测试平台中的信号
    reg clk;
    reg reset;
    reg en;
    reg [DATA_WIDTH*OUTPUT_NODES-1:0] input_fc;
    wire [DATA_WIDTH*OUTPUT_NODES-1:0] output_fc;

    // 实例化被测试模块
    activationFunction #(
        .DATA_WIDTH(DATA_WIDTH),
        .OUTPUT_NODES(OUTPUT_NODES)
    ) uut (
        .clk(clk),
        .reset(reset),
        .en(en),
        .input_fc(input_fc),
        .output_fc(output_fc)
    );

    // 时钟生成
    initial begin
        clk = 0;
        forever #5 clk = ~clk; // 每 5 时间单位切换一次时钟状态
    end

    // 测试过程
    initial begin
        // 初始化信号
        reset = 1;
        en = 0;
        input_fc = 0;

        // 复位过程
        #10;
        reset = 0;

        // 测试 1: 输入数据处理
        #10;
        en = 1;
        input_fc = {32'h00000001, 32'h00000002, 32'h00000003, 32'h00000004,
                    32'h00000005, 32'h00000006, 32'h00000007, 32'h00000008,
                    32'h00000009, 32'h0000000A, 32'h0000000B, 32'h0000000C,
                    32'h0000000D, 32'h0000000E, 32'h0000000F, 32'h00000010,
                    32'h00000011, 32'h00000012, 32'h00000013, 32'h00000014,
                    32'h00000015, 32'h00000016, 32'h00000017, 32'h00000018,
                    32'h00000019, 32'h0000001A, 32'h0000001B, 32'h0000001C,
                    32'h0000001D, 32'h0000001E, 32'h0000001F, 32'h00000020};

        // 等待处理完成
        #10;

        // 测试 2: 改变输入数据,测试负数的处理
        input_fc = {32'h80000001, 32'h80000002, 32'h80000003, 32'h80000004,
                    32'h80000005, 32'h80000006, 32'h80000007, 32'h80000008,
                    32'h80000009, 32'h8000000A, 32'h8000000B, 32'h8000000C,
                    32'h8000000D, 32'h8000000E, 32'h8000000F, 32'h80000010,
                    32'h80000011, 32'h80000012, 32'h80000013, 32'h80000014,
                    32'h80000015, 32'h80000016, 32'h80000017, 32'h80000018,
                    32'h80000019, 32'h8000001A, 32'h8000001B, 32'h8000001C,
                    32'h8000001D, 32'h8000001E, 32'h8000001F, 32'h80000020};

        // 等待处理完成
        #10;

        // 禁用模块
        en = 0;

        // 等待一段时间以观察状态
        #10;

        // 启用模块并测试复位
        reset = 1;
        #10;
        reset = 0;
        en = 1;

        // 等待一段时间
        #10;

        // 结束仿真
        $finish;
    end

    // 观察输出信号变化
    //initial begin
    //    $monitor("Time: %0t, Output: %h", $time, output_fc);
    //end
  
    // edaplayground仿真https://blog.csdn.net/ResumeProject/article/details/139300170  
    initial begin
    	$dumpfile("dump.vcd"); $dumpvars;
    end


endmodule

仿真

edaplayground

在这里插入图片描述

  • 第一个时钟周期:rest为1,输出为0

  • 第二个时钟周期:rest为0,输入为空,输出为0
    在这里插入图片描述

  • 第三个时钟周期:rest为0,输入为20,输出为20
    在这里插入图片描述

  • 第四个时钟周期:rest为0,输入为负数,输出为0

  • 在这里插入图片描述

digitaljs

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值