【IC设计】基于Verilog的8层矩阵乘法设计

news2024/11/25 0:41:35

文章目录

    • 项目要求
      • 基本要求
      • 截断要求
        • 低位截断
        • 高位饱和
      • 参考结果
    • 项目实现
      • 实现思路
      • 实现代码
        • matrix_multiplier_16.v
        • tb_mm_mlp.v
    • VCS&Verdi综合前仿真
    • dc综合
    • VCS&Verdi综合后仿真
    • 不足之处

项目要求

基本要求

输入有9个矩阵,权重矩阵有8个,分别是Weight I0~I7,Input矩阵I -1
8个矩阵都是都是16行*16列的,且矩阵中的每个元素是16位补码形式的有符号定点数(1位符号位,6位整数位,9位小数位)
在这里插入图片描述
要求将Weight I0依次乘以Input I-1 ,Weight I1 ,Weight I2 ,Weight I3 ,Weight I4, Weight I5, Weight I6 , Weight I7,依次得到Input I0 ,Input I1 ,Input I2 ,Input I3 ,Input I4 ,Input I5 ,Input I6 ,Input I7
最终输出Input I7

截断要求

对于矩阵AB=C,C矩阵的第i行第j列元素是A的第i行和B的第j列进行乘加运算得到的,
由于矩阵的元素是16位,两个16位元素相乘结果需要用2
16-1=31位表示,再考虑相加,因此需要31+4=35位来表示。
在这个项目中不考虑相加后会超过31位的情况,只用31位表示。
对于Weight I0 * Input I-1=Input I0,Input I0中的每个元素都是31位的,有1位符号位,18位小数,12位整数,要求截断为16位再作为下一层的输入。
在这里插入图片描述
A[15:0]*B[15:0]=C_31[30:0] 要将C_31[30:0]转为C_16[15:0]需要考虑低位截断高位饱和操作:

低位截断

低位C_31[8:0]截断,要考虑C_31[8]的四舍五入,
如果符号位为0,则向前进1,
如果符号位为1,直接截断。
这个操作的正确性证明如下:
在这里插入图片描述

高位饱和

C[15:9]能表示的范围在[-64:63],如果C_31[30:24]超过该范围,产生上/下溢,C_16[14:9]则取能表示的最大/最小值
如果符号位为0,C_31[29:24]存在1则上溢,
如果符号位为1,C_31[29:24]存在0则下溢。

参考结果

这里给出第一层和最后一层(第八层)的输出作为参考,需要注意的是矩阵AB和BA结果是不同的,这里第一层的结果是Weight I0在左边乘以Input -1 ,得到的Input 0
在这里插入图片描述
在这里插入图片描述

项目实现

实现思路

如图所示,其中标记绿色的是调用$readmemh从文件中直接读取的,项目实现思路如下:

  1. 首先,使用$readmemh从文件中读取
    Weight I0,Input I-1 ,Weight I1 ,Weight I2 ,Weight I3 ,Weight I4, Weight I5, Weight I6 , Weight I7
    存储到对应的二维数组中,然后将这些二维数组转为一维数组(因为Verilog模块的端口不能使用多维数组)。

  2. 接着,实例化第一个16*16的模块matrix_multiplier_16,输入I_16_1d和W0_2d,得到相乘的结果I0_31_1d,将其转为二维矩阵I0_31_2d,然后按照截断要求转为I0_16_2d

  3. 下面,反复实例化matrix_multiplier_16,每次将上一层计算结果和对应的Weight矩阵作为输入,得到相乘的结果,最终结果是第八层的输出I7_16_2d。

在这里插入图片描述

实现代码

matrix_multiplier_16.v

