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

news2024/11/27 6:16:18

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) begin
	exponentA = 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) begin
		sum=0;
	end else begin
		if (exponentB > exponentA) begin
			shiftAmount = exponentB - exponentA;
			fractionA = fractionA >> (shiftAmount);
			exponent = exponentB;
		end else if (exponentA > exponentB) begin 
			shiftAmount = exponentA - exponentB;
			fractionB = fractionB >> (shiftAmount);
			exponent = exponentA;
		end
		if (floatA[31] == floatB[31]) begin			//same sign
			{cout,fraction} = fractionA + fractionB;
			if (cout == 1'b1) begin
				{cout,fraction} = {cout,fraction} >> 1;
				exponent = exponent + 1;
			end
			sign = floatA[31];
		end else begin						//different signs
			if (floatA[31] == 1'b1) begin
				{cout,fraction} = fractionB - fractionA;
			end else begin
				{cout,fraction} = fractionA - fractionB;
			end
			sign = cout;
			if (cout == 1'b1) begin
				fraction = -fraction;
			end else begin
			end
			if (fraction [23] == 0) begin
				if (fraction[22] == 1'b1) begin
					fraction = fraction << 1;
					exponent = exponent - 1;
				end else if (fraction[21] == 1'b1) begin
					fraction = fraction << 2;
					exponent = exponent - 2;
				end else if (fraction[20] == 1'b1) begin
					fraction = fraction << 3;
					exponent = exponent - 3;
				end else if (fraction[19] == 1'b1) begin
					fraction = fraction << 4;
					exponent = exponent - 4;
				end else if (fraction[18] == 1'b1) begin
					fraction = fraction << 5;
					exponent = exponent - 5;
				end else if (fraction[17] == 1'b1) begin
					fraction = fraction << 6;
					exponent = exponent - 6;
				end else if (fraction[16] == 1'b1) begin
					fraction = fraction << 7;
					exponent = exponent - 7;
				end else if (fraction[15] == 1'b1) begin
					fraction = fraction << 8;
					exponent = exponent - 8;
				end else if (fraction[14] == 1'b1) begin
					fraction = fraction << 9;
					exponent = exponent - 9;
				end else if (fraction[13] == 1'b1) begin
					fraction = fraction << 10;
					exponent = exponent - 10;
				end else if (fraction[12] == 1'b1) begin
					fraction = fraction << 11;
					exponent = exponent - 11;
				end else if (fraction[11] == 1'b1) begin
					fraction = fraction << 12;
					exponent = exponent - 12;
				end else if (fraction[10] == 1'b1) begin
					fraction = fraction << 13;
					exponent = exponent - 13;
				end else if (fraction[9] == 1'b1) begin
					fraction = fraction << 14;
					exponent = exponent - 14;
				end else if (fraction[8] == 1'b1) begin
					fraction = fraction << 15;
					exponent = exponent - 15;
				end else if (fraction[7] == 1'b1) begin
					fraction = fraction << 16;
					exponent = exponent - 16;
				end else if (fraction[6] == 1'b1) begin
					fraction = fraction << 17;
					exponent = exponent - 17;
				end else if (fraction[5] == 1'b1) begin
					fraction = fraction << 18;
					exponent = exponent - 18;
				end else if (fraction[4] == 1'b1) begin
					fraction = fraction << 19;
					exponent = exponent - 19;
				end else if (fraction[3] == 1'b1) begin
					fraction = fraction << 20;
					exponent = exponent - 20;
				end else if (fraction[2] == 1'b1) begin
					fraction = fraction << 21;
					exponent = exponent - 21;
				end else if (fraction[1] == 1'b1) begin
					fraction = fraction << 22;
					exponent = exponent - 22;
				end else if (fraction[0] == 1'b1) begin
					fraction = fraction << 23;
					exponent = exponent - 23;
				end
			end
		end
		mantissa = fraction[22:0];
		sum = {sign,exponent,mantissa};			
	end		
end

endmodule

如图所示:

在这里插入图片描述

2.1.2 分析与综合

将floatAdd设置为顶层:

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

综合完成,关闭即可:

在这里插入图片描述

2.1.3 功能仿真

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

在这里插入图片描述

输入激励文件名:

在这里插入图片描述

确认创建:

在这里插入图片描述

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

`timescale 1ns / 1ps

module tb_floatAdd();
reg [31:0] floatA;
reg [31:0] floatB;
wire [31:0] sum;

initial begin
	
	// 0.0004125 + 0.000000525
	#0
	floatA = 32'hbab1cf4b;
	floatB = 32'h3aaaad74;

	// 0.0004125 + 0
	#10
	floatA = 32'b00111001110110000100010011010000;
	floatB = 32'b00000000000000000000000000000000;

	#10
	$stop;
end

floatAdd 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) begin
	if (floatA == 0 || floatB == 0) begin
		product = 0;
	end else begin
		sign = 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) begin
			fraction = fraction << 1;
			exponent = exponent - 1; 
		end else if (fraction[46] == 1'b1) begin
			fraction = fraction << 2;
			exponent = exponent - 2;
		end else if (fraction[45] == 1'b1) begin
			fraction = fraction << 3;
			exponent = exponent - 3;
		end else if (fraction[44] == 1'b1) begin
			fraction = fraction << 4;
			exponent = exponent - 4;
		end else if (fraction[43] == 1'b1) begin
			fraction = fraction << 5;
			exponent = exponent - 5;
		end else if (fraction[42] == 1'b1) begin
			fraction = fraction << 6;
			exponent = exponent - 6;
		end else if (fraction[41] == 1'b1) begin
			fraction = fraction << 7;
			exponent = exponent - 7;
		end else if (fraction[40] == 1'b1) begin
			fraction = fraction << 8;
			exponent = exponent - 8;
		end else if (fraction[39] == 1'b1) begin
			fraction = fraction << 9;
			exponent = exponent - 9;
		end else if (fraction[38] == 1'b0) begin
			fraction = fraction << 10;
			exponent = exponent - 10;
		end else if (fraction[37] == 1'b1) begin
			fraction = fraction << 11;
			exponent = exponent - 11;
		end else if (fraction[36] == 1'b1) begin
			fraction = fraction << 12;
			exponent = exponent - 12;
		end else if (fraction[35] == 1'b1) begin
			fraction = fraction << 13;
			exponent = exponent - 13;
		end else if (fraction[34] == 1'b1) begin
			fraction = fraction << 14;
			exponent = exponent - 14;
		end else if (fraction[33] == 1'b1) begin
			fraction = fraction << 15;
			exponent = exponent - 15;
		end else if (fraction[32] == 1'b1) begin
			fraction = fraction << 16;
			exponent = exponent - 16;
		end else if (fraction[31] == 1'b1) begin
			fraction = fraction << 17;
			exponent = exponent - 17;
		end else if (fraction[30] == 1'b1) begin
			fraction = fraction << 18;
			exponent = exponent - 18;
		end else if (fraction[29] == 1'b0) begin
			fraction = fraction << 19;
			exponent = exponent - 19;
		end else if (fraction[28] == 1'b1) begin
			fraction = fraction << 20;
			exponent = exponent - 20;
		end else if (fraction[27] == 1'b1) begin
			fraction = fraction << 21;
			exponent = exponent - 21;
		end else if (fraction[26] == 1'b1) begin
			fraction = fraction << 22;
			exponent = exponent - 22;
		end else if (fraction[27] == 1'b1) begin
			fraction = fraction << 23;
			exponent = exponent - 23;
		end
	
		mantissa = fraction[47:25];
		product = {sign,exponent,mantissa};
	end
end

endmodule

如图所示:

在这里插入图片描述

2.2.2 分析与综合

将floatMult设置为顶层:

在这里插入图片描述

关闭上次的分析文件:

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

2.2.3 功能仿真

创建激励文件tb_floatMult:

在这里插入图片描述

双击打开,输入激励:

`timescale 1ns / 1ps

module tb_floatMult();
reg [31:0] floatA;
reg [31:0] floatB;
wire [31:0] product;

initial begin
	
	// 0.0004125 * 0.000000525
	#0
	floatA = 32'b00111001110110000100010011010000;
	floatB = 32'b00110101000011001110110110111010;

	// 0.0004125 * 0
	#10
	floatA = 32'b00111001110110000100010011010000;
	floatB = 32'b00000000000000000000000000000000;

	#10
	$stop;
end

floatMult 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) begin
    if(enable==1'b0) begin
        one_or_x=32'b00111111100000000000000000000000; //initially 1
        mult1=32'b00111111100000000000000000000000; //initially 1
        out_reg=32'b00000000000000000000000000000000; //initially 0
        output_exp=32'b00000000000000000000000000000000; //output zero until ack is 1
        divisors=224'b00111110001010101010101010101011_00111110010011001100110011001101_00111110100000000000000000000000_00111110101010101010101010101011_00111111000000000000000000000000_00111111100000000000000000000000_00111111100000000000000000000000;
        ack=1'b0; // acknowledge is 0 at the beginning
    end 
    else begin
	   one_or_x=x;
	   mult1=out_m2; //get the output of the second multiplication to multiply with x
	   divisors=divisors>>32; //shift 32 bit to divide the out_m1 with the new number to compute the factorial
	   out_reg=output_add1;
	   if(divisors==224'b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) 
	   begin
		  output_exp=output_add1;
		  ack=1'b1;
	   end
	  end
end

endmodule 

如图所示:

在这里插入图片描述

2.3.2 分析与综合

将exponent文件设置为顶层:

在这里插入图片描述

关闭上次的分析文件:

在这里插入图片描述

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

在这里插入图片描述

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

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

在这里插入图片描述

综合完成,关闭即可:

在这里插入图片描述

2.3.3 功能仿真

创建TestBench,操作如图所示:

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

`timescale 1ns / 1ps

module 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 begin
	clk=1'b1;
	x=32'b00111111010101100110110011110100; //0.8376
	enable=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.96
	enable=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
end

endmodule

如图所示:

在这里插入图片描述

将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/17

assign 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 Xi
	ack=1'b0; //reset finish bit
	reset=1'b1;
end*/


always @ (negedge clk) begin
	if (enable==1'b0) begin
		mux=Xi;
		ack=1'b0;
	end
	else begin 
		if(mux==Xip1) begin
			ack=1'b1; //set ack bit to show that the division is done
			output_rec={{number[31],8'b11111101-number[30:23]},Xip1[22:0]}; //sign of number, new exponent, mantissa of Xip1
		end 
		else begin
			mux=Xip1; //continue until ack is 1
		end
	end
	
end

endmodule

如图所示:

在这里插入图片描述

2.4.2 分析与综合

将floatReciprocal文件设置为顶层:

在这里插入图片描述

关闭上次的分析文件:

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

综合完成,关闭:

在这里插入图片描述

2.4.3 功能仿真

创建tb_floatReciprocal激励文件:

在这里插入图片描述

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

`timescale 1ns / 1ps

module 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 begin
	clk=1'b1; //positive edge first
	num=32'b00111110101100001010001111010111; //0.345
	enable=1'b0;
	#(PERIOD);
	enable=1'b1;
	while( ack!=1'b1) begin
		#(PERIOD);
	end
	//output is 2.89855074883
	num=32'b10111110111111101111100111011011;
	enable=1'b0;
	#(PERIOD);
	enable=1'b1; 
	while (ack!=1'b1) begin
		#(PERIOD);
	end
	//output is -2.00803232193
	$stop;
end

endmodule

如图所示:

在这里插入图片描述
将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 unit

reg enableDiv; //signal to enable division unit initially zero
reg [DATA_WIDTH-1:0] outExpReg;
reg [3:0] mulCounter;
reg [3:0] addCounter;

genvar i;
generate
	for (i = 0; i < inputNum; i = i + 1) begin
		exponent #(.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
endgenerate

floatAdd 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 reciprocal

always @ (negedge clk) begin
	if(enable==1'b1) begin
		if(ackSoft==1'b0) begin 
			if(acksExp[0]==1'b1) begin //if the exponents finished
				if(enableDiv==1'b0) begin //division still did not start
					if(addCounter<4'b1001) begin
						addCounter=addCounter+1;
						outExpReg=expSum;
					end
					else begin
						enableDiv=1'b1;
					end
				end
				else if(ackDiv==1'b1) begin //check if the reciprocal is ready
					if(mulCounter<4'b1010) begin
						outputs[DATA_WIDTH*mulCounter+:DATA_WIDTH]=outMul;
						mulCounter=mulCounter+1;
					end
					else begin
						ackSoft=1'b1;
					end
				end
			end
		end
	end
	else begin
		//if enable is off reset all counters and acks
		mulCounter=4'b0000;
		addCounter=4'b0000;
		outExpReg=32'b00000000000000000000000000000000;
		ackSoft=1'b0;
		enableDiv=1'b0;
	end
	
end

endmodule

如图所示:

在这里插入图片描述

2.5.2 分析与综合

将softmax文件设置为顶层:

在这里插入图片描述

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

在这里插入图片描述

对设计进行分析,如图:

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

2.5.3 功能仿真

创建tb_softmax文件,如图:

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

`timescale 1ns / 1ps

module 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 begin
	clk=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.323
	count=1;
	enable=1'b0;
	#(PERIOD);
	enable=1'b1;
	
	while(ackSoft!=1'b1) begin
		count=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.03681

	inputs=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.323
	count=1;
	enable=1'b0;
	#(PERIOD);
	enable=1'b1;
	while(ackSoft!=1'b1) begin
		count=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.0360757
 										
end
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生成原理图:

在这里插入图片描述

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/336069.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机操作系统 左万利 第二章课后习题答案

计算机操作系统 左万利 第二章课后习题答案 1、为何引进多道程序设计&#xff0c;在多道程序设计中&#xff0c;内存中作业的道数是否越多越好&#xff1f;说明原因。 引入多道程序设计技术是为了提高计算机系统资源的利用率。在多道程序系统中&#xff0c;内存中作业的道数并…

Windows 搭建ARM虚拟机 UOS系统

搭建环境安装虚拟机下载虚拟机QEMU&#xff0c;https://www.qemu.org/download/&#xff0c;目前最新版本是7.2.0。安装完成后&#xff0c;需要将qemu的安装路径设置到环境变量完成后运行cmd&#xff0c;测试环境变量配置完成。qemu-system-aarch64 --version如上截图所示&…

【QT】QHostInfo 和 QNetworkInterface 的使用

目录1. Qt网络模块2. QHostInfo2.1 公共函数2.2 静态函数3. QNetworkInterface3.1 公共函数3.2 静态函数4. 代码示例Dialog.hDialog.cpp界面展示1. Qt网络模块 使用Qt网络模块&#xff0c;需要在配置文件.pro中添加&#xff1a; Qt network2. QHostInfo 2.1 公共函数 QLis…

10分钟学会Jmeter接口测试

一提到接口测试&#xff0c;通常大家会有这样的疑问&#xff1a;前端测试不是已经覆盖到各种业务逻辑了吗&#xff1f;为什么还要做接口测试&#xff0c;接口测试和前端测试是不是重复了&#xff1f;对于这个问题&#xff0c;可以从下面几个方面来解释&#xff1a; 什么是接口…

OpenMMLab AI实战营 第6课 语义分割与MMSegmentation

第6课 语义分割与MMSegmentation 1. 语义分割简介 任务&#xff1a;将图像按照物体的类别分割成不同的区域&#xff0c;等价于对每个像素进行分类应用 无人驾驶人像分割智能遥感医疗影像分析 语义分割 vs 实例分割 vs 全景分割 语义分割&#xff1a;仅考虑像素的类别&#xf…

如何利用火遍全球的ChatGPT搞钱?

火遍全球的ChatGPT想必大家都知道了。已经有人借助它赚到了2023年的第一桶金&#xff0c;连比尔盖茨都称赞ChatGPT不亚于互联网的诞生。还有人借助Chagpt通过了Google面试&#xff0c;拿到了年薪18万美元的工程师offer。要明白&#xff0c;年薪百万的谷歌程序员&#xff0c;对于…

百度富文本UE的问题集合

百度富文本编辑能上传视频成功但是在浏览器不能播放、显示的问题百度富文本视频封面空白问题百度富文本编辑器UMEditor 添加视频无法删除百度富文本编辑器结果存数据库取出来到js赋值报错怎么让浏览器重新加载修改过的JS文件&#xff0c;而不是沿用缓存里的百度富文本编辑能上传…

智慧物流管理系统

智慧物流运用物联网、大数据、云计算、人工智能等技术优化物流决策过程。智慧物流获取、分析物流信息并做出决策&#xff0c;从商品源开始实时跟踪与管理&#xff0c;保证信息流快于商品流&#xff0c;实现信息与物质快速、高效、流畅地运转&#xff0c;集自动化、数字化、网络…

浏览器如何使用HTTP防止ip限制

当我们浏览网页尤其是频发刷新网页时&#xff0c;会跳出来验证码。主要因为频繁刷新导致目标网页限制了您本地ip&#xff0c;正常过一段时间也或许恢复&#xff0c;如果遇到紧急的事情急需访问&#xff0c;不妨试试下面的操作。不管是网页还是电脑游戏都可以通过改变地址实现防…

Linux内核移植(源码分析、配置与编译)

目录 一、Linux内核概述 1.1内核与操作系统 ​编辑1.2Linux层次结构 1.3Linux内核特点 二、Linux内核源码结构 2.1Linux内核源码获取 2.2Linux内核源码结构 三、Linux内核源码的配置和编译 3.1Linux内核源码配置 3.2make menuconfig 3.3内核编译&#xff08;以下命令…

Java学习记录day6

书接上回 类与对象 static关键字 static的作用&#xff1a; 修饰一个属性&#xff1a;声明为static的变量实质上就是一个全局变量,其生命周期为从类被加载开始一直到程序结束&#xff1b;修饰方法&#xff1a;无须本类的对象也可以调用该方法&#xff1b;修饰一个类&#x…

Yii中render和renderPartial的区别

一、Yii项目来源二、配置yiisoft/yii2-app-basic&#xff0c;写个Demo1、默认的首页2、自定义Demo的html内容3、php渲染代码1&#xff09;、render() 渲染2&#xff09;、renderPartial() 渲染三、给出结论一、Yii项目来源 直接composer安装&#xff1a;composer create-proje…

注意力机制(SE,ECA,CBAM) Pytorch代码

注意力机制1 SENet2 ECANet3 CBAM3.1 通道注意力3.2 空间注意力3.3 CBAM4 展示网络层具体信息1 SENet SE注意力机制&#xff08;Squeeze-and-Excitation Networks&#xff09;:是一种通道类型的注意力机制&#xff0c;就是在通道维度上增加注意力机制&#xff0c;主要内容是是…

【光线追踪】光线追踪重投影方法(Ray Tracing Reprojection)

光线追踪重投影方法 重投影这项技术一般用于时间性帧复用技术上&#xff0c;例如TAA(Temporal Anti-Aliasing)反走样或者抗锯齿技术。读这篇文章最好先对TAA这类技术的算法流程有了解。 1.TAA抗锯齿技术简介 先简单介绍下TAA抗锯齿的原理&#xff0c;在游戏中&#xff0c;当前…

解决ThinkPHP5.1出现MISS缓存未命中问题

一淘模板&#xff08;56admin.com&#xff09;给大家带来了关于ThinkPHP5.1的相关知识&#xff0c;其中主要介绍了CDN是什么&#xff1f;为什么使用它&#xff1f;怎么解决ThinkPHP5.1 MISS缓存未命中问题&#xff1f;感兴趣的朋友下面一起来看一下吧&#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功能包编译时出现"未定义的引用"的问题 问题描述&#…

@RefreshScope 加在 Quartz 触发器类导致异常问题分析

背景 承接上篇&#xff0c;测试过程中又遇到了 Nacos Config 的动态刷新注解 RefreshScope 与 Quartz 框架结合的问题&#xff0c;Bug 排查路上&#xff0c;顺手记录一下吧。 问题 有个模块使用了Quartz &#xff0c;通过配置控制任务调度的周期和分组名称。 因为引用了动态…

如何解决thinkphp验证码不能显示问题?

thinkPHP做验证码这一块,可以使用自带的验证码扩展,具体步骤如下: 一、安装扩展 composer require topthink/think-captcha 二、模版中使用 将原来静态页面的验证码图片替换为{:captcha_img()},这个会自动生成验证码图片。 <div>{:captcha_img()}</div> 或者 &…

如何理解 K8s 动态伸缩与触发上线?

K8s 版本&#xff1a;1.23.6 目录一、动态伸缩二、触发上线一般地&#xff0c;如果仅修改 Pod 的副本数&#xff08;如新增/缩减&#xff09;&#xff0c;这就属于动态伸缩。如果是修改容器镜像的版本&#xff0c;则会触发上线&#xff0c;具体看下面例子。 一、动态伸缩 1、…

00后整顿职场?公司测试岗却新来了个00后卷王,3个月薪资干到20K...

最近聊到软件测试的行业内卷&#xff0c;越来越多的转行和大学生进入测试行业。想要获得更好的待遇和机会&#xff0c;不断提升自己的技能栈成了测试老人迫在眉睫的问题。 不论是面试哪个级别的测试工程师&#xff0c;面试官都会问一句“会编程吗&#xff1f;有没有自动化测试…