- 代码实现对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_NODESoutput 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// 对应的输出数据设置为 0output_fc[DATA_WIDTH*i +: DATA_WIDTH] = 0;end else begin// 否则,将输入数据直接赋值给输出数据output_fc[DATA_WIDTH*i +: DATA_WIDTH] = input_fc[DATA_WIDTH*i +: DATA_WIDTH];endendendendendendmodule
TestBench
// Code your testbench here
// or browse Examples
`timescale 1ns / 1psmodule 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 beginclk = 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;endendmodule
仿真
edaplayground
-
第一个时钟周期:rest为1,输出为0
-
第二个时钟周期:rest为0,输入为空,输出为0
-
第三个时钟周期:rest为0,输入为20,输出为20
-
第四个时钟周期:rest为0,输入为负数,输出为0