`timescale 1ns / 1ps
//输入端口A矩阵,B矩阵是16行16列,每个元素16位有符号定点数(1位符号位,6位整数位,9位小数位)
//输出端口Result矩阵是A*B的结果,是16行16列,每个元素是31位有符号定点数(1位符号位,12位整数位,18位小数位)
//Verilog模块的端口只能是一维数组,所以每次调用该模块要保证输入的矩阵已经被转化成了一维长数组
module matrix_multiplier_16(A,B,Result);
       input  [16*16*16-1:0] A;
       input  [16*16*16-1:0] B;
       output   [16*16*31-1:0] Result;
       
       reg  [16*16*31-1:0] reg_result;
       reg signed [15:0] A1[0:15][0:15];
       reg signed [15:0] B1[0:15][0:15];
       reg signed [30:0] Res1[0:15][0:15];

       integer i,j,k;
       
       always@(A or B) begin
         //在模块内将一维转二维,方便计算
         for(i=0;i<16;i=i+1) begin
             for(j=0;j<16;j=j+1) begin
                 A1[i][j]=A[i*16*16+j*16+:16];
                 B1[i][j]=B[i*16*16+j*16+:16];
             end
         end
         
         //初始化结果为0
         for(i=0;i<16;i=i+1) begin
             for(j=0;j<16;j=j+1) begin
                 Res1[i][j]=31'd0;
             end
         end
         
         //使用矩阵相乘的定义计算Res1矩阵的结果
         //Res1[i][j]是A的第i行和B的第j列相乘再相加的结果
         for(i=0;i<16;i=i+1)begin
    		 for(j=0;j<16;j=j+1)begin
	   		   for(k=0;k<16;k=k+1)begin
	   		        //A1[i][k]和B1[k][j]都是补码形式的有符号定点数
	   		        //A[补码]*B[补码]=(A*B)[补码] 
	   		        Res1[i][j]=Res1[i][j]+A1[i][k]*B1[k][j];
			   end
			 end
		 end
		 
		 //将二维转回一维,将Res1[0][0]存储在reg_result的最高位,Res[i][j]前面有i*16+j个数据,每个31位,因此转为1维的索引是
		 //16*16*31-1-(i*16+j)*31
		 //这里涉及到一个语法:A[7:3]和A[7-:4]是等价的 同理A[0+:3]和A[0:2]等价
		 for(i=0;i<16;i=i+1)begin
		     for(j=0;j<16;j=j+1)begin
		         //When 2d converted to 1d,it is stored from high bit to low bit.
		         reg_result[16*16*31-1-((i*16+j)*31) -: 31]=Res1[i][j];
		     end
		 end
		 
       end
       assign Result=reg_result;
      
endmodule

tb_mm_mlp.v

命名为tb_mm_mlp是因为mm是matrix multiplier,mlp是多层感知机,深度学习中多层感知机的计算实际上就是矩阵乘法加激活函数。

`timescale 1ns/1ps
`define FILE_INPUT 1
`define PRINT_A_B_OUTPUT 1

