当前位置: 首页 > news >正文

一起学习用Verilog在FPGA上实现CNN----(六)SoftMax层设计

1 SoftMax层设计

1.1 softmax

SoftMax函数的作用是输入归一化,计算各种类的概率,即计算0-9数字的概率,SoftMax层的原理图如图所示,输入和输出均为32位宽的10个分类,即32x10=320

在这里插入图片描述

本项目softmax实现逻辑为:

  • 指数计算(通过exponent实现)
  • 计算指数和(通过floatAdd实现)
  • 求指数和倒数(通过floatReciprocal实现)
  • 计算每个元素的softmax值(通过floatMult实现)

1.2 exponent

每个输入分别输入到各自的exponent模块,计算指数,该模块的输入和输出位宽均为32位,输入1个数,计算输出1个指数

在这里插入图片描述

exponent模块展开原理图,如图所示,包含2个乘法器和1个加法器

在这里插入图片描述

1.3 floatAdd

加法器计算所有指数的和

在这里插入图片描述

1.4 floatReciprocal

floatReciprocal模块计算指数和的倒数

在这里插入图片描述

floatReciprocal模块展开原理图,如图所示

在这里插入图片描述

1.5 floatMult

乘法器计算各输入的softmax值,然后输出

在这里插入图片描述

2 代码实现

2.1 floatAdd

2.1.1 设计输入

创建floatAdd文件,操作如图:
在这里插入图片描述

输入文件名:

在这里插入图片描述

双击打开,输入代码:

module floatAdd (floatA,floatB,sum);input [31:0] floatA, floatB;
output reg [31:0] sum;reg sign;
reg [7:0] exponent;
reg [22:0] mantissa;
reg [7:0] exponentA, exponentB;
reg [23:0] fractionA, fractionB, fraction;	//fraction = {1,mantissa}
reg [7:0] shiftAmount;
reg cout;always @ (floatA or floatB) beginexponentA = floatA[30:23];exponentB = floatB[30:23];fractionA = {1'b1,floatA[22:0]};fractionB = {1'b1,floatB[22:0]}; exponent = exponentA;if (floatA == 0) begin						//special case (floatA = 0)sum = floatB;end else if (floatB == 0) begin					//special case (floatB = 0)sum = floatA;end else if (floatA[30:0] == floatB[30:0] && floatA[31]^floatB[31]==1'b1) beginsum=0;end else beginif (exponentB > exponentA) beginshiftAmount = exponentB - exponentA;fractionA = fractionA >> (shiftAmount);exponent = exponentB;end else if (exponentA > exponentB) begin shiftAmount = exponentA - exponentB;fractionB = fractionB >> (shiftAmount);exponent = exponentA;endif (floatA[31] == floatB[31]) begin			//same sign{cout,fraction} = fractionA + fractionB;if (cout == 1'b1) begin{cout,fraction} = {cout,fraction} >> 1;exponent = exponent + 1;endsign = floatA[31];end else begin						//different signsif (floatA[31] == 1'b1) begin{cout,fraction} = fractionB - fractionA;end else begin{cout,fraction} = fractionA - fractionB;endsign = cout;if (cout == 1'b1) beginfraction = -fraction;end else beginendif (fraction [23] == 0) beginif (fraction[22] == 1'b1) beginfraction = fraction << 1;exponent = exponent - 1;end else if (fraction[21] == 1'b1) beginfraction = fraction << 2;exponent = exponent - 2;end else if (fraction[20] == 1'b1) beginfraction = fraction << 3;exponent = exponent - 3;end else if (fraction[19] == 1'b1) beginfraction = fraction << 4;exponent = exponent - 4;end else if (fraction[18] == 1'b1) beginfraction = fraction << 5;exponent = exponent - 5;end else if (fraction[17] == 1'b1) beginfraction = fraction << 6;exponent = exponent - 6;end else if (fraction[16] == 1'b1) beginfraction = fraction << 7;exponent = exponent - 7;end else if (fraction[15] == 1'b1) beginfraction = fraction << 8;exponent = exponent - 8;end else if (fraction[14] == 1'b1) beginfraction = fraction << 9;exponent = exponent - 9;end else if (fraction[13] == 1'b1) beginfraction = fraction << 10;exponent = exponent - 10;end else if (fraction[12] == 1'b1) beginfraction = fraction << 11;exponent = exponent - 11;end else if (fraction[11] == 1'b1) beginfraction = fraction << 12;exponent = exponent - 12;end else if (fraction[10] == 1'b1) beginfraction = fraction << 13;exponent = exponent - 13;end else if (fraction[9] == 1'b1) beginfraction = fraction << 14;exponent = exponent - 14;end else if (fraction[8] == 1'b1) beginfraction = fraction << 15;exponent = exponent - 15;end else if (fraction[7] == 1'b1) beginfraction = fraction << 16;exponent = exponent - 16;end else if (fraction[6] == 1'b1) beginfraction = fraction << 17;exponent = exponent - 17;end else if (fraction[5] == 1'b1) beginfraction = fraction << 18;exponent = exponent - 18;end else if (fraction[4] == 1'b1) beginfraction = fraction << 19;exponent = exponent - 19;end else if (fraction[3] == 1'b1) beginfraction = fraction << 20;exponent = exponent - 20;end else if (fraction[2] == 1'b1) beginfraction = fraction << 21;exponent = exponent - 21;end else if (fraction[1] == 1'b1) beginfraction = fraction << 22;exponent = exponent - 22;end else if (fraction[0] == 1'b1) beginfraction = fraction << 23;exponent = exponent - 23;endendendmantissa = fraction[22:0];sum = {sign,exponent,mantissa};			end		
endendmodule

