• 以32bit加法器为核心的加法、减法、乘法和除法计算器(ALU)


    1 任务概述

    实现一个以加法器为核心的计算器。
    加法:能够实现32bit加法
    减法:能够实现32bit减法
    乘法:能够实现两个32bit数字的乘法,乘积为64bit
    除法:能够实现两个32bit无符号数的除法,商为32bit,余数为32bit
    解读:该部分的关键在于串并转换,状态数并不多,也没有必要简化;串并转换的关键在于计数器信号和使能信号;而且对于线路空闲时发送无效字节同样很重要,需要借助已存在的或者需要新建信号来支持。 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2 系统模块设计

    在这里插入图片描述

    图2-1 系统模块图
    输入端口

    • Operand_X-32bit
      加数、被减数、乘数、被除数
    • Operand_Y-32bit
      加数、减数、乘数、除数
    • Opcode
      运算选择信号;3’b001-加法、3’b010-减法、3’b110-乘法、3’b111-除法、其余无效
    • clk
      时钟信号
      输出端口
    • Result-64bit
      64bit运算结果
      内部模块连线图
      在这里插入图片描述

    图2-2 内部模块连线图
    详细设计
    3.1 加减法
    引入补码可以将加法和减法统一起来,可以采用“联通符号位在内,按位取反,末位加一”的方法,由[y]_补求[-y]_补。
    在这里插入图片描述

    图3-1以加法器为核心的加减法器电路原理示意图
    3.2 乘法
    如果使用“符号位单独处理(异或运算),数值按照无符号数乘法”的方法处理有符号数乘法的话,因为一般机器采用补码表示,所以需要在补码和原码之间来回做变换,增加了操作步骤。
    Booth乘法算法:
    进行n轮加法、移位,最后再多来一次加法
    每次加法可能+0 、+[x]补、+[-x]
    每次移位是“补码的算数右移”
    符号位参与运算
    在2中,需要根据部分积 y 中的最低两位来确定加什么:
    表2-1 最低两位操作表
    y_i y
    (i+1) y
    (i+1) y_i 操作
    0 0 0 +0
    0 1 1 +[x]_补
    1 0 -1 +[-x]_补
    1 1 0 +0
    在这里插入图片描述

    图3-2以加法器为核心的Booth乘法电路原理示意图
    3.3 除法
    第三个版本将商寄存器和余数寄存器合并为一个左移的64-bit寄存器,从余数移位开始计算,运算完成后,结果的高低两个部分需要通过移位互换位置(处理器设计中低位是商,高位是余数)。
    在这里插入图片描述

    图3-3除法算法流程图
    除法器采用一个32-bit的除法寄存器、一个32-bit的ALU和一个64-bit的余数寄存器:
    在这里插入图片描述

    图3-4除法模块示意图
    笔者也编写了补码乘法——加减交替法,但是由于对于该算法理解不是很透彻,导致无法验证,遂放弃,于是只简单开发了无符号数乘法。
    在这里插入图片描述

    图3-5加减交替法有符号数除法电路示意图

    4 对编码的说明

    加法器
    通过补码可以将加法和减法统一起来,如果是减法的话,可以通过+[y]_补 来实现。

    assign Result[32:0] = Operand_X+B+add_cin;
        always @(Operand_Y or Opcode) begin
            if (Opcode == 3'b010) 
                B = ~Operand_Y;
            else if (Opcode == 3'b001)
                B = Operand_Y;
        end
        always @(Opcode) begin
            if (Opcode == 3'b010)
                add_cin = 1'b1;
            else if (Opcode == 3'b001)
                add_cin = 1'b0;
        end
        reg c;
        assign Result ={{32{c}},res};
        always @(Cout or res) begin
            if ((Operand_X[31]^Operand_Y[31])==0) begin
                if (Opcode == 3'b001&&Cout) c = Operand_X[31];
                else c = res[31];
            end else begin
                if (Opcode == 3'b010&&Cout) c = Operand_X[31];
                else c = res[31];
            end
        end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    乘法器
    以加法器为核心,经过33个周期实现两个32bit的数据相乘。

    always @(posedge clk or posedge rst) begin
            if (rst) 
                Result <= 65'b0;
            else if (Opcode == 3'b110) begin
                Result <= {32'b0,Operand_X,1'b0};
            end else begin
                Result <= {Add_Result[31],Add_Result,Result[32:1]};
            end
        end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    加法器两个输入信号的生成

    always @(posedge rst or Result or Operand_X or Busy) begin
            if (rst)
                Add_A <= 32'b0;  
            else if (Busy) 
                Add_A <= Result[64:33];
            else
                Add_A <= Operand_X;
        end
    
        always @(Busy or Multiplicand or Operand_Y) begin
            if (Busy) 
                Operand_Y_inner <= Multiplicand;
            else 
                Operand_Y_inner <= Operand_Y;
        end
    
        always @(Opcode_inner or Operand_Y_inner) begin
            if (Opcode_inner == 2'b10)
                Add_B <= Operand_Y_inner;
            else if (Opcode_inner == 2'b11)
                Add_B <= ~Operand_Y_inner;
            else 
                Add_B <= 32'b0;
        end
    
        always @(Opcode_inner) begin
            if (Opcode_inner == 2'b11)
                Add_Cin <= 1'b1;
            else 
                Add_Cin <= 1'b0; 
    end
    	if (Result[1:0] == 2'b00 || Result[1:0] == 2'b11)
                    Opcode_inner <= 2'b00;
                else if (Result[1:0] == 2'b01) 
                    Opcode_inner <= 2'b10;
                else 
                    Opcode_inner <= 2'b11;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    除法器
    32bit无符号数除法,经过33个周期得出结果。

    always @(posedge clk or posedge rst) begin
            if (rst) begin
                result <= 64'b0; 
            end else if (Opcode == 3'b111) begin
                result <= {31'b0,Operand_X,1'b0};
            end else if (result[63:32] >= Operand_Y)
                result = {mid_result[30:0],result[31:0],1'b1};
            else 
                result = {result[62:32],result[31:0],1'b0} ;
        end
         
        always @(result) begin
            mid_result = result[63:32] - Operand_Y;
    end
    	assign Remainder= (Operand_Y == 32'b0)?32'bz:{1'b0,result[63:33]};
        assign Quotient = result[31:0];
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    加减交替法实现补码有符号除法:未仿真验证
    
    • 1

    在这里插入图片描述

    图4-1 加减交替法算法步骤

    //符号扩展
        assign operand_x = {Operand_X[31],Operand_X};
        assign operand_y = {Operand_Y[31],Operand_Y};
        //0 不等,1 相等
        always @(Add_A or Add_B or Add_Cin) begin
            Result = Add_A + Add_B + Add_Cin;
        end
        
        always @(posedge rst or posedge clk) begin
            if (rst) 
                Mul_Counter <= 5'b0;
            else if (Opcode == 3'b110) 
                Mul_Counter <= 5'b11111;
            else if (Busy) 
                Mul_Counter <= Mul_Counter - 1;
        end
    
        always @(posedge clk or posedge rst) begin
            if (rst)
                Busy <= 1'b0;
            else if (Opcode == 3'b110) 
                Busy <= 1'b1;
            else if (Busy == 1'b1 && Mul_Counter == 5'b00000) begin
                Busy <= 1'b0;
            end
        end
    
        always @(operand_x or Busy or Add_A) begin
            if (Busy) 
                Add_A <= {Add_A[32:1],1'b0};
            else
                Add_A <= operand_x;
        end
    
        // 1 同号,0 异号
        always @(Opcode_inner or operand_y) begin
            if (Opcode_inner == 1'b0)
                Add_B <= operand_y;
            else if (Opcode_inner == 1'b1)
                Add_B <= ~operand_y;
        end
    
        always @(Opcode_inner) begin
            if (Opcode_inner == 1'b1)
                Add_Cin <= 1'b1;
            else 
                Add_Cin <= 1'b0; 
        end
    
        always @(Opcode_inner or Quotient or Busy) begin
            if (!Busy) begin
                Quotient <= 32'b0;
            end else begin
                if (Opcode_inner == 1'b1) 
                    Quotient <= {Quotient[31:1],1'b1};
                else
                    Quotient <= {Quotient[31:1],1'b0};
            end
        end
    
        always @(Busy or Result or Opcode or operand_y) begin
            if (Busy) begin
                if (Result[32:31] == operand_y[32:31])
                    Opcode_inner <= 1'b1;
                else 
                    Opcode_inner <= 1'b0;
            end else begin 
                if (Opcode == 3'b100) 
                    Opcode_inner <= 1'b0;
                else if (Opcode == 3'b101) 
                    Opcode_inner <= 1'b1;
                else 
                    Opcode_inner <= 1'b0; 
            end
        end
        assign Remainder = Result[31:0];
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76

    顶层设计模块
    为了使得获取乘法和除法结果的设计更为简便,将muler和divider模块中的计数器改为计33计数器,使得在最后一个周期,即第33个周期输出结果,该周期之后,对应的Busy信号将清零。
    reg [63:0] Result;
    wire [63:0] Result1,Result2,Result3;
    wire Buys1,Busy2;
    assign Opc = Opcode;
    add_sub as1(
    .Operand_X(Operand_X),
    .Operand_Y(Operand_Y),
    .Opcode(Opc),
    .Result(Result1)
    );
    muler m1(
    .clk(clk),
    .rst(rst),
    .Opcode(Opc),
    .Operand_X(Operand_X),
    .Operand_Y(Operand_Y),
    .Busy(Busy1),
    .Cout(Cout),
    .Product(Result2)
    );
    divider D1(
    .clk(clk),
    .rst(rst),
    .Opcode(Opc),
    .Operand_X(Operand_X),
    .Operand_Y(Operand_Y),
    .Busy(Busy2),
    .Result(Result3)
    );
    always @(Result3 or Result1 or Result2) begin
    if (Opcode == 3’b010||Opcode == 3’b001)
    Result <= Result1;
    else if (Busy1)
    Result <= Result2;
    else if (Busy2)
    Result <= Result3;
    else
    Result <= 64’bz;
    end
    Testbench开发
    5.1. Testbench开发思路
    该题目的仿真并不算难点,仅有的难点在于计算下一个计算周期的Busy信号的产生,即下一次测试数据的打入时间至少在前一次数据计算完成后。
    由于该计算器由三个部分完成,所以采用三个部分先单独测试,然后在进行整体测试的思路。
    在这里插入图片描述

    图5-1 项目文件结构图
    5.2. Testbench说明
    加减法
    表5-1 加减法测试用例及测试结果表
    X Y 是否通过

    {$random}%{2^32}	{$random}%{2^32}32'h0007 (7)	32'hfffffff4(-12)32'h7fff	32'h7fff	是
    32'hffff_fffd(-3)	32'hffff_fff4(-12)32'h8000_0000( -2^31)	32'h0001(1)	是
    	代码
    	initial begin 
            Operand_X = {$random}%{2^32};
            Operand_Y = {$random}%{2^32};
            Opcode = 3'd1;
            res = Operand_X+Operand_Y;
            #10;res1 = Result;
            if (res == res1) begin
                $display("[time@%t]: x=%h,y=%h,Opcode=%h -------PASS",$time,Operand_X,Operand_Y,Opcode);
            end else begin
                $display("[time@%t]ERROR: x=%h,y=%h,Opcode=%h",$time,Operand_X,Operand_Y,Opcode);
                //$finish;
            end
    
            #10; 
            Operand_X = 32'h0007; Operand_Y = 32'hfffffff4;
            Opcode = 3'd1;
            #10;res1 = Result; //7+(-12)= -5;
            if (64'hffff_ffff_ffff_fffb == res1) begin
                $display("[time@%t]: x=%h,y=%h,Opcode=%h -------PASS",$time,Operand_X,Operand_Y,Opcode);
            end else begin
                $display("[time@%t]ERROR: x=%h,y=%h,Opcode=%h",$time,Operand_X,Operand_Y,Opcode);
                //$finish;
            end
    
            #10; 
            Operand_X = 32'h7fff;
            Operand_Y = 32'h7fff;
            Opcode = 3'd1;
            #10;res1 = Result;
            if (64'h0000_FFFE == res1) begin
                $display("[time@%t]: x=%h,y=%h,Opcode=%h -------PASS",$time,Operand_X,Operand_Y,Opcode);
            end else begin
                $display("[time@%t]ERROR: x=%h,y=%h,Opcode=%h",$time,Operand_X,Operand_Y,Opcode);
                //$finish;
            end
    
            #10;
            Operand_X = 32'hffff_fffd;//-3
            Operand_Y = 32'hffff_fff4;//-12
            Opcode = 3'd2;
            #10;res1 = Result; //-3-(-12) = 9
            if (64'h0000_0009 == res1) begin
                $display("[time@%t]: x=%h,y=%h,Opcode=%h-------PASS",$time,Operand_X,Operand_Y,Opcode);
            end else begin
                $display("[time@%t]ERROR: x=%h,y=%h,Opcode=%h",$time,Operand_X,Operand_Y,Opcode);
                //$finish;
            end
    
            #10;
            Operand_X = 32'h8000_0000;//-2^31
            Operand_Y = 32'h0001;//1
            Opcode = 3'd2;
            #10;res1 = Result; //
            if (64'hffff_ffff_7fff_ffff == res1) begin
                $display("[time@%t]: x=%h,y=%h,Opcode=%h-------PASS",$time,Operand_X,Operand_Y,Opcode);
            end else begin
                $display("[time@%t]ERROR: x=%h,y=%h,Opcode=%h",$time,Operand_X,Operand_Y,Opcode);
                //$finish;
            end
            #20;
            $finish;
        end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    乘法

    always begin
            #5; clk = ~clk;
        end
    
        initial begin
            #15;
            Operand_X = 32'b0000_0000_0000_0000_0000_0111_0110_0001;
            Operand_Y = 32'b0000_0000_0000_0000_1001_0111_0110_0001;
            // Operand_X = 32'h6;
            // Operand_Y = 32'h2;
            #330;
            #15;
            Operand_X = $random;
            Operand_Y = $random;
            #330;
            #15;
            Operand_X = 32'b1000_0000_0000_0000_0000_0111_0110_0001;
            Operand_Y = 32'b1000_0000_0000_0000_1001_0111_0110_0001;
            #330;
            #15;
            Operand_X = 32'b0111_1111_1111_1111_1111_1111_1111_1111;
            Operand_Y = 32'b1000_0100_1001_0111_1110_1100_0111_1000;
            #330;
        end
    
        always begin
            Opcode = 3'b000;
            #15;
            Opcode = 3'b110;
            #5;
            Opcode = 3'b000;
            #330;
        end
    
        initial begin
            clk = 0;
            rst = 0;
        end
    
        always begin
            #5;
            rst = 1;
            #5;
            rst = 0;
            #10;
            #330;
        end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    除法

    always begin
            #5; clk = ~clk;
        end
    
        initial begin
            #15;
            Operand_X = 32'h000A;
            Operand_Y = 32'h0002;
            #330;
            #15;
            Operand_X = 2;
            Operand_Y = 0;
            #330;
            #15;
            Operand_X = 32'd18;
            Operand_Y = 32'h5;
            #330;
            #15;
            Operand_X = 32'd34;
            Operand_Y = 32'h6;
            #330;
        end
    
        always begin
            Opcode = 3'b000;
            #15;
            Opcode = 3'b111;
            #5;
            Opcode = 3'b000;
            #330;
        end
    
        initial begin
            clk = 0;
            rst = 0;
        end
    
        always begin
            #5;
            rst = 1;
            #5;
            rst = 0;
            #10;
            #330;
        end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    整体测试
    //初始化模块

    alu_top al_tp1(
            .Operand_X(Operand_X),
            .Operand_Y(Operand_Y),
            .Opcode(Opcode),
            .clk(clk),
            .rst(rst),
            .Opc(Opc),
            .Busy1(Busy1),
            .Busy2(Busy2),
            .Result1(Result1),
            .Result2(Result2),
            .Result3(Result3),
            .Result(Result)
        );
        always begin
            #5;clk = ~clk;
        end
        initial begin
            #5;
            //加法器
            Operand_X = 32'h0007; Operand_Y = 32'hfffffff4; 
            #10;res1 = Result; //7+(-12)= -5;
            if (64'hffff_ffff_ffff_fffb == res1) begin
                $display("[time@%t]: x=%h,y=%h,Opcode=%h -------PASS",$time,Operand_X,Operand_Y,Opcode);
            end else begin
                $display("[time@%t]ERROR: x=%h,y=%h,Opcode=%h",$time,Operand_X,Operand_Y,Opcode);
            end
            //乘法器
            #15;
            Operand_X = 32'b0000_0000_0000_0000_0000_0111_0110_0001;
            Operand_Y = 32'b0000_0000_0000_0000_1001_0111_0110_0001;
            #330;
            //除法器
            #15;
            Operand_X = 32'd18;
            Operand_Y = 32'h5;
        end
    
        always begin
            Opcode = 3'b000;
            #5;
            Opcode = 3'd1;
            #10;
            //乘法器
            Opcode = 3'b000;
            #10;
            Opcode = 3'b110;
            #5;
            #5;
            Opcode = 3'b000;
            #325;
            //除法器
            Opcode = 3'b000;
            #10;
            Opcode = 3'b111;
            #5;
            #5;
            Opcode = 3'b000;
            #330;
        end
    
        initial begin
            #5;
            #10;
            //乘法器
            clk = 1;
            rst = 0;
            #15;
            #330;
            //除法器
            clk = 1;
            rst = 0;
            #15;
            #330;
        end
    
        always begin
            #5;
            #10;
            //乘法器
            #5;
            rst = 1;
            #5;
            rst = 0;
            #10;
            #325;
            //除法器
            #5;
            rst = 1;
            #5;
            rst = 0;
            #10;
            #330;
        end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    ### 6仿真结果
    
    • 1

    6.1 加减法

    图6-1 加减法仿真成功图
    6.2 乘法

    图6-2 乘法测试用例1仿真成功

    图6-3乘法测试用例2仿真成功

    图6-3乘法测试用例3仿真成功

    图6-4乘法测试用例4仿真成功
    6.3 除法

    图6-5除法测试用例1仿真成功

    图6-6除法测试用例2(除数为零)仿真成功

    图6-7除法测试用例3仿真成功

    图6-8除法测试用例4仿真成功
    总结
    编写Testbench文件时,首先要搞清楚每个信号是怎么产生的,其次要弄清楚信号之间的产生逻辑,结合实际想要完成的功能,在仿真过程中,发现并修改Design Source文件的错误。
    在复杂逻辑,以及类似于多bit数据寄存器等难以通过肉眼直接观察正误的项目中,要优先理清楚Design Source文件中的逻辑,避免逻辑错误,而不是想着在仿真过程中发现逻辑错误,尽可能节 省项目完成时间。
    仿真过程中尽可能把出现的所有信号都显示出来,这样的话更容易发现问题所在。
    针对次题目,仿真过程中需要将十进制和二进制补码等相互转换才更容易观察出正误,如果采用自行判断的话,笔者目前还没有掌握方法——将十进制转化成二进制补码,因为计算机中多采用补码,所以待学习。
    附:代码
    alu_top.v

    `timescale 1ns / 1ps
    //
    // Company: 
    // Engineer: 
    // 
    // Create Date: 2023/09/30 20:51:22
    // Design Name: 
    // Module Name: alu_top
    // Project Name: 
    // Target Devices: 
    // Tool Versions: 
    // Description: 
    // 
    // Dependencies: 
    // 
    // Revision:
    // Revision 0.01 - File Created
    // Additional Comments:
    // 
    //
    
    
    module alu_top(
        input   [31:0]  Operand_X,Operand_Y,
        input   [2:0]   Opcode,
        input           clk,
        input           rst,
        input   [63:0]  Result1,Result2,Result3,
        input           Busy1,Busy2,
        output  [2:0]   Opc,
        output  [63:0]  Result
    
    );
        //reg     [31:0]  Operand_X,Operand_Y;
        reg   [63:0]  Result;
        wire [63:0] Result1,Result2,Result3;
        //reg     [2:0]   Opcode;
        //reg             clk,rst;
     
        wire            Buys1,Busy2;
        assign Opc = Opcode;
        add_sub as1(
            .Operand_X(Operand_X),
            .Operand_Y(Operand_Y),
            .Opcode(Opc),
            .Result(Result1)
        );
    
        muler m1(
            .clk(clk),
            .rst(rst),
            .Opcode(Opc),
            .Operand_X(Operand_X),
            .Operand_Y(Operand_Y),
            .Busy(Busy1),
            .Cout(Cout),
            .Product(Result2)
        );
    
        divider D1(
            .clk(clk),
            .rst(rst),
            .Opcode(Opc),
            .Operand_X(Operand_X),
            .Operand_Y(Operand_Y),
            .Busy(Busy2),
            .Result(Result3)
        );
    
        // always @(posedge clk) begin
        //     Result <= 64'b1;
        // end
        // assign Result = (Opcode == 3'b010||Opcode==3'b001)?Result1:
        //                     (Opcode == 3'b110)?Result2:
        //                     (Opcode == 3'b111)?Result3:
        //                     64'bZ;
        always @(Result3 or Result1 or Result2) begin
            if (Opcode == 3'b010||Opcode == 3'b001) 
                Result <= Result1;
            else if (Busy1) 
                Result <= Result2;
            else if (Busy2)
                Result <= Result3;
            else 
                Result <= 64'bz;
        end
    endmodule
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89

    add_sub.v

    module add_sub (
        input [31:0]    Operand_X,Operand_Y,
        input [2:0]     Opcode,
        output[63:0]    Result
    );
        wire Cout;
        reg [31:0] B;
        reg add_cin;
        wire [31:0] res;
        assign {Cout,res} = Operand_X+B+add_cin;
        always @(Operand_Y or Opcode) begin
            if (Opcode == 3'b010) 
                B = ~Operand_Y;
            else if (Opcode == 3'b001)
                B = Operand_Y;
        end
        always @(Opcode) begin
            if (Opcode == 3'b010)
                add_cin = 1'b1;
            else if (Opcode == 3'b001)
                add_cin = 1'b0;
        end
        reg c;
        assign Result ={{32{c}},res};
        always @(Cout or res) begin
            if ((Operand_X[31]^Operand_Y[31])==0) begin
                if (Opcode == 3'b001&&Cout) c = Operand_X[31];
                else c = res[31];
            end else begin
                if (Opcode == 3'b010&&Cout) c = Operand_X[31];
                else c = res[31];
            end
            
        end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    muler.v

    
    module muler(
        input           rst,
        input           clk,
        input  [2:0]    Opcode,
        input  [31:0]   Operand_X,
        input  [31:0]   Operand_Y,
        output          Busy,
        output          Cout,
        output [63:0]   Product         
    );
        reg         Busy,Cout;
        reg [64:0]  Result;
        reg [31:0]  Add_A,Add_B,Add_Result;
        reg         Add_Cin;
        reg [5:0]   Mul_Counter;
        reg [31:0]  Multiplicand,Operand_Y_inner;
        reg [1:0]   Opcode_inner;
        //00:add 0,01:sub multiplicand; 10:add multipicand;11:reserved
        always @(Add_A or Add_B or Add_Cin) begin
            {Cout,Add_Result} = Add_A+Add_B+Add_Cin;
        end
        assign Product = Result[64:1];
        always @(posedge rst or posedge clk) begin
            if (rst) 
                Mul_Counter <= 6'b0;
            else if (Opcode == 3'b110) 
                Mul_Counter <= 6'b100000;
            else if (Busy) 
                Mul_Counter <= Mul_Counter - 1;
        end
    
        always @(posedge clk or posedge rst) begin
            if (rst)
                Busy <= 1'b0;
            else if (Opcode == 3'b110) 
                Busy <= 1'b1;
            else if (Busy == 1'b1 && Mul_Counter == 6'b000000) begin
                Busy <= 1'b0;
            end
        end
    
        always @(posedge clk or posedge rst) begin
            if (rst) 
                Multiplicand <= 32'b0;
            else if (Opcode == 3'b110) 
                Multiplicand <= Operand_Y;
        end
    
        always @(posedge clk or posedge rst) begin
            if (rst) 
                Result <= 65'b0;
            else if (Opcode == 3'b110) begin
                Result <= {32'b0,Operand_X,1'b0};
            end else begin
                Result <= {Add_Result[31],Add_Result,Result[32:1]};
            end
        end
    
        always @(posedge rst or Result or Operand_X or Busy) begin
            if (rst)
                Add_A <= 32'b0;  
            else if (Busy) 
                Add_A <= Result[64:33];
            else
                Add_A <= Operand_X;
        end
    
        always @(Busy or Multiplicand or Operand_Y) begin
            if (Busy) 
                Operand_Y_inner <= Multiplicand;
            else 
                Operand_Y_inner <= Operand_Y;
        end
    
        always @(Opcode_inner or Operand_Y_inner) begin
            if (Opcode_inner == 2'b10)
                Add_B <= Operand_Y_inner;
            else if (Opcode_inner == 2'b11)
                Add_B <= ~Operand_Y_inner;
            else 
                Add_B <= 32'b0;
        end
    
        always @(Opcode_inner) begin
            if (Opcode_inner == 2'b11)
                Add_Cin <= 1'b1;
            else 
                Add_Cin <= 1'b0; 
        end
    
        always @(Busy or Result or Opcode) begin
            if (Busy) begin
                if (Result[1:0] == 2'b00 || Result[1:0] == 2'b11)
                    Opcode_inner <= 2'b00;
                else if (Result[1:0] == 2'b01) 
                    Opcode_inner <= 2'b10;
                else 
                    Opcode_inner <= 2'b11;
            end else begin
                if (Opcode == 3'b100) 
                    Opcode_inner <= 2'b10;
                else if (Opcode == 3'b101) 
                    Opcode_inner <= 2'b11;
                else 
                    Opcode_inner <= 2'b00; 
            end
        end
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110

    divider.v

    
    module divider (
        input           rst,
        input           clk,
        input  [2:0]    Opcode,
        input  [31:0]   Operand_X,
        input  [31:0]   Operand_Y,
        output          Busy,
        // output          Cout,
        output [31:0]   Quotient,
        output [31:0]   Remainder,  
        output [63:0]   Result  
    );
        wire[31:0]  Quotient,Remainder;
        reg [63:0]  result;//hi-remainder,lo-quotient;
        reg         Busy;
        
        reg [5:0]   Mul_Counter;
        reg [31:0]  mid_result;
        wire[63:0]  Result;
        assign Result = {Remainder,Quotient};//高位是余数,低位是商
        always @(posedge clk or posedge rst) begin
            if (rst) begin
                result <= 64'b0; 
            end else if (Opcode == 3'b111) begin
                result <= {31'b0,Operand_X,1'b0};
            end else if (result[63:32] >= Operand_Y)
                result = {mid_result[30:0],result[31:0],1'b1};
            else 
                result = {result[62:32],result[31:0],1'b0} ;
        end
         
        always @(result) begin
            mid_result = result[63:32] - Operand_Y;
        end
    
        always @(posedge clk or posedge rst) begin
            if (rst) begin
                Busy <= 1'b0;
            end else if (Opcode == 3'b111) begin
                Busy <= 1'b1;
            end else if (Mul_Counter == 6'b0)
                Busy <= 1'b0;
        end
    
    
        always @(posedge rst or posedge clk) begin
            if (rst) 
                Mul_Counter <= 6'b0;
            else if (Opcode == 3'b111) 
                Mul_Counter <= 6'b100000;
            else if (Busy) 
                Mul_Counter <= Mul_Counter - 1;
        end
    
        assign Remainder= (Operand_Y == 32'b0)?32'bz:{1'b0,result[63:33]};
        assign Quotient = result[31:0];
    endmodule
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    alu_top.v

    
    
    module alu_top_tb();
        reg     [31:0]  Operand_X,Operand_Y;
        wire    [63:0]  Result,Result1,Result2,Result3;
        reg     [2:0]   Opcode;
        wire     [2:0]   Opc;
        reg             clk,rst;
        reg     [63:0]  res1;
        wire            Busy1,Busy2;
    
        alu_top al_tp1(
            .Operand_X(Operand_X),
            .Operand_Y(Operand_Y),
            .Opcode(Opcode),
            .clk(clk),
            .rst(rst),
            .Opc(Opc),
            .Busy1(Busy1),
            .Busy2(Busy2),
            .Result1(Result1),
            .Result2(Result2),
            .Result3(Result3),
            .Result(Result)
        );
        always begin
            #5;clk = ~clk;
        end
        initial begin
            #5;
            //加法器
            Operand_X = 32'h0007; Operand_Y = 32'hfffffff4; 
            #10;res1 = Result; //7+(-12)= -5;
            if (64'hffff_ffff_ffff_fffb == res1) begin
                $display("[time@%t]: x=%h,y=%h,Opcode=%h -------PASS",$time,Operand_X,Operand_Y,Opcode);
            end else begin
                $display("[time@%t]ERROR: x=%h,y=%h,Opcode=%h",$time,Operand_X,Operand_Y,Opcode);
            end
            //乘法器
            #15;
            Operand_X = 32'b0000_0000_0000_0000_0000_0111_0110_0001;
            Operand_Y = 32'b0000_0000_0000_0000_1001_0111_0110_0001;
            #330;
            //除法器
            #15;
            Operand_X = 32'd18;
            Operand_Y = 32'h5;
        end
    
    
        always begin
            Opcode = 3'b000;
            #5;
            Opcode = 3'd1;
            #10;
            //乘法器
            Opcode = 3'b000;
            #10;
            Opcode = 3'b110;
            #5;
            #5;
            Opcode = 3'b000;
            #325;
            //除法器
            Opcode = 3'b000;
            #10;
            Opcode = 3'b111;
            #5;
            #5;
            Opcode = 3'b000;
            #330;
        end
    
        initial begin
            #5;
            #10;
            //乘法器
            clk = 1;
            rst = 0;
            #15;
            #330;
            //除法器
            clk = 1;
            rst = 0;
            #15;
            #330;
        end
    
        always begin
            #5;
            #10;
            //乘法器
            #5;
            rst = 1;
            #5;
            rst = 0;
            #10;
            #325;
            //除法器
            #5;
            rst = 1;
            #5;
            rst = 0;
            #10;
            #330;
        end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107

    add_sub_tb.v

    module add_sub_tb;
        // 定义信号
        reg  [31:0] Operand_X, Operand_Y;
        reg  [2:0]  Opcode;
        wire [63:0] Result;
    
        // 实例化被测试模块
        add_sub uut (
            .Operand_X(Operand_X),
            .Operand_Y(Operand_Y),
            .Opcode(Opcode),
            .Result(Result)
        );
        reg [63:0] res,res1;
        
        // 初始化信号
        initial begin 
            Operand_X = {$random}%{2^32};
            Operand_Y = {$random}%{2^32};
            Opcode = 3'd1;
            res = Operand_X+Operand_Y;
            #10;res1 = Result;
            if (res == res1) begin
                $display("[time@%t]: x=%h,y=%h,Opcode=%h -------PASS",$time,Operand_X,Operand_Y,Opcode);
            end else begin
                $display("[time@%t]ERROR: x=%h,y=%h,Opcode=%h",$time,Operand_X,Operand_Y,Opcode);
                //$finish;
            end
    
            #10; 
            Operand_X = 32'h0007; Operand_Y = 32'hfffffff4;
            Opcode = 3'd1;
            #10;res1 = Result; //7+(-12)= -5;
            if (64'hffff_ffff_ffff_fffb == res1) begin
                $display("[time@%t]: x=%h,y=%h,Opcode=%h -------PASS",$time,Operand_X,Operand_Y,Opcode);
            end else begin
                $display("[time@%t]ERROR: x=%h,y=%h,Opcode=%h",$time,Operand_X,Operand_Y,Opcode);
                //$finish;
            end
    
            #10; 
            Operand_X = 32'h7fff;
            Operand_Y = 32'h7fff;
            Opcode = 3'd1;
            #10;res1 = Result;
            if (64'h0000_FFFE == res1) begin
                $display("[time@%t]: x=%h,y=%h,Opcode=%h -------PASS",$time,Operand_X,Operand_Y,Opcode);
            end else begin
                $display("[time@%t]ERROR: x=%h,y=%h,Opcode=%h",$time,Operand_X,Operand_Y,Opcode);
                //$finish;
            end
    
            #10;
            Operand_X = 32'hffff_fffd;//-3
            Operand_Y = 32'hffff_fff4;//-12
            Opcode = 3'd2;
            #10;res1 = Result; //-3-(-12) = 9
            if (64'h0000_0009 == res1) begin
                $display("[time@%t]: x=%h,y=%h,Opcode=%h-------PASS",$time,Operand_X,Operand_Y,Opcode);
            end else begin
                $display("[time@%t]ERROR: x=%h,y=%h,Opcode=%h",$time,Operand_X,Operand_Y,Opcode);
                //$finish;
            end
    
            #10;
            Operand_X = 32'h8000_0000;//-2^31
            Operand_Y = 32'h0001;//1
            Opcode = 3'd2;
            #10;res1 = Result; //
            if (64'hffff_ffff_7fff_ffff == res1) begin
                $display("[time@%t]: x=%h,y=%h,Opcode=%h-------PASS",$time,Operand_X,Operand_Y,Opcode);
            end else begin
                $display("[time@%t]ERROR: x=%h,y=%h,Opcode=%h",$time,Operand_X,Operand_Y,Opcode);
                //$finish;
            end
            #20;
            $finish;
        end
    
    
    
    endmodule
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83

    tb_muler.v

    
    module tb_muler( );
        reg         rst,clk;
        wire        Busy,Cout;  
        reg [2:0]   Opcode;
        wire[63:0]  Result;
        reg [31:0]  Operand_X,Operand_Y;
        
        muler m1(
            .rst(rst),
            .clk(clk),
            .Opcode(Opcode),
            .Operand_X(Operand_X),
            .Operand_Y(Operand_Y),
            .Busy(Busy),
            .Cout(Cout),
            .Product(Result)
        );
    
        always begin
            #5; clk = ~clk;
        end
    
        initial begin
            #15;
            Operand_X = 32'b0000_0000_0000_0000_0000_0111_0110_0001;
            Operand_Y = 32'b0000_0000_0000_0000_1001_0111_0110_0001;
            // Operand_X = 32'h6;
            // Operand_Y = 32'h2;
            #330;
            #15;
            Operand_X = $random;
            Operand_Y = $random;
            #330;
            #15;
            Operand_X = 32'b1000_0000_0000_0000_0000_0111_0110_0001;
            Operand_Y = 32'b1000_0000_0000_0000_1001_0111_0110_0001;
            #330;
            #15;
            Operand_X = 32'b0111_1111_1111_1111_1111_1111_1111_1111;
            Operand_Y = 32'b1000_0100_1001_0111_1110_1100_0111_1000;
            #330;
        end
    
        always begin
            Opcode = 3'b000;
            #15;
            Opcode = 3'b110;
            #5;
            Opcode = 3'b000;
            #330;
        end
    
        initial begin
            clk = 0;
            rst = 0;
        end
    
        always begin
            #5;
            rst = 1;
            #5;
            rst = 0;
            #10;
            #330;
        end
    endmodule
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    tb_divider.v

    
    module tb_muler( );
        reg         rst,clk;
        wire        Busy,Cout;  
        reg [2:0]   Opcode;
        wire[63:0]  Result;
        reg [31:0]  Operand_X,Operand_Y;
        
        muler m1(
            .rst(rst),
            .clk(clk),
            .Opcode(Opcode),
            .Operand_X(Operand_X),
            .Operand_Y(Operand_Y),
            .Busy(Busy),
            .Cout(Cout),
            .Product(Result)
        );
    
        always begin
            #5; clk = ~clk;
        end
    
        initial begin
            #15;
            Operand_X = 32'b0000_0000_0000_0000_0000_0111_0110_0001;
            Operand_Y = 32'b0000_0000_0000_0000_1001_0111_0110_0001;
            // Operand_X = 32'h6;
            // Operand_Y = 32'h2;
            #330;
            #15;
            Operand_X = $random;
            Operand_Y = $random;
            #330;
            #15;
            Operand_X = 32'b1000_0000_0000_0000_0000_0111_0110_0001;
            Operand_Y = 32'b1000_0000_0000_0000_1001_0111_0110_0001;
            #330;
            #15;
            Operand_X = 32'b0111_1111_1111_1111_1111_1111_1111_1111;
            Operand_Y = 32'b1000_0100_1001_0111_1110_1100_0111_1000;
            #330;
        end
    
        always begin
            Opcode = 3'b000;
            #15;
            Opcode = 3'b110;
            #5;
            Opcode = 3'b000;
            #330;
        end
    
        initial begin
            clk = 0;
            rst = 0;
        end
    
        always begin
            #5;
            rst = 1;
            #5;
            rst = 0;
            #10;
            #330;
        end
    endmodule
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
  • 相关阅读:
    机器学习(三十二):Apriori 算法进行关联规则挖掘(一)
    Redis常用的五大数据类型及命令(String、List、Set、Hash、Zset)
    什么是人工通用智能(AGI)
    【2023】数据挖掘课程设计:基于TF-IDF的文本分类
    Webfunny大版本改造(mysql迁移至clickhouse)
    Mysql(列类型)
    【Python】《Python编程:从入门到实践 (第2版) 》笔记-汇总
    【机器学习】阿里云天池竞赛——工业蒸汽量预测(6)
    AWC 2023 10月11日在深盛大开幕 全球汽车人汇聚一堂定义汽车制造未来
    Linux之vim的使用详细解析
  • 原文地址:https://blog.csdn.net/qq_46264636/article/details/133500344