module tb_mm_mlp();

       reg signed [15:0] I_16_2d[0:15][0:15]; 
       reg [16*16*16-1:0] I_16_1d;
       
       reg signed [15:0] I0_16_2d[0:15][0:15];
       reg signed [15:0] I1_16_2d[0:15][0:15];
       reg signed [15:0] I2_16_2d[0:15][0:15];
       reg signed [15:0] I3_16_2d[0:15][0:15];
       reg signed [15:0] I4_16_2d[0:15][0:15];
       reg signed [15:0] I5_16_2d[0:15][0:15];
       reg signed [15:0] I6_16_2d[0:15][0:15];
       reg signed [15:0] I7_16_2d[0:15][0:15];
       
       reg [16*16*16-1:0] I0_16_1d;
       reg [16*16*16-1:0] I1_16_1d;
       reg [16*16*16-1:0] I2_16_1d;
       reg [16*16*16-1:0] I3_16_1d;
       reg [16*16*16-1:0] I4_16_1d;
       reg [16*16*16-1:0] I5_16_1d;
       reg [16*16*16-1:0] I6_16_1d;
       reg [16*16*16-1:0] I7_16_1d;
       
       reg signed [15:0] W0_2d[0:15][0:15];
       reg signed [15:0] W1_2d[0:15][0:15]; 
       reg signed [15:0] W2_2d[0:15][0:15]; 
       reg signed [15:0] W3_2d[0:15][0:15]; 
       reg signed [15:0] W4_2d[0:15][0:15]; 
       reg signed [15:0] W5_2d[0:15][0:15]; 
       reg signed [15:0] W6_2d[0:15][0:15];   
       reg signed [15:0] W7_2d[0:15][0:15];
       reg [16*16*16-1:0] W0_1d;
       reg [16*16*16-1:0] W1_1d;
       reg [16*16*16-1:0] W2_1d;
       reg [16*16*16-1:0] W3_1d;
       reg [16*16*16-1:0] W4_1d;
       reg [16*16*16-1:0] W5_1d;
       reg [16*16*16-1:0] W6_1d;
       reg [16*16*16-1:0] W7_1d;
               
       reg signed [30:0] I0_31_2d[0:15][0:15];
       reg signed [30:0] I1_31_2d[0:15][0:15];
       reg signed [30:0] I2_31_2d[0:15][0:15];
       reg signed [30:0] I3_31_2d[0:15][0:15];
       reg signed [30:0] I4_31_2d[0:15][0:15];
       reg signed [30:0] I5_31_2d[0:15][0:15];
       reg signed [30:0] I6_31_2d[0:15][0:15];
       reg signed [30:0] I7_31_2d[0:15][0:15];

       wire [31*16*16-1:0] I0_31_1d;
       wire [31*16*16-1:0] I1_31_1d;
       wire [31*16*16-1:0] I2_31_1d;
       wire [31*16*16-1:0] I3_31_1d;
       wire [31*16*16-1:0] I4_31_1d;
       wire [31*16*16-1:0] I5_31_1d;
       wire [31*16*16-1:0] I6_31_1d;
       wire [31*16*16-1:0] I7_31_1d;
       
       integer i,j,k;
       
       matrix_multiplier_16 DUT1(.A(W0_1d), .B(I_16_1d), .Result(I0_31_1d));
       matrix_multiplier_16 DUT2(.A(W1_1d), .B(I0_16_1d), .Result(I1_31_1d));
       matrix_multiplier_16 DUT3(.A(W2_1d), .B(I1_16_1d), .Result(I2_31_1d));
       matrix_multiplier_16 DUT4(.A(W3_1d), .B(I2_16_1d), .Result(I3_31_1d));
       matrix_multiplier_16 DUT5(.A(W4_1d), .B(I3_16_1d), .Result(I4_31_1d));
       matrix_multiplier_16 DUT6(.A(W5_1d), .B(I4_16_1d), .Result(I5_31_1d));
       matrix_multiplier_16 DUT7(.A(W6_1d), .B(I5_16_1d), .Result(I6_31_1d));
       matrix_multiplier_16 DUT8(.A(W7_1d), .B(I6_16_1d), .Result(I7_31_1d));
       initial begin
         $display("Start read mem I-1,W0,W1...W7");
         $fsdbDumpfile("mm_mlp.fsdb");
         $fsdbDumpMDA();
         $readmemb("I.mem",I_16_2d);
         $readmemb("W0.mem",W0_2d);
         $readmemb("W1.mem",W1_2d);
         $readmemb("W2.mem",W2_2d);
         $readmemb("W3.mem",W3_2d);
         $readmemb("W4.mem",W4_2d);
         $readmemb("W5.mem",W5_2d);
         $readmemb("W6.mem",W6_2d);
         $readmemb("W7.mem",W7_2d);         

         //2d to 1d
         for(i=0;i<16;i=i+1) begin
             for(j=0;j<16;j=j+1) begin
                 I_16_1d[i*16*16+j*16+:16]=I_16_2d[i][j];
                 W0_1d[i*16*16+j*16+:16]=W0_2d[i][j];
                 W1_1d[i*16*16+j*16+:16]=W1_2d[i][j];
                 W2_1d[i*16*16+j*16+:16]=W2_2d[i][j];
                 W3_1d[i*16*16+j*16+:16]=W3_2d[i][j];
                 W4_1d[i*16*16+j*16+:16]=W4_2d[i][j];
                 W5_1d[i*16*16+j*16+:16]=W5_2d[i][j];
                 W6_1d[i*16*16+j*16+:16]=W6_2d[i][j];
                 W7_1d[i*16*16+j*16+:16]=W7_2d[i][j];
                 I0_16_2d[i][j]=16'b0;
                 I1_16_2d[i][j]=16'b0;
                 I2_16_2d[i][j]=16'b0;
                 I3_16_2d[i][j]=16'b0;
                 I4_16_2d[i][j]=16'b0;
                 I5_16_2d[i][j]=16'b0;
                 I6_16_2d[i][j]=16'b0;
                 I7_16_2d[i][j]=16'b0;
             end
         end
         
         #20
         for(i=0;i<16;i=i+1)begin
             for(j=0;j<16;j=j+1)begin
                 I0_31_2d[i][j]=I0_31_1d[16*16*31-1-((i*16+j)*31) -: 31];
                 //截断处理:
                 //1.1先赋值符号位
                 I0_16_2d[i][j][15]=I0_31_2d[i][j][30];
                 
                 //1.2考虑低位截断(含有四舍五入)
                 if(I0_31_2d[i][j][8]==1'b1)begin
                    I0_31_2d[i][j][29:9]=I0_31_2d[i][j][29:9]+1;
                 end
                 
                 //1.3考虑高位饱和(上溢、下溢、截断)
                 if(I0_31_2d[i][j][30]==1'b0&&I0_31_2d[i][j][29:18]>=64) begin
                    I0_16_2d[i][j][14:9]=6'b111_111;
                 end else if(I0_31_2d[i][j][30]==1'b1&&I0_31_2d[i][j][29:24]!=63)begin
                    I0_16_2d[i][j][14:9]=6'b000_000;
                 end else begin
                    I0_16_2d[i][j][14:0]=I0_31_2d[i][j][23:9];
                 end
             end
         end
         
         for(i=0;i<16;i=i+1) begin
             for(j=0;j<16;j=j+1) begin
                 I0_16_1d[i*16*16+j*16+:16]=I0_16_2d[i][j];
             end
         end
         
         #20
         //I1截断处理
         for(i=0;i<16;i=i+1)begin
             for(j=0;j<16;j=j+1)begin
                 I1_31_2d[i][j]=I1_31_1d[16*16*31-1-((i*16+j)*31) -: 31];
                 //先赋值符号位
                 I1_16_2d[i][j][15]=I1_31_2d[i][j][30];
                 
                 //考虑截断(含有四舍五入)
                 //这里其实只考虑了为1时向前进位,但实际上符号位为1时是不用进位的,原理见前面的低位截断分析
                 if(I1_31_2d[i][j][8]==1'b1)begin
                    I1_31_2d[i][j][29:9]=I1_31_2d[i][j][29:9]+1;
                 end
                 
                 //再考虑饱和(上溢、下溢和截断)
                 if(I1_31_2d[i][j][30]==1'b0&&I1_31_2d[i][j][29:18]>=64) begin
                    I1_16_2d[i][j][14:9]=6'b111_111;
                 end else if(I1_31_2d[i][j][30]==1'b1&&I1_31_2d[i][j][29:24]!=63)begin
                    I1_16_2d[i][j][14:9]=6'b000_000;
                 end else begin
                    I1_16_2d[i][j][14:0]=I1_31_2d[i][j][23:9];
                 end
             end
         end


         for(i=0;i<16;i=i+1) begin
             for(j=0;j<16;j=j+1) begin
                 I1_16_1d[i*16*16+j*16+:16]=I1_16_2d[i][j];
             end
         end

         
         #20
         //I2截断处理
         for(i=0;i<16;i=i+1)begin
             for(j=0;j<16;j=j+1)begin
                 I2_31_2d[i][j]=I2_31_1d[16*16*31-1-((i*16+j)*31) -: 31];
                 //先赋值符号位
                 I2_16_2d[i][j][15]=I2_31_2d[i][j][30];
                 
                 //考虑截断(含有四舍五入)
                 if(I2_31_2d[i][j][8]==1'b1)begin
                    I2_31_2d[i][j][29:9]=I2_31_2d[i][j][29:9]+1;
                 end
                 
                 //再考虑饱和(上溢、下溢和截断)
                 if(I2_31_2d[i][j][30]==1'b0&&I2_31_2d[i][j][29:18]>=64) begin
                    I2_16_2d[i][j][14:9]=6'b111_111;
                 end else if(I2_31_2d[i][j][30]==1'b1&&I2_31_2d[i][j][29:24]!=63)begin
                    I2_16_2d[i][j][14:9]=6'b000_000;
                 end else begin
                    I2_16_2d[i][j][14:0]=I2_31_2d[i][j][23:9];
                 end
             end
         end

         
         for(i=0;i<16;i=i+1) begin
             for(j=0;j<16;j=j+1) begin
                 I2_16_1d[i*16*16+j*16+:16]=I2_16_2d[i][j];
             end
         end
         
         #20
         //I3截断处理
         for(i=0;i<16;i=i+1)begin
             for(j=0;j<16;j=j+1)begin
                 I3_31_2d[i][j]=I3_31_1d[16*16*31-1-((i*16+j)*31) -: 31];
                 //先赋值符号位
                 I3_16_2d[i][j][15]=I3_31_2d[i][j][30];
                 
                 //考虑截断(含有四舍五入)
                 if(I3_31_2d[i][j][8]==1'b1)begin
                    I3_31_2d[i][j][29:9]=I3_31_2d[i][j][29:9]+1;
                 end
                 
                 //再考虑饱和(上溢、下溢和截断)
                 if(I3_31_2d[i][j][30]==1'b0&&I3_31_2d[i][j][29:18]>=64) begin
                    I3_16_2d[i][j][14:9]=6'b111_111;
                 end else if(I3_31_2d[i][j][30]==1'b1&&I3_31_2d[i][j][29:24]!=63)begin
                    I3_16_2d[i][j][14:9]=6'b000_000;
                 end else begin
                    I3_16_2d[i][j][14:0]=I3_31_2d[i][j][23:9];
                 end
             end
         end

         
         for(i=0;i<16;i=i+1) begin
             for(j=0;j<16;j=j+1) begin
                 I3_16_1d[i*16*16+j*16+:16]=I3_16_2d[i][j];
             end
         end
         
         #20
         //I4截断处理
         for(i=0;i<16;i=i+1)begin
             for(j=0;j<16;j=j+1)begin
                 I4_31_2d[i][j]=I4_31_1d[16*16*31-1-((i*16+j)*31) -: 31];
                 //先赋值符号位
                 I4_16_2d[i][j][15]=I4_31_2d[i][j][30];
                 
                 //考虑截断(含有四舍五入)
                 if(I4_31_2d[i][j][8]==1'b1)begin
                    I4_31_2d[i][j][29:9]=I4_31_2d[i][j][29:9]+1;
                 end
                 
                 //再考虑饱和(上溢、下溢和截断)
                 if(I4_31_2d[i][j][30]==1'b0&&I4_31_2d[i][j][29:18]>=64) begin
                    I4_16_2d[i][j][14:9]=6'b111_111;
                 end else if(I4_31_2d[i][j][30]==1'b1&&I4_31_2d[i][j][29:24]!=63)begin
                    I4_16_2d[i][j][14:9]=6'b000_000;
                 end else begin
                    I4_16_2d[i][j][14:0]=I4_31_2d[i][j][23:9];
                 end
             end
         end

         
         for(i=0;i<16;i=i+1) begin
             for(j=0;j<16;j=j+1) begin
                 I4_16_1d[i*16*16+j*16+:16]=I4_16_2d[i][j];
             end
         end

         #20
         //I5截断处理
         for(i=0;i<16;i=i+1)begin
             for(j=0;j<16;j=j+1)begin
                 I5_31_2d[i][j]=I5_31_1d[16*16*31-1-((i*16+j)*31) -: 31];
                 //先赋值符号位
                 I5_16_2d[i][j][15]=I5_31_2d[i][j][30];
                 
                 //考虑截断(含有四舍五入)
                 if(I5_31_2d[i][j][8]==1'b1)begin
                    I5_31_2d[i][j][29:9]=I5_31_2d[i][j][29:9]+1;
                 end
                 
                 //再考虑饱和(上溢、下溢和截断)
                 if(I5_31_2d[i][j][30]==1'b0&&I5_31_2d[i][j][29:18]>=64) begin
                    I5_16_2d[i][j][14:9]=6'b111_111;
                 end else if(I5_31_2d[i][j][30]==1'b1&&I5_31_2d[i][j][29:24]!=63)begin
                    I5_16_2d[i][j][14:9]=6'b000_000;
                 end else begin
                    I5_16_2d[i][j][14:0]=I5_31_2d[i][j][23:9];
                 end
             end
         end

         
         for(i=0;i<16;i=i+1) begin
             for(j=0;j<16;j=j+1) begin
                 I5_16_1d[i*16*16+j*16+:16]=I5_16_2d[i][j];
             end
         end
         
         #20
         //I6截断处理
         for(i=0;i<16;i=i+1)begin
             for(j=0;j<16;j=j+1)begin
                 I6_31_2d[i][j]=I6_31_1d[16*16*31-1-((i*16+j)*31) -: 31];
                 //先赋值符号位
                 I6_16_2d[i][j][15]=I6_31_2d[i][j][30];
                 
                 //考虑截断(含有四舍五入)
                 if(I6_31_2d[i][j][8]==1'b1)begin
                    I6_31_2d[i][j][29:9]=I6_31_2d[i][j][29:9]+1;
                 end
                 
                 //再考虑饱和(上溢、下溢和截断)
                 if(I6_31_2d[i][j][30]==1'b0&&I6_31_2d[i][j][29:18]>=64) begin
                    I6_16_2d[i][j][14:9]=6'b111_111;
                 end else if(I6_31_2d[i][j][30]==1'b1&&I6_31_2d[i][j][29:24]!=63)begin
                    I6_16_2d[i][j][14:9]=6'b000_000;
                 end else begin
                    I6_16_2d[i][j][14:0]=I6_31_2d[i][j][23:9];
                 end
             end
         end

         
         for(i=0;i<16;i=i+1) begin
             for(j=0;j<16;j=j+1) begin
                 I6_16_1d[i*16*16+j*16+:16]=I6_16_2d[i][j];
             end
         end
         
         #20
         //I7截断处理
         for(i=0;i<16;i=i+1)begin
             for(j=0;j<16;j=j+1)begin
                 I7_31_2d[i][j]=I7_31_1d[16*16*31-1-((i*16+j)*31) -: 31];
                 //先赋值符号位
                 I7_16_2d[i][j][15]=I7_31_2d[i][j][30];
                 
                 //考虑截断(含有四舍五入)
                 if(I7_31_2d[i][j][8]==1'b1)begin
                    I7_31_2d[i][j][29:9]=I7_31_2d[i][j][29:9]+1;
                 end
                 
                 //再考虑饱和(上溢、下溢和截断)
                 if(I7_31_2d[i][j][30]==1'b0&&I7_31_2d[i][j][29:18]>=64) begin
                    I7_16_2d[i][j][14:9]=6'b111_111;
                 end else if(I7_31_2d[i][j][30]==1'b1&&I7_31_2d[i][j][29:24]!=63)begin
                    I7_16_2d[i][j][14:9]=6'b000_000;
                 end else begin
                    I7_16_2d[i][j][14:0]=I7_31_2d[i][j][23:9];
                 end
             end
         end

         #20
         for(i=0;i<16;i=i+1) begin
             for(j=0;j<16;j=j+1) begin
                 I7_16_1d[i*16*16+j*16+:16]=I7_16_2d[i][j];
             end
         end
 

         #400        
         $finish;
       end
endmodule

VCS&Verdi综合前仿真

综合前仿真是仿真自己写的RTL代码,步骤如下:

  1. 创建filelist.f文件,写入要编译的模块:
./matrix_multiplier_16.v
./tb_mm_mlp.v
  1. 使用vcs编译
vcs -full64 -fgp -y ./ic_lab/sim_ver +libext+.v -timescale=1ns/1ps -file ./filelist.f -kdb -fsdb -debug_access+all +lint=TFIPC +neg_tchk -negdelay -v ./ic_lab/data/PDK/verilog/*.v
  1. 使用verdi查看波形
verdi -ssf mm_mlp.fsdb

可以看到输出和参考结果的图一致
在这里插入图片描述
参考结果:
在这里插入图片描述

dc综合

dc_shell
set my_lib_path "./ic_lab/data/PDK/synopsys/ ./ic_lab/data/PDK/symbol/"
set search_path "$search_path $my_lib_path"
set design_dw_lib ./ic_lab/dw_foundation.sldb
set_app_var target_library  "ih55lp_hs_rvt_tt_1p20_25c_basic.db"
set_app_var link_library "* ih55lp_hs_rvt_tt_1p20_25c_basic.db $design_dw_lib"
set_app_var synthetic_library  "ih55lp_hs_rvt_tt_1p20_25c_basic.db $design_dw_lib"
set_app_var symbol_library "IH55LP_HS_RVT.sdb"
read_verilog ./matrix_multiplier_16.v
//这里可以添加一些时钟、时延控制,但我这个程序中没有写时钟信号,就不加了
set_max_area 0
compile
report_constraint -all_violators
report_area
write −format verilog −output ./matrix_multiplier_16_nelist.v
write_sdf ./matrix_multipleir_16.sdf 

write −format verilog −output ./matrix_multiplier_16_nelist.v执行结果:
注意只编译这一个模块,就不要加hierarchy,因为hierarchy是层次化的意思,会自顶向下找其他模块,只编译一个模块加这个参数会报错。
在这里插入图片描述
write_sdf ./matrix_multiplier_16.sdf执行结果:
在这里插入图片描述

VCS&Verdi综合后仿真

综合后仿真是仿真dc综合出来的网表文件

  1. 原先写编译文件路径的filelist.f改为
./matrix_multiplier_netlist.v
./tb_mm_mlp.v
  1. 使用vcs编译
vcs -full64 -fgp -y ./ic_lab/sim_ver +libext+.v -timescale=1ns/1ps -file ./filelist.f -kdb -fsdb -debug_access+all +lint=TFIPC +neg_tchk -negdelay -v ./ic_lab/data/PDK/verilog/*.v

后方跑完截图
在这里插入图片描述

  1. 使用verdi查看波形
verdi -ssf mm_mlp.fsdb

不足之处

  1. 在实现矩阵乘法的过程中,没有使用sram,没有使用优化算法,如booth
    encoding,加法树等进行优化,只是暴力实现了矩阵乘法。编译了几个小时才出结果,跑个后仿消耗了4.8G内存,有亿点离谱。

  2. 没有任何时钟和控制信号

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

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

相关文章

win11安装open-ssh server

帮助链接&#xff1a; 安装 OpenSSH | Microsoft Learn step1: 本机管理模式的power shell下查询安装状态 Get-WindowsCapability -Online | Where-Object Name -like OpenSSH* Name : OpenSSH.Client~~~~0.0.1.0 State : InstalledName : OpenSSH.Server~~~~0.0.1.0 Stat…

Kafka生产者与消费者api示例

生产者api示例 一个正常的生产逻辑需要具备以下几个步骤 配置生产者参数及创建相应的生产者实例 构建待发送的消息 发送消息 关闭生产者实例 采用默认分区方式将消息散列的发送到各个分区当中 package com.doitedu;import org.apache.kafka.clients.producer.KafkaProduce…

【人工智能】— 线性分类器、感知机、损失函数的选取、最小二乘法分类、模型复杂性和过度拟合、规范化

【人工智能】— 感知机、线性分类器、感知机、感知机、最小二乘法分类、模型复杂性和过度拟合、规范化 Linear predictions 线性预测分类线性分类器感知机感知机学习策略损失函数的选取距离的计算 最小二乘法分类求解最小二乘分类矩阵解法一般线性分类模型复杂性和过度拟合训练…

重估端到端原则

评价技术迭代的旧的定势眼光来自于该技术诞生时。 1970/80/90 年代&#xff0c;相比传输带宽技术&#xff0c;处理器更强。网络协议倾向于字段多&#xff0c;字段小且紧凑&#xff0c;尽可能减少传输量&#xff0c;用 “算法技巧” 等价&#xff0c;如果 TCP 序列号 48 位&…

【iOS】消息传递和消息转发机制

消息传递机制 在OC语言中&#xff0c;调用对象的方法被叫做消息传递。消息有名称和选择子(selector)&#xff0c;可以接受参数&#xff0c;还可能有返回值。 在Objective-C中&#xff0c;如果向某对象传递消息&#xff0c;那就会使用动态绑定机制来决定需要调用的方法。在底层…

C++进阶 —— 范围for(C++11新特性)

目录 一&#xff0c;范围for介绍 二&#xff0c;范围for注意事项 一&#xff0c;范围for介绍 范围for&#xff08;range-based for loop&#xff09;是C11新引入的特性&#xff0c;可遍历各种序列结构的容器&#xff08;如数组、vector、list等&#xff09;&#xff1b;每次循…

【QT】Qt ApplicationManager Compositor源码分析

Qt ApplicationManager的Compositor功能分析 根据Qt ApplicationManager官网介绍&#xff0c;它基于Wayland协议实现了Compositor功能。下述为官网介绍。实际上&#xff0c;QtApplicationManager是使用了QtWayland模块来实现Compositor的。Wayland是一套旨在替代XWindow的 Com…

微机实验:第5章——存储器设计

存储器设计 将两片6116所有的存储单元都写入11H。 提示&#xff1a;6116的存储容量为2K*8b&#xff0c;片内地址为0000H-07FFH,两片一起构成F8000H-F8FFFH的内存空间。 仿真调试时可以看到&#xff1a;每片从0000H-07FFH的每个存储单元均显示11H。 CODE SEGMENTASSUME CS:C…

4-4 哈夫曼编码

博主简介&#xff1a;一个爱打游戏的计算机专业学生博主主页&#xff1a; 夏驰和徐策所属专栏&#xff1a;算法设计与分析 1.什么是哈夫曼编码&#xff1f; 哈夫曼编码&#xff08;Huffman coding&#xff09;是一种用于数据压缩的无损编码方法。它是由David A. Huffman在1952…

STM32F4_软件模拟SPI

目录 1. 硬件连接 2. SPI通讯协议 3. W25Q64 简介 4. 程序详解 4.1 main.c 4.2 SPI.c 4.3 SPI.h 4.4 W25Q128.c 4.5 W25Q128.h 4.6 OLED.c 4.7 OLED.h 4.8 OLED_Font.h 5. 实验结果 我们都知道&#xff0c;SPI 和 IIC 一样&#xff0c;都可以通过硬件方式和软件方…

JSON基础(待补充)

一、JSON初识 1.1基础认识 JSON是一种轻量级的数据交换格式&#xff0c;它基于JavaScript语言的对象表示法&#xff0c;可以在多种语言之间进行数据交换。JSON的基本数据类型有数值、字符串、布尔值、数组、对象和空值。JSON的格式简洁易读&#xff0c;也易于解析和处理。JSON…

【数据结构】由完全二叉树引申出的堆的实现

【数据结构】由完全二叉树引申出的堆的实现 一、什么是堆二、目标三、实现1、初始化工作2、堆的插入(堆的创建)2.1、向上调整建堆2.1.1、向上调整算法原理解析2.1.2、代码实现 2.2、向下调整建堆2.2.1、向下调整算法原理解析2.2.2、代码实现 2.3、“向上”和“向下”复杂度的差…

初识网络安全

目录 HTML前置基础知识 1、id和class区别&#xff1a; 2、一些常用的属性&#xff1a; 3、HTML字符编码和实体编码 4、URL介绍 网址的组成部分&#xff1a; TTL值 DNS工作原理和资源记录及其种类&#xff1a; 5、正确区分“加密”和“签名” 6、状态码 1xx &#xf…

如何安装pycharm

PyCharm是JetBrains公司推出的一款Python集成开发环境&#xff08;IDE&#xff09;&#xff0c;可以提供高效的Python代码编写、调试和测试。以下是一些PyCharm的主要功能&#xff1a; 代码智能提示和自动补全功能&#xff1b;支持调试和测试Python代码&#xff1b;完整的Pyth…

基于Springboot+Vue的幼儿园管理系统设计与实现

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架下…

汽车相关知识及术语

1 汽车构造与制造流程 1.1 汽车构造 汽车可以分为四大部分 车身&#xff1a; 骨架、车身钣金件以及座椅、仪表、天窗、车外后视镜等车身附件 动力系统&#xff1a; 发动机和变速器 底盘&#xff1a; 传动系统、悬架系统、转向系统、制动系统和车轮轮胎 电气电子系统&#…

《Apollo 智能驾驶进阶课程》三、无人车自定位技术

1. 什么是无人车自定位系统 相对一个坐标系来确定无人车的位置和姿态 定位的指标要求大概分为三个部分&#xff1a;精度、鲁棒性、场景 定位精度必须控制在10厘米以内&#xff0c;才能使行驶中的自动驾驶车辆避免出现碰撞/车道偏离的情况。鲁棒性一般情况下用最大值来衡量。…

Java IO流详细教程

目录 一、IO介绍 IO流体系 字节流 字节输出流&#xff1a;FileoutputStream 字节输入流FilelnputStream 字符流 字符输入流 字符输出流 缓冲流 字节缓冲流 字符缓冲流 序列化、反序列化流 序列化/对象操作输出流 反序列化/对象操作输入流 打印流 字节打印流 字…

firewalld与iptables练习

1、禁止一个IP访问 iptables -I INPUT -s $ip -j REJECT 2、清空默认的防火墙默认规则&#xff1a; iptables -F 3、保存清空后的防火墙规则表 service iptables save 4、firewall-cmd --list-all #查看防火墙规则&#xff08;只显示/etc/firewalld/zones/public.xml中防火墙…

投票活动链接创建微信链接视频投票线上免费投票链接

近些年来&#xff0c;第三方的微信投票制作平台如雨后春笋般络绎不绝。随着手机的互联网的发展及微信开放平台各项基于手机能力的开放&#xff0c;更多人选择微信投票小程序平台&#xff0c;因为它有非常大的优势。 1.它比起微信公众号自带的投票系统、传统的H5投票系统有可以图…