如图所示:

在这里插入图片描述

2.1.2 分析与综合

将floatAdd设置为顶层:

在这里插入图片描述

对设计进行分析,操作如图:

在这里插入图片描述

分析后的设计,Vivado自动生成原理图,如图:

在这里插入图片描述

对设计进行综合,操作如图:

在这里插入图片描述

综合完成,关闭即可:

在这里插入图片描述

2.1.3 功能仿真

创建仿真激励文件,操作如图:

在这里插入图片描述

输入激励文件名:

在这里插入图片描述

确认创建:

在这里插入图片描述

双击打开,输入激励代码:

`timescale 1ns / 1psmodule tb_floatAdd();
reg [31:0] floatA;
reg [31:0] floatB;
wire [31:0] sum;initial begin// 0.0004125 + 0.000000525#0floatA = 32'hbab1cf4b;floatB = 32'h3aaaad74;// 0.0004125 + 0#10floatA = 32'b00111001110110000100010011010000;floatB = 32'b00000000000000000000000000000000;#10$stop;
endfloatAdd FADD
(.floatA(floatA),.floatB(floatB),.sum(sum)
);endmodule

如图所示:

在这里插入图片描述

将tb_floatAdd设置为顶层:

在这里插入图片描述

开始进行仿真,操作如下:

在这里插入图片描述

仿真波形,如图:

在这里插入图片描述
仿真结束,关闭仿真:

在这里插入图片描述

2.2 floatMult

2.2.1 设计输入

创建floatMult文件,操作如图:

在这里插入图片描述
双击打开,输入代码:

module floatMult (floatA,floatB,product);input [31:0] floatA, floatB;
output reg [31:0] product;reg sign;
reg [7:0] exponent;
reg [22:0] mantissa;
reg [23:0] fractionA, fractionB;	//fraction = {1,mantissa}
reg [47:0] fraction;always @ (floatA or floatB) beginif (floatA == 0 || floatB == 0) beginproduct = 0;end else beginsign = floatA[31] ^ floatB[31];exponent = floatA[30:23] + floatB[30:23] - 8'd127 + 8'd2;fractionA = {1'b1,floatA[22:0]};fractionB = {1'b1,floatB[22:0]};fraction = fractionA * fractionB;if (fraction[47] == 1'b1) beginfraction = fraction << 1;exponent = exponent - 1; end else if (fraction[46] == 1'b1) beginfraction = fraction << 2;exponent = exponent - 2;end else if (fraction[45] == 1'b1) beginfraction = fraction << 3;exponent = exponent - 3;end else if (fraction[44] == 1'b1) beginfraction = fraction << 4;exponent = exponent - 4;end else if (fraction[43] == 1'b1) beginfraction = fraction << 5;exponent = exponent - 5;end else if (fraction[42] == 1'b1) beginfraction = fraction << 6;exponent = exponent - 6;end else if (fraction[41] == 1'b1) beginfraction = fraction << 7;exponent = exponent - 7;end else if (fraction[40] == 1'b1) beginfraction = fraction << 8;exponent = exponent - 8;end else if (fraction[39] == 1'b1) beginfraction = fraction << 9;exponent = exponent - 9;end else if (fraction[38] == 1'b0) beginfraction = fraction << 10;exponent = exponent - 10;end else if (fraction[37] == 1'b1) beginfraction = fraction << 11;exponent = exponent - 11;end else if (fraction[36] == 1'b1) beginfraction = fraction << 12;exponent = exponent - 12;end else if (fraction[35] == 1'b1) beginfraction = fraction << 13;exponent = exponent - 13;end else if (fraction[34] == 1'b1) beginfraction = fraction << 14;exponent = exponent - 14;end else if (fraction[33] == 1'b1) beginfraction = fraction << 15;exponent = exponent - 15;end else if (fraction[32] == 1'b1) beginfraction = fraction << 16;exponent = exponent - 16;end else if (fraction[31] == 1'b1) beginfraction = fraction << 17;exponent = exponent - 17;end else if (fraction[30] == 1'b1) beginfraction = fraction << 18;exponent = exponent - 18;end else if (fraction[29] == 1'b0) beginfraction = fraction << 19;exponent = exponent - 19;end else if (fraction[28] == 1'b1) beginfraction = fraction << 20;exponent = exponent - 20;end else if (fraction[27] == 1'b1) beginfraction = fraction << 21;exponent = exponent - 21;end else if (fraction[26] == 1'b1) beginfraction = fraction << 22;exponent = exponent - 22;end else if (fraction[27] == 1'b1) beginfraction = fraction << 23;exponent = exponent - 23;endmantissa = fraction[47:25];product = {sign,exponent,mantissa};end
endendmodule

如图所示:

在这里插入图片描述

2.2.2 分析与综合

将floatMult设置为顶层:

在这里插入图片描述

关闭上次的分析文件:

在这里插入图片描述

对设计进行分析,操作如图:

在这里插入图片描述

分析后的设计,Vivado自动生成原理图,如图:

在这里插入图片描述

对设计进行综合,综合完成,关闭即可:

在这里插入图片描述

2.2.3 功能仿真

创建激励文件tb_floatMult:

在这里插入图片描述

双击打开,输入激励:

`timescale 1ns / 1psmodule tb_floatMult();
reg [31:0] floatA;
reg [31:0] floatB;
wire [31:0] product;initial begin// 0.0004125 * 0.000000525#0floatA = 32'b00111001110110000100010011010000;floatB = 32'b00110101000011001110110110111010;// 0.0004125 * 0#10floatA = 32'b00111001110110000100010011010000;floatB = 32'b00000000000000000000000000000000;#10$stop;
endfloatMult FM
(.floatA(floatA),.floatB(floatB),.product(product)
);endmodule

如图所示:

在这里插入图片描述

将tb_floatMult设置为顶层:

在这里插入图片描述

开始进行仿真:

在这里插入图片描述

仿真波形如图:

在这里插入图片描述

仿真结束,关闭仿真:

在这里插入图片描述

2.3 exponent

2.3.1 设计输入

创建exponent文件,如图:

在这里插入图片描述

双击打开,输入代码:

module exponent (x,clk,enable,output_exp,ack);
parameter DATA_WIDTH=32;
localparam taylor_iter=7;
input [DATA_WIDTH-1:0] x;
input clk;
input enable;
output reg ack;
output reg [DATA_WIDTH-1:0] output_exp;reg [DATA_WIDTH*taylor_iter-1:0] divisors; // 1/6 1/5 1/4 1/3 1/2 1 1
reg [DATA_WIDTH-1:0] mult1; //is 1 in the first cycle and then the output of the second multiplication in the rest
reg [DATA_WIDTH-1:0] one_or_x; //one in the first cycle and then x for the rest
wire [DATA_WIDTH-1:0] out_m1; //output of the first multiplication which is either with 1 or x
wire [DATA_WIDTH-1:0] out_m2; //the output of the second muliplication and the input of the first
wire [DATA_WIDTH-1:0] output_add1;
reg [DATA_WIDTH-1:0] out_reg; //the output of the Addition each cycle floatMult FM1 (mult1,one_or_x,out_m1); 
floatMult FM2 (out_m1,divisors[31:0],out_m2); 
floatAdd FADD1 (out_m2,out_reg,output_add1); always @ (posedge clk) beginif(enable==1'b0) beginone_or_x=32'b00111111100000000000000000000000; //initially 1mult1=32'b00111111100000000000000000000000; //initially 1out_reg=32'b00000000000000000000000000000000; //initially 0output_exp=32'b00000000000000000000000000000000; //output zero until ack is 1divisors=224'b00111110001010101010101010101011_00111110010011001100110011001101_00111110100000000000000000000000_00111110101010101010101010101011_00111111000000000000000000000000_00111111100000000000000000000000_00111111100000000000000000000000;ack=1'b0; // acknowledge is 0 at the beginningend else beginone_or_x=x;mult1=out_m2; //get the output of the second multiplication to multiply with xdivisors=divisors>>32; //shift 32 bit to divide the out_m1 with the new number to compute the factorialout_reg=output_add1;if(divisors==224'b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) beginoutput_exp=output_add1;ack=1'b1;endend
endendmodule 

如图所示:

在这里插入图片描述

2.3.2 分析与综合

将exponent文件设置为顶层:

在这里插入图片描述

关闭上次的分析文件:

在这里插入图片描述

对本次设计进行分析,操作如图:

在这里插入图片描述

分析后的设计,Vivado自动生成原理图,如图:

在这里插入图片描述
对设计进行综合,操作如图:

在这里插入图片描述

综合完成,关闭即可:

在这里插入图片描述

2.3.3 功能仿真

创建TestBench,操作如图所示:

在这里插入图片描述
双击打开,输入激励代码:

`timescale 1ns / 1psmodule tb_exponent();
localparam DATA_WIDTH=32;
reg [DATA_WIDTH-1:0] x;
reg clk;
reg enable;
wire [DATA_WIDTH-1:0] output_exp;
wire ack; 
exponent #(.DATA_WIDTH(DATA_WIDTH)) exp (.x(x),.clk(clk),.output_exp(output_exp),.ack(ack),.enable(enable));localparam PERIOD = 100;
always #(PERIOD/2) clk = ~clk;initial beginclk=1'b1;x=32'b00111111010101100110110011110100; //0.8376enable=1'b0;#(PERIOD);enable=1'b1;while (ack!=1'b1) begin //7 clock cycles to finish#(PERIOD);end//output is 2.31074953079 and real should be 2.310814361840001 x=32'b10111111011101011100001010001111; //-0.96enable=1'b0;#(PERIOD);enable=1'b1;while (ack!=1'b1) begin //7 clock cycles to finish#(PERIOD);end//output is 0.383025914431 and real should be 0.38289288597511206
endendmodule

如图所示:

在这里插入图片描述

将tb_exponent设置为顶层:

在这里插入图片描述

开始进行仿真,操作如图:

在这里插入图片描述

仿真波形,如图:

在这里插入图片描述

仿真完成,关闭:

在这里插入图片描述

2.4 floatReciprocal

2.4.1 设计输入

创建floatReciprocal文件,如图:

在这里插入图片描述

双击打开,输入代码:

module floatReciprocal(number,enable,clk,output_rec,ack);parameter DATA_WIDTH=32;
input [DATA_WIDTH-1:0] number; //the number that we need to get the 1/number of
input clk,enable; 
output reg[DATA_WIDTH-1:0] output_rec; // = 1/number
output reg ack;wire [DATA_WIDTH-1:0] Ddash; // D' = Mantissa of D and exponent of -1
wire [DATA_WIDTH-1:0] P2Ddash; // (-32/17) * D'
wire [DATA_WIDTH-1:0] Xi ; // X[i]= 43/17 - (32/17)D'
wire [DATA_WIDTH-1:0] Xip1; //X[i+1]
wire [DATA_WIDTH-1:0] out0; // Xi*D
wire [DATA_WIDTH-1:0] out1; // 1-Xi*D
wire [DATA_WIDTH-1:0] out2; // X*(1-Xi*D)
reg  [DATA_WIDTH-1:0] mux;localparam P1=32'b01000000001101001011010010110101; // 43/17
localparam P2=32'b10111111111100001111000011110001; // -32/17assign Ddash={{1'b0,8'b01111110},number[22:0]};floatMult FM1 (P2,Ddash,P2Ddash); // -(32/17)* D'
floatAdd FADD1 (P2Ddash,P1,Xi); // 43/17 * (-32/17)D'
floatMult FM2 (mux,Ddash,out0); // Xi*D'
floatAdd FSUB1 (32'b00111111100000000000000000000000,{1'b1,out0[DATA_WIDTH-2:0]},out1); // 1-Xi*D
floatMult FM3 (mux,out1,out2); // X*(1-Xi*D)
floatAdd FADD2 (mux,out2,Xip1); //Xi+Xi*(1-D*Xi)/*always @(number) begin//when a new input is entered the ack signal is reset and the mux is Xiack=1'b0; //reset finish bitreset=1'b1;
end*/always @ (negedge clk) beginif (enable==1'b0) beginmux=Xi;ack=1'b0;endelse begin if(mux==Xip1) beginack=1'b1; //set ack bit to show that the division is doneoutput_rec={{number[31],8'b11111101-number[30:23]},Xip1[22:0]}; //sign of number, new exponent, mantissa of Xip1end else beginmux=Xip1; //continue until ack is 1endendendendmodule

如图所示:

在这里插入图片描述

2.4.2 分析与综合

将floatReciprocal文件设置为顶层:

在这里插入图片描述

关闭上次的分析文件:

在这里插入图片描述

对设计进行分析,操作如图:

在这里插入图片描述

分析后的设计,Vivado自动生成原理图,如图:

在这里插入图片描述

对设计进行综合,操作如图:

在这里插入图片描述

综合完成,关闭:

在这里插入图片描述

2.4.3 功能仿真

创建tb_floatReciprocal激励文件:

在这里插入图片描述

双击打开,输入激励代码:

`timescale 1ns / 1psmodule tb_floatReciprocal();
localparam DATA_WIDTH=32;
reg [DATA_WIDTH-1:0] num;
reg clk,enable;
wire [DATA_WIDTH-1:0] output_rec;
wire ack;floatReciprocal #(.DATA_WIDTH(DATA_WIDTH))  FA (.number(num),.clk(clk),.output_rec(output_rec),.ack(ack),.enable(enable));localparam PERIOD = 100;always #(PERIOD/2) clk = ~clk;initial beginclk=1'b1; //positive edge firstnum=32'b00111110101100001010001111010111; //0.345enable=1'b0;#(PERIOD);enable=1'b1;while( ack!=1'b1) begin#(PERIOD);end//output is 2.89855074883num=32'b10111110111111101111100111011011;enable=1'b0;#(PERIOD);enable=1'b1; while (ack!=1'b1) begin#(PERIOD);end//output is -2.00803232193$stop;
endendmodule

如图所示:

在这里插入图片描述
将tb_floatReciprocal设置为顶层:

在这里插入图片描述

开始进行仿真,操作如图:

在这里插入图片描述

仿真波形,如图:

在这里插入图片描述

仿真结束,关闭仿真:

在这里插入图片描述

2.5 softmax

2.5.1 设计输入

创建softmax文件,如图:

在这里插入图片描述
双击打开,输入代码:

module softmax(inputs,clk,enable,outputs,ackSoft);
parameter DATA_WIDTH=32;
localparam inputNum=10;
input [DATA_WIDTH*inputNum-1:0] inputs;
input clk;
input enable;
output reg [DATA_WIDTH*inputNum-1:0] outputs;
output reg ackSoft;wire [DATA_WIDTH-1:0] expSum;
wire [DATA_WIDTH-1:0] expReciprocal;
wire [DATA_WIDTH-1:0] outMul;
wire [DATA_WIDTH*inputNum-1:0] exponents ;
wire [inputNum-1:0] acksExp; //acknowledge signals of exponents 
wire ackDiv; //ack signal of the division unitreg enableDiv; //signal to enable division unit initially zero
reg [DATA_WIDTH-1:0] outExpReg;
reg [3:0] mulCounter;
reg [3:0] addCounter;genvar i;
generatefor (i = 0; i < inputNum; i = i + 1) beginexponent #(.DATA_WIDTH(DATA_WIDTH)) exp (.x(inputs[DATA_WIDTH*i+:DATA_WIDTH]),.enable(enable),.clk(clk),.output_exp(exponents[DATA_WIDTH*i+:DATA_WIDTH]),.ack(acksExp[i]));end
endgeneratefloatAdd FADD1 (exponents[DATA_WIDTH*addCounter+:DATA_WIDTH],outExpReg,expSum);
floatReciprocal #(.DATA_WIDTH(DATA_WIDTH)) FR (.number(expSum),.clk(clk),.output_rec(expReciprocal),.ack(ackDiv),.enable(enableDiv));
floatMult FM1 (exponents[DATA_WIDTH*mulCounter+:DATA_WIDTH],expReciprocal,outMul); //multiplication with reciprocalalways @ (negedge clk) beginif(enable==1'b1) beginif(ackSoft==1'b0) begin if(acksExp[0]==1'b1) begin //if the exponents finishedif(enableDiv==1'b0) begin //division still did not startif(addCounter<4'b1001) beginaddCounter=addCounter+1;outExpReg=expSum;endelse beginenableDiv=1'b1;endendelse if(ackDiv==1'b1) begin //check if the reciprocal is readyif(mulCounter<4'b1010) beginoutputs[DATA_WIDTH*mulCounter+:DATA_WIDTH]=outMul;mulCounter=mulCounter+1;endelse beginackSoft=1'b1;endendendendendelse begin//if enable is off reset all counters and acksmulCounter=4'b0000;addCounter=4'b0000;outExpReg=32'b00000000000000000000000000000000;ackSoft=1'b0;enableDiv=1'b0;endendendmodule

如图所示:

在这里插入图片描述

2.5.2 分析与综合

将softmax文件设置为顶层:

在这里插入图片描述

关闭上次的分析,操作如图:

在这里插入图片描述

对设计进行分析,如图:

在这里插入图片描述

分析后的设计,Vivado自动生成原理图,如图:

在这里插入图片描述

对设计进行综合,操作如图:

在这里插入图片描述

2.5.3 功能仿真

创建tb_softmax文件,如图:

在这里插入图片描述
双击打开,输入激励代码:

`timescale 1ns / 1psmodule tb_softmax();
localparam DATA_WIDTH=32;
localparam inputNum=10;
reg [DATA_WIDTH*inputNum-1:0] inputs;
reg clk;
reg enable;
wire [DATA_WIDTH*inputNum-1:0] outputs;
wire ackSoft;
softmax #(.DATA_WIDTH(DATA_WIDTH)) soft(inputs,clk,enable,outputs,ackSoft);localparam PERIOD = 100;
integer count;
always #(PERIOD/2) clk = ~clk;initial beginclk=1'b1;inputs=320'b00111110010011001100110011001101_10111110010011001100110011001101_00111111100110011001100110011010_00111111101001100110011001100110_10111111011001100110011001100110_00111110100110011001100110011010_01000000010001100110011001100110_10111100101000111101011100001010_00111111100011100001010001111011_00111110101001010110000001000010;//inputs are 0.2 -0.2 1.2 1.3 -0.9 0.3 3.1 -0.02 1.11 0.323count=1;enable=1'b0;#(PERIOD);enable=1'b1;while(ackSoft!=1'b1) begincount=count+1;#(PERIOD);		end//outputs are 0.03255, 0.02182, 0.08847, 0.09776, 0.0108, 0.0359, 0.5687,  0.02612, 0.0808, 0.03681inputs=320'b00111111001100001010001111010111_10111110010011001100110011001101_00111111100110011001100110011010_00111111101001100110011001100110_10111111011001100110011001100110_00111110100110011001100110011010_01000000010001100110011001100110_10111100101000111101011100001010_00111111100011100001010001111011_00111110101001010110000001000010;//inputs are 0.69 -0.2 1.2 1.3 -0.9 0.3 3.1 -0.02 1.11 0.323count=1;enable=1'b0;#(PERIOD);enable=1'b1;while(ackSoft!=1'b1) begincount=count+1;#(PERIOD);end//outputs are 0.05207118 0.0213835  0.0866926  0.09579553 0.01062096 0.03525543 0.5572659  0.0256007  0.07923851 0.0360757end
endmodule

如图所示:

在这里插入图片描述

将tb_softmax文件设置为顶层:

在这里插入图片描述

开始进行仿真,如图:

在这里插入图片描述

仿真波形:

在这里插入图片描述

仿真结束,关闭:

在这里插入图片描述

2.6 integrationFC

2.6.1 设计输入

创建integrationFC文件,操作如图:

在这里插入图片描述
双击打开,输入代码:

module integrationFC(clk,reset,iFCinput,CNNoutput);parameter DATA_WIDTH = 32;
parameter IntIn = 120;
parameter FC_1_out = 84;
parameter FC_2_out = 10;input clk, reset;
input [IntIn*DATA_WIDTH-1:0] iFCinput;
output [FC_2_out*DATA_WIDTH-1:0] CNNoutput;wire [FC_1_out*DATA_WIDTH-1:0] fc1Out;
wire [FC_1_out*DATA_WIDTH-1:0] fc1OutTanh;wire [FC_2_out*DATA_WIDTH-1:0] fc2Out;
wire [FC_2_out*DATA_WIDTH-1:0] fc2OutSMax;reg SMaxEnable;
wire DoneFlag;softmax SMax(.inputs(fc2Out),.clk(clk),.enable(SMaxEnable),.outputs(CNNoutput),.ackSoft(DoneFlag));endmodule

如图所示:

在这里插入图片描述

2.6.2 分析与综合

将integrationFC设置为顶层:

在这里插入图片描述

关闭上次的分析文件:

在这里插入图片描述

对设计进行分析,操作如图:

在这里插入图片描述

分析后的设计,Vivado生成原理图:

在这里插入图片描述

希望本文对大家有帮助,上文若有不妥之处,欢迎指正

分享决定高度,学习拉开差距

相关文章:

一起学习用Verilog在FPGA上实现CNN----(六)SoftMax层设计

1 SoftMax层设计 1.1 softmax SoftMax函数的作用是输入归一化&#xff0c;计算各种类的概率&#xff0c;即计算0-9数字的概率&#xff0c;SoftMax层的原理图如图所示&#xff0c;输入和输出均为32位宽的10个分类&#xff0c;即32x10320 本项目softmax实现逻辑为&#xff1a; …...

pixhawk2.4.8-APM固件-MP地面站配置过程记录

目录一、硬件准备二、APM固件、MP地面站下载三、地面站配置1 刷固件2 机架选择3 加速度计校准4 指南针校准5 遥控器校准6 飞行模式7 紧急断电&无头模式8 基础参数设置9 电流计校准10 电调校准11 起飞前检查&#xff08;每一项都非常重要&#xff09;12 飞行经验四、遇到的问…...

【unity细节】关于资源商店(Package Maneger)无法下载资源问题的解决

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 秩沅 原创 收录于专栏&#xff1a;unity细节和bug ⭐关于资源商店为何下载不了的问题⭐ 文章目录⭐关于资源商店为何下载不了的问题…...

[Arxiv 2022] A Novel Plug-in Module for Fine-Grained Visual Classification

Contents MethodPlug-in ModuleLoss functionExperimentsReferencesMethod Plug-in Module Backbone:为了帮助模型抽取出不同尺度的特征,作者在 backbone 里加入了 FPNWeakly Supervised Selector:假设 backbone 的 i i...

RocketMQ Broker消息处理流程及部分源码解析

&#x1f34a; Java学习&#xff1a;Java从入门到精通总结 &#x1f34a; 深入浅出RocketMQ设计思想&#xff1a;深入浅出RocketMQ设计思想 &#x1f34a; 绝对不一样的职场干货&#xff1a;大厂最佳实践经验指南 &#x1f4c6; 最近更新&#xff1a;2023年2月10日 &#x…...

Java面试题:Java集合框架

文章目录一、Java集合框架二、Java集合特性三、各集合类的使用ArrayListLinkedListHashSetHashSet源码解析对源码进行总结HashSet可同步HashSet的使用HashMap四、Iterator迭代器五、遍历集合元素的若干方式参考文章&#xff1a;Hash详解参考文章&#xff1a;深入浅出学Java——…...

时间之间的比较与计算相差年、月、日、小时、分钟、毫秒、纳秒以及判断闰年--LocalDateTime

如何把String/Date转成LocalDateTime参考String、Date与LocalDate、LocalTime、LocalDateTime之间互转 String、Date、LocalDateTime、Calendar与时间戳之间互相转化参考String、Date、LocalDateTime、Calendar与时间戳之间互相转化 比较方法介绍 isBefore(ChronoLocalDateT…...

PyTorch学习笔记:nn.L1Loss——L1损失

PyTorch学习笔记&#xff1a;nn.L1Loss——L1损失 torch.nn.L1Loss(size_averageNone, reduceNone, reductionmean)功能&#xff1a;创建一个绝对值误差损失函数&#xff0c;即L1损失&#xff1a; l(x,y)L{l1,…,lN}T,ln∣xn−yn∣l(x,y)L\{l_1,\dots,l_N\}^T,l_n|x_n-y_n| l(…...

Java程序设计-ssm企业财务管理系统设计与实现

摘要系统设计系统实现开发环境&#xff1a;摘要 对于企业集来说,财务管理的地位很重要。随着计算机和网络在企业中的广泛应用&#xff0c;企业发展速度在不断加快&#xff0c;在这种市场竞争冲击下企业财务管理系统必须优先发展&#xff0c;这样才能保证在竞争中处于优势地位。…...

疑难杂症篇(二十一)--Ubuntu18.04安装usb-cam过程出现的问题

对Ubuntu18.04{\rm Ubuntu 18.04}Ubuntu18.04环境下的ROS{\rm ROS}ROS的melodic{\rm melodic}melodic版本安装usb−cam{\rm usb-cam}usb−cam过程出现的两个常见问题提出解决方案。 1.问题1&#xff1a;usb-cam功能包编译时出现"未定义的引用"的问题 问题描述&#…...

npm-npm i XX --save 和--save-dev

之前使用npm i XX --save 和--save-dev 没太在意&#xff0c;就想记录一下&#xff0c;查到一篇比较全的(链接&#xff1a;NPM install -save 和 -save-dev 傻傻分不清)&#xff0c;直接看好了&#xff0c;哈哈~ # 安装模块到项目目录下 npm install moduleName # -g 的意思是…...

可重构或可调谐微波滤波器技术

电子可重构&#xff0c;或者说电调微波滤波器由于其在改善现在及未来微波系统容量中不断提高的重要性而正吸引着人们越来越多的关注来对其进行研究和开发。例如&#xff0c;崭露头脚的超宽带&#xff08;UWB&#xff09;技术要求使用很宽的无线电频谱。然而&#xff0c;作为资源…...

医院智能化解决方案-门(急)诊、医技、智能化项目解决方案

【版权声明】本资料来源网络&#xff0c;知识分享&#xff0c;仅供个人学习&#xff0c;请勿商用。【侵删致歉】如有侵权请联系小编&#xff0c;将在收到信息后第一时间删除&#xff01;完整资料领取见文末&#xff0c;部分资料内容&#xff1a;篇幅有限&#xff0c;无法完全展…...

判断元素是否在可视区域

前言 在日常开发中&#xff0c;我们经常需要判断目标元素是否在视窗之内或者和视窗的距离小于一个值&#xff08;例如 100 px&#xff09;&#xff0c;从而实现一些常用的功能&#xff0c;例如&#xff1a; 图片的懒加载列表的无限滚动计算广告元素的曝光情况可点击链接的预加…...

告别传统繁杂的采购合同管理 打造企业自动化采购管理模式

随着企业竞争日趋激烈&#xff0c;采购成本压力剧增&#xff0c;企业对于采购合同管理更加严格&#xff0c;从而把控物资成本。对于任何一家企业采购来说&#xff0c;规范化合同的全面管理&#xff0c;是采购活动中重要的一个环节。 但在如今&#xff0c;依旧有很多企业采购合…...

【prism】路由事件映射到Command命令

在之前的一篇文章中&#xff0c;我介绍了普通的自定义事件&#xff1a; 【wpf】自定义事件总结&#xff08;Action&#xff0c; EventHandler&#xff09;_code bean的博客-CSDN博客_wpf action可以说通过Action和EventHandle&#xff0c;自定义事件是相当的方便简单了。https…...

面向对象的基本概念和方法

面向对象的开发方法在近几十年见得以广泛应用&#xff0c;我们常见的Java语言就是一种典型的面向对象的开发语言。然而&#xff0c;面向对象的概念较为复杂&#xff0c;知识点也很细碎&#xff0c;本文整理了面向对象的基本概念和方法&#xff0c;供大家参考。为了便于读者理解…...

数据可视化大屏百度地图绘制行政区域标注实战案例解析(个性化地图、标注、视频、控件、定位、检索)

百度地图开发系列目录 数据可视化大屏应急管理综合指挥调度系统完整案例详解&#xff08;PHP-API、Echarts、百度地图&#xff09;数据可视化大屏百度地图API开发&#xff1a;停车场分布标注和检索静态版百度地图高级开发&#xff1a;map.getDistance计算多点之间的距离并输入…...

1.面向对象和类的关系?2.什么是Promise、3.Promise和async、await的关系

面向对象:面向对象是一种编程思想&#xff08;oop&#xff09;。(Js里面所有的东西都可以看做对象&#xff0c;Js它是基于原型的面向对象语言&#xff0c;采用原型的方式来构造对象)很多个具有相同属性和行为的对象就可以抽象为类&#xff0c;对象是类的一个实例。JavaScript在…...

【程序化天空盒】过程记录01:日月 天空渐变 大气散射

1 日月 SunAndMoon 昼夜的话肯定少不了太阳和月亮&#xff0c;太阳和月亮实现的道理是一样的&#xff0c;只不过是月亮比太阳多了一个需要控制月牙程度&#xff08;or添加贴图&#xff09;的细节~ 1.1 Sun 太阳的话很简单&#xff0c;直接在shader里实现一个太阳跟随平行光旋…...

大话软工笔记—需求分析概述

需求分析&#xff0c;就是要对需求调研收集到的资料信息逐个地进行拆分、研究&#xff0c;从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要&#xff0c;后续设计的依据主要来自于需求分析的成果&#xff0c;包括: 项目的目的…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

Qt Widget类解析与代码注释

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码&#xff0c;写上注释 当然可以&#xff01;这段代码是 Qt …...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

《通信之道——从微积分到 5G》读书总结

第1章 绪 论 1.1 这是一本什么样的书 通信技术&#xff0c;说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号&#xff08;调制&#xff09; 把信息从信号中抽取出来&am…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

Python如何给视频添加音频和字幕

在Python中&#xff0c;给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加&#xff0c;包括必要的代码示例和详细解释。 环境准备 在开始之前&#xff0c;需要安装以下Python库&#xff1a;…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...