自己动手写CPU_step6.1_算数运算指令

news2024/11/13 14:58:54

接上篇的加减指令,本篇主要实现CLZ、CLO、SLT等指令。

CLZ:从最高位开始数0的个数直到遇到1。

        例:0x0000,0001        CLZ指令结果:31        0x8000,ffff        CLZ指令结果是0

CLZ:从高位开始数1的个数直到遇到0。

        例:0xffff,0000        CLO指令结果:16        0x0000,ffff        CLO指令结果是0


修改ID模块

主要修改部分:

end else if (op == `EXE_SPECIAL2) begin     //由FUNC字段决定,操作码为011100的指令
            reg1_rden   <=  1'd1;
            reg2_rden   <=  1'd1;
            reg_wb      <=  1'd1;
            case (func)
                `EXE_CLZ:   begin
                        aluop   <=  `EXE_CLZ_FUNC;
                end
                `EXE_CLO:   begin
                        aluop   <=  `EXE_CLO_FUNC;
                end
                default:    begin
                        aluop   <=  7'd0;
                end
            endcase

整体代码:

`include "defines.v"
//译码阶段  对if_id传入的指令进行译码,分离出操作数和操作码
module id(
    input                           rst,
    input [`InstAddrBus]            pc,
    input [`InstDataBus]            inst,
    //读通用寄存器        读取        
    input [`RegDataBus]             reg1_data,
    input [`RegDataBus]             reg2_data,
    output reg                      reg1_rden,
    output reg                      reg2_rden,
    output reg [`RegAddrBus]        reg1_addr,  //源操作数1的地址
    output reg [`RegAddrBus]        reg2_addr,  //源操作数2的地址
    //送到ex阶段的值
    output reg [`RegDataBus]        reg1,       //源操作数1 32b
    output reg [`RegDataBus]        reg2,       //源操作数2 32b
    output reg                      reg_wb,     //写回目的寄存器标志    
    output reg [`RegAddrBus]        reg_wb_addr,//写回目的寄存器地址
    output reg [`AluOpBus]          aluop,      //操作码    
    //相邻指令的冲突,由EX阶段给出数据旁路
    input                           ex_wr_en,   //处于执行阶段的指令是否要写目的寄存器 
    input [`RegDataBus]             ex_wr_data, 
    input [`RegAddrBus]             ex_wr_addr,  
    //相隔一条指令的冲突,由MEM阶段给出数据旁路
    input                           mem_wr_en,  //处于访存阶段指令是否要写目的寄存器
    input [`RegDataBus]             mem_wr_data,
    input [`RegAddrBus]             mem_wr_addr
    );

wire [5:0] op = inst[31:26];         //从指令中获取操作码   高6位
wire [5:0] func = inst[5:0];        //从指令中获取功能号确定指令类型   低6位
wire [4:0] shmat = inst[10:6];      //部分移位位数不从寄存器取值,直接由shmat给出
reg [`RegDataBus] imm;              //立即数

always @ (*) begin
    if (rst) begin
        reg1_rden       <= 1'd0;
        reg2_rden       <= 1'd0;
        reg1_addr       <= 5'd0;
        reg2_addr       <= 5'd0;
        imm             <= 32'd0;
        reg_wb          <= 1'd0;
        reg_wb_addr     <= 5'd0;
        aluop           <= 7'd0;
    end else begin
        reg1_rden       <= 1'd0;
        reg2_rden       <= 1'd0;
        reg1_addr       <= inst[25:21];         //默认从指令中读取操作数1地址
        reg2_addr       <= inst[20:16];         //默认从指令中读取操作数2地址
        imm             <= 32'd0; 
        reg_wb          <= 1'd0;
        reg_wb_addr     <= inst[15:11];         //默认结果地址寄存器rd        
        aluop           <= 7'd0;                
        //操作类型
        if (op == `EXE_SPECIAL) begin
            reg1_rden   <= 1'd1;
            reg2_rden   <= 1'd1;
            reg_wb      <= 1'd1;
            case (func) 
                `EXE_AND:   begin
                        aluop   <=  `EXE_AND_FUNC;
                end            
                `EXE_OR:    begin
                        aluop   <=  `EXE_OR_FUNC;
                end
                `EXE_XOR:   begin
                        aluop   <=  `EXE_XOR_FUNC;
                end
                `EXE_NOR:   begin
                        aluop   <=  `EXE_NOR_FUNC;
                end
                `EXE_SLLV:  begin
                        aluop   <=  `EXE_SLL_FUNC;
                end
                `EXE_SRLV:  begin
                        aluop   <=  `EXE_SRLV_FUNC;
                end
                `EXE_SRAV:  begin
                        aluop   <=  `EXE_SRAV_FUNC;
                end
                `EXE_SLL:   begin
                        reg1_rden   <=  1'd0;
                        imm[4:0]    <=  shmat;
                        aluop       <=  `EXE_SLL_FUNC;
                end
                `EXE_SRL:   begin
                        reg1_rden   <=  1'd0;
                        imm[4:0]    <=  shmat;
                        aluop       <=  `EXE_SRL_FUNC;
                end
                `EXE_SRA:   begin
                        reg1_rden   <=  1'd0;
                        imm[4:0]    <=  shmat;
                        aluop       <=  `EXE_SRA_FUNC;
                end
                `EXE_MOVN:  begin
                        if (reg2 == 32'd0)  begin
                            reg_wb  <=  1'b0;
                        end else begin
                            reg_wb  <=  1'b1;
                            aluop   <=  `EXE_MOVN_FUNC;
                        end
                end
                `EXE_MOVZ:  begin
                        if (reg2 == 32'd0)  begin
                            reg_wb  <=  1'b1;
                            aluop   <=  `EXE_MOVZ_FUNC;
                        end else begin
                            reg_wb  <=  1'b0;
                        end
                end
                `EXE_MFHI:  begin
                        reg1_rden   <=  1'b0;
                        reg2_rden   <=  1'b0;
                        aluop       <=  `EXE_MFHI_FUNC;
                end
                `EXE_MFLO:  begin
                        reg1_rden   <=  1'b0;
                        reg2_rden   <=  1'b0;
                        aluop       <=  `EXE_MFLO_FUNC; 
                end
                `EXE_MTHI:  begin
                        reg2_rden   <=  1'b0;
                        reg_wb      <=  1'b0;
                        aluop       <=  `EXE_MTHI_FUNC;
                end
                `EXE_MTLO:  begin
                        reg2_rden   <=  1'b0;
                        reg_wb      <=  1'b0;
                        aluop       <=  `EXE_MTLO_FUNC;
                end
                `EXE_ADD:   begin
                        aluop   <=  `EXE_ADD_FUNC;
                end
                `EXE_ADDU:  begin
                        aluop   <=  `EXE_ADDU_FUNC;
                end
                `EXE_SUB:   begin
                        aluop   <=  `EXE_SUB_FUNC;
                end
                `EXE_SUBU:  begin
                        aluop   <=  `EXE_SUBU_FUNC;
                end
                `EXE_SLT:   begin
                        aluop   <=  `EXE_SLT_FUNC;
                end
                `EXE_SLTU:  begin
                        aluop   <=  `EXE_SLTU_FUNC;
                end
                default:    
                        aluop       <=  7'd0;
            endcase
        end else if (op == `EXE_SPECIAL2) begin     //由FUNC字段决定,操作码为011100的指令
            reg1_rden   <=  1'd1;
            reg2_rden   <=  1'd1;
            reg_wb      <=  1'd1;
            case (func)
                `EXE_CLZ:   begin
                        aluop   <=  `EXE_CLZ_FUNC;
                end
                `EXE_CLO:   begin
                        aluop   <=  `EXE_CLO_FUNC;
                end
                default:    begin
                        aluop   <=  7'd0;
                end
            endcase
        end else begin
            reg1_rden   <= 1'd1;  //需要读取操作数1 rs寄存器的值
            reg2_rden   <= 1'd0;  //不需要读取操作数2 rt寄存器值,
            imm         <= {16'h0, inst[15:0]};   
            reg_wb      <= 1'd1;
            reg_wb_addr <= inst[20:16];
            case (op)
                `EXE_ORI:   begin           //或指令  rs寄存器值是操作数1,imm是操作数2,结果放到rt寄存器
                        aluop   <=  `EXE_ORI_OP;           
                end
                `EXE_ANDI:  begin
                        aluop   <=  `EXE_ANDI_OP;
                end 
                `EXE_XORI:  begin
                        aluop   <=  `EXE_XORI_OP;
                end
                `EXE_LUI:   begin
                        reg1_rden   <= 1'b0;
                        aluop   <=  `EXE_LUI_OP;
                end
                `EXE_ADDI:  begin
                        aluop   <=  `EXE_ADDI_OP;
                end
                `EXE_ADDIU: begin
                        aluop   <=  `EXE_ADDIU_OP;
                end
                `EXE_SLTI:  begin
                        aluop   <=  `EXE_SLTI_OP;
                end
                `EXE_SLTIU: begin
                        aluop   <=  `EXE_SLTIU_OP;
                end
                default:
                        aluop   <=  7'd0;    
            endcase
        end
    end
end

always @ (*) begin
    if (rst) begin
        reg1 <= 32'd0;
    end else if (reg1_rden == 1'd1 && ex_wr_en == 1'd1 && ex_wr_addr == reg1_addr) begin    //执行阶段旁路
        reg1 <= ex_wr_data;
    end else if (reg1_rden == 1'd1 && mem_wr_en == 1'd1 && mem_wr_addr == reg1_addr) begin   //访存阶段旁路
        reg1 <= mem_wr_data;
    end else if (reg1_rden == 1'd1) begin   //从通用寄存器获取操作数
        reg1 <= reg1_data;
    end else if (reg1_rden == 1'd0) begin   //从指令中获取操作数
        reg1 <= imm;
    end else begin
        reg1 <= 32'd0;
    end
end
    
always @ (*) begin
    if (rst) begin
        reg2 <= 32'd0;
    end else if (reg2_rden == 1'd1 && ex_wr_en == 1'd1 && ex_wr_addr == reg2_addr) begin    //执行阶段旁路
        reg2 <= ex_wr_data;
    end else if (reg2_rden == 1'd1 && mem_wr_en == 1'd1 && mem_wr_addr == reg2_addr) begin   //访存阶段旁路
        reg2 <= mem_wr_data;
    end else if (reg2_rden == 1'd1) begin   //从通用寄存器获取操作数
        reg2 <= reg2_data;
    end else if (reg2_rden == 1'd0) begin   //从指令中获取操作数
        reg2 <= imm;
    end else begin
        reg2 <= 32'd0;
    end
end
    
endmodule

修改EX模块

主要修改部分:

//计算clz和clo的结果,0~32
wire [31:0]  clz_res    =   reg1[31] ? 0 : reg1[30] ? 1 : reg1[29] ? 2 : reg1[28] ? 3 : reg1[27] ? 4 : reg1[26] ? 5 :
                             reg1[25] ? 6 : reg1[24] ? 7 : reg1[23] ? 8 : reg1[22] ? 9 : reg1[21] ? 10 : reg1[20] ? 11 :
			                 reg1[19] ? 12 : reg1[18] ? 13 : reg1[17] ? 14 : reg1[16] ? 15 : reg1[15] ? 16 : reg1[14] ? 17 : 
							 reg1[13] ? 18 : reg1[12] ? 19 : reg1[11] ? 20 : reg1[10] ? 21 : reg1[9] ? 22 : reg1[8] ? 23 : 
						     reg1[7] ? 24 : reg1[6] ? 25 : reg1[5] ? 26 : reg1[4] ? 27 : reg1[3] ? 28 : reg1[2] ? 29 : 
							 reg1[1] ? 30 : reg1[0] ? 31 : 32 ;
wire [31:0] reg1_i     =    ~reg1;
wire [31:0] clo_res    =    reg1_i[31] ? 0 : reg1_i[30] ? 1 : reg1_i[29] ? 2 :reg1_i[28] ? 3 : reg1_i[27] ? 4 : 
                             reg1_i[26] ? 5 : reg1_i[25] ? 6 : reg1_i[24] ? 7 : reg1_i[23] ? 8 : reg1_i[22] ? 9 :
                             reg1_i[21] ? 10 : reg1_i[20] ? 11 : reg1_i[19] ? 12 : reg1_i[18] ? 13 : reg1_i[17] ? 14 : 
							 reg1_i[16] ? 15 : reg1_i[15] ? 16 : reg1_i[14] ? 17 : reg1_i[13] ? 18 : reg1_i[12] ? 19 :
							 reg1_i[11] ? 20 : reg1_i[10] ? 21 : reg1_i[9] ? 22 : reg1_i[8] ? 23 : reg1_i[7] ? 24 :
							 reg1_i[6] ? 25 : reg1_i[5] ? 26 : reg1_i[4] ? 27 : reg1_i[3] ? 28 : reg1_i[2] ? 29 : 
							 reg1_i[1] ? 30 : reg1_i[0] ? 31 : 32 ;
 `EXE_CLZ_FUNC:                  begin
                        reg_wb_data     <=  clz_res;
                end     
                `EXE_CLO_FUNC:                  begin
                        reg_wb_data     <=  clo_res;
                end      

整体代码:

`include "defines.v"
//执行阶段,根据译码阶段得到的操作码和操作数进行运算,得到结果
module ex(
    input                       rst,
    input [`AluOpBus]           aluop,
    input [`RegDataBus]         reg1,
    input [`RegDataBus]         reg2,
    input                       reg_wb_i,
    input [`RegAddrBus]         reg_wb_addr_i,
    output reg                  reg_wb_o,
    output reg [`RegAddrBus]    reg_wb_addr_o,
    output reg [`RegDataBus]    reg_wb_data,    //写回数据到目的寄存器
    //HILO寄存器
    input [`RegDataBus]         hi_reg_i,       //读取HI寄存器数据
    input [`RegDataBus]         lo_reg_i,       //读取LO寄存器数据
    output reg [`RegDataBus]    hi_reg_o,       //写入HI寄存器数据
    output reg [`RegDataBus]    lo_reg_o,       //写入LO寄存器数据
    output reg                  hi_wren,        //HI寄存器写使能        
    output reg                  lo_wren,        //LO寄存器写使能        
    //  HILO寄存器旁路                          
    input [`RegDataBus]         wb_hi_i,
    input [`RegDataBus]         wb_lo_i,
    input                       wb_hi_wren_i,  //有指令写HI,从写回阶段给出旁路(隔一条指令)
    input                       wb_lo_wren_i,  //有指令写LO,从写回阶段给出旁路(隔一条指令)
    input [`RegDataBus]         mem_hi_i,
    input [`RegDataBus]         mem_lo_i,
    input                       mem_hi_wren_i,  //有指令写HI,从访存阶段给出旁路(上一条指令)
    input                       mem_lo_wren_i  //有指令写LO,从访存阶段给出旁路(上一条指令)
    );

wire [31:0] mfhi_res = mem_hi_wren_i ? mem_hi_i : wb_hi_wren_i ? wb_hi_i : hi_reg_i; 
wire [31:0] mflo_res = mem_lo_wren_i ? mem_lo_i : wb_lo_wren_i ? wb_lo_i : lo_reg_i; 

//需要转换成补码的指令
wire [31:0] reg2_mux   =   ((aluop==`EXE_SUB_FUNC)||(aluop==`EXE_SUBU_FUNC)||(aluop==`EXE_SLT_FUNC)) ? (~reg2+1) : reg2;
wire [31:0] res        =   reg1 + reg2_mux;    //判断加减的结果是否溢出,减法转换成加法
//overflow flag 两个正数相加得负或两个负数相加得正则溢出
wire        of         =   ((!reg1[31]&&!reg2_mux[31]&&res[31])||(reg1[31]&&reg2_mux[31]&&!res[31])); 
//计算clz和clo的结果,0~32
wire [31:0]  clz_res    =   reg1[31] ? 0 : reg1[30] ? 1 : reg1[29] ? 2 : reg1[28] ? 3 : reg1[27] ? 4 : reg1[26] ? 5 :
                             reg1[25] ? 6 : reg1[24] ? 7 : reg1[23] ? 8 : reg1[22] ? 9 : reg1[21] ? 10 : reg1[20] ? 11 :
			                 reg1[19] ? 12 : reg1[18] ? 13 : reg1[17] ? 14 : reg1[16] ? 15 : reg1[15] ? 16 : reg1[14] ? 17 : 
							 reg1[13] ? 18 : reg1[12] ? 19 : reg1[11] ? 20 : reg1[10] ? 21 : reg1[9] ? 22 : reg1[8] ? 23 : 
						     reg1[7] ? 24 : reg1[6] ? 25 : reg1[5] ? 26 : reg1[4] ? 27 : reg1[3] ? 28 : reg1[2] ? 29 : 
							 reg1[1] ? 30 : reg1[0] ? 31 : 32 ;
wire [31:0] reg1_i     =    ~reg1;
wire [31:0] clo_res    =    reg1_i[31] ? 0 : reg1_i[30] ? 1 : reg1_i[29] ? 2 :reg1_i[28] ? 3 : reg1_i[27] ? 4 : 
                             reg1_i[26] ? 5 : reg1_i[25] ? 6 : reg1_i[24] ? 7 : reg1_i[23] ? 8 : reg1_i[22] ? 9 :
                             reg1_i[21] ? 10 : reg1_i[20] ? 11 : reg1_i[19] ? 12 : reg1_i[18] ? 13 : reg1_i[17] ? 14 : 
							 reg1_i[16] ? 15 : reg1_i[15] ? 16 : reg1_i[14] ? 17 : reg1_i[13] ? 18 : reg1_i[12] ? 19 :
							 reg1_i[11] ? 20 : reg1_i[10] ? 21 : reg1_i[9] ? 22 : reg1_i[8] ? 23 : reg1_i[7] ? 24 :
							 reg1_i[6] ? 25 : reg1_i[5] ? 26 : reg1_i[4] ? 27 : reg1_i[3] ? 28 : reg1_i[2] ? 29 : 
							 reg1_i[1] ? 30 : reg1_i[0] ? 31 : 32 ;

    always @ (*) begin
        if (rst) begin
            reg_wb_o        <= 1'd0;
            reg_wb_addr_o   <= 5'd0;
            reg_wb_data     <= 32'd0;
            hi_reg_o        <= 32'd0;
            lo_reg_o        <= 32'd0;
            hi_wren         <= 1'b0;
            lo_wren         <= 1'b0;
        end else begin
            reg_wb_o        <= reg_wb_i;
            reg_wb_addr_o   <= reg_wb_addr_i;
            reg_wb_data     <= 32'd0;
            hi_wren         <= 1'b0;
            lo_wren         <= 1'b0;
            hi_reg_o        <= 32'd0;
            lo_reg_o        <= 32'd0;
            case (aluop) 
                `EXE_ORI_OP,`EXE_OR_FUNC:       begin
                       reg_wb_data      <=  reg1 | reg2;
                end
                `EXE_ANDI_OP,`EXE_AND_FUNC:     begin
                        reg_wb_data     <=  reg1 & reg2;
                end
                `EXE_XORI_OP,`EXE_XOR_FUNC:     begin
                        reg_wb_data     <=  reg1 ^ reg2;
                end
                `EXE_LUI_OP:                    begin
                        reg_wb_data     <=  {reg2[15:0],reg2[31:16]};
                end
                `EXE_NOR_FUNC:                  begin
                        reg_wb_data     <=  ~(reg1 | reg2);
                end
                `EXE_SLL_FUNC,`EXE_SLLV_FUNC:   begin
                        reg_wb_data     <=  reg2 << reg1[4:0];
                end
                `EXE_SRL_FUNC,`EXE_SRLV_FUNC:   begin
                        reg_wb_data     <=  reg2 >> reg1[4:0];
                end
                `EXE_SRA_FUNC,`EXE_SRAV_FUNC:   begin       //算术移位也可以直接使用>>>
                        reg_wb_data     <=  ({32{reg2[31]}} << (6'd32 - {1'b0,reg1[4:0]})) | reg2 >> reg1[4:0];
                end
                `EXE_MOVN_FUNC,`EXE_MOVZ_FUNC:  begin
                        reg_wb_data     <=  reg1;
                end
                `EXE_MFHI_FUNC:                 begin
                        reg_wb_data     <=  mfhi_res;       
                end
                `EXE_MFLO_FUNC:                 begin
                        reg_wb_data     <=  mflo_res;
                end
                `EXE_MTHI_FUNC:                 begin
                        hi_wren         <=  1'b1;
                        hi_reg_o        <=  reg1;
                        lo_reg_o        <=  lo_reg_i;
                end
                `EXE_MTLO_FUNC:                 begin
                        lo_wren         <=  1'b1;
                        lo_reg_o        <=  reg1;
                        hi_reg_o        <=  hi_reg_i;
                end
                `EXE_ADD_FUNC,`EXE_SUB_FUNC,
                `EXE_ADDI_OP:                   begin       //加法减法都是加法实现
                        reg_wb_data     <=  res;
                        reg_wb_o        <=  of ? 0 : 1;
                end
                `EXE_ADDU_FUNC,`EXE_SUBU_FUNC,
                `EXE_ADDIU_OP:                  begin       //无符号数无需判断溢出,直接截断保存
                        reg_wb_data     <=  res;
                end
                `EXE_CLZ_FUNC:                  begin
                        reg_wb_data     <=  clz_res;
                end     
                `EXE_CLO_FUNC:                  begin
                        reg_wb_data     <=  clo_res;
                end      
                default:                        begin
                        reg_wb_o        <= 1'd0;
                        reg_wb_addr_o   <= 5'd0;
                        reg_wb_data     <= 32'd0;
                        hi_reg_o        <= 32'd0;
                        lo_reg_o        <= 32'd0;
                        hi_wren         <= 1'b0;
                        lo_wren         <= 1'b0;
                end
            endcase
        end
    end

endmodule

仿真测试1

34010001        ORI         赋值reg1为0000,0001
3c02ffff            LUI          赋值reg2为ffff,0000
70201820        CLZ        clz(reg1) => reg3         结果应该是31 
70402021        CLO        clo(reg2) => reg4        结果应该是16

由仿真结果可知,这两条指令执行正确。


下面是SLT指令的实现

SLT指令:(rs < rt) => rd(1/0)        如果rs小于rt寄存器的值,将1写入rd否则写0。

修改ID模块

这部分和之前类似,只给出部分代码

        if (op == `EXE_SPECIAL) begin
            case (func) 
                `EXE_SLT:   begin
                        aluop   <=  `EXE_SLT_FUNC;
                end
                `EXE_SLTU:  begin
                        aluop   <=  `EXE_SLTU_FUNC;
                end
        else begin
            case (op)
                `EXE_SLTI:  begin
                        aluop   <=  `EXE_SLTI_OP;
                end
                `EXE_SLTIU: begin
                        aluop   <=  `EXE_SLTIU_OP;
                end

修改EX模块

//计算reg1 < reg2的补码比较
assign reg1_lt_reg2 = ((aluop == `EXE_SLT_FUNC) || (aluop == `EXE_SLTI_OP)) ? ((reg1[31] && !reg2[31]) || 
                        (!reg1[31] && !reg2[31] && res[31]) || (reg1[31] && reg2[31] && res[31])) : (reg1 < reg2);
            case (aluop) 
                `EXE_SLT_FUNC,`EXE_SLTU_FUNC,
                `EXE_SLTI_OP,`EXE_SLTIU_OP:     begin
                        reg_wb_data     <=  reg1_lt_reg2;
                end

整体ID模块和EX模块

`include "defines.v"
//译码阶段  对if_id传入的指令进行译码,分离出操作数和操作码
module id(
    input                           rst,
    input [`InstAddrBus]            pc,
    input [`InstDataBus]            inst,
    //读通用寄存器        读取        
    input [`RegDataBus]             reg1_data,
    input [`RegDataBus]             reg2_data,
    output reg                      reg1_rden,
    output reg                      reg2_rden,
    output reg [`RegAddrBus]        reg1_addr,  //源操作数1的地址
    output reg [`RegAddrBus]        reg2_addr,  //源操作数2的地址
    //送到ex阶段的值
    output reg [`RegDataBus]        reg1,       //源操作数1 32b
    output reg [`RegDataBus]        reg2,       //源操作数2 32b
    output reg                      reg_wb,     //写回目的寄存器标志    
    output reg [`RegAddrBus]        reg_wb_addr,//写回目的寄存器地址
    output reg [`AluOpBus]          aluop,      //操作码    
    //相邻指令的冲突,由EX阶段给出数据旁路
    input                           ex_wr_en,   //处于执行阶段的指令是否要写目的寄存器 
    input [`RegDataBus]             ex_wr_data, 
    input [`RegAddrBus]             ex_wr_addr,  
    //相隔一条指令的冲突,由MEM阶段给出数据旁路
    input                           mem_wr_en,  //处于访存阶段指令是否要写目的寄存器
    input [`RegDataBus]             mem_wr_data,
    input [`RegAddrBus]             mem_wr_addr
    );

wire [5:0] op = inst[31:26];         //从指令中获取操作码   高6位
wire [5:0] func = inst[5:0];        //从指令中获取功能号确定指令类型   低6位
wire [4:0] shmat = inst[10:6];      //部分移位位数不从寄存器取值,直接由shmat给出
reg [`RegDataBus] imm;              //立即数

always @ (*) begin
    if (rst) begin
        reg1_rden       <= 1'd0;
        reg2_rden       <= 1'd0;
        reg1_addr       <= 5'd0;
        reg2_addr       <= 5'd0;
        imm             <= 32'd0;
        reg_wb          <= 1'd0;
        reg_wb_addr     <= 5'd0;
        aluop           <= 7'd0;
    end else begin
        reg1_rden       <= 1'd0;
        reg2_rden       <= 1'd0;
        reg1_addr       <= inst[25:21];         //默认从指令中读取操作数1地址
        reg2_addr       <= inst[20:16];         //默认从指令中读取操作数2地址
        imm             <= 32'd0; 
        reg_wb          <= 1'd0;
        reg_wb_addr     <= inst[15:11];         //默认结果地址寄存器rd        
        aluop           <= 7'd0;                
        //操作类型
        if (op == `EXE_SPECIAL) begin
            reg1_rden   <= 1'd1;
            reg2_rden   <= 1'd1;
            reg_wb      <= 1'd1;
            case (func) 
                `EXE_AND:   begin
                        aluop   <=  `EXE_AND_FUNC;
                end            
                `EXE_OR:    begin
                        aluop   <=  `EXE_OR_FUNC;
                end
                `EXE_XOR:   begin
                        aluop   <=  `EXE_XOR_FUNC;
                end
                `EXE_NOR:   begin
                        aluop   <=  `EXE_NOR_FUNC;
                end
                `EXE_SLLV:  begin
                        aluop   <=  `EXE_SLL_FUNC;
                end
                `EXE_SRLV:  begin
                        aluop   <=  `EXE_SRLV_FUNC;
                end
                `EXE_SRAV:  begin
                        aluop   <=  `EXE_SRAV_FUNC;
                end
                `EXE_SLL:   begin
                        reg1_rden   <=  1'd0;
                        imm[4:0]    <=  shmat;
                        aluop       <=  `EXE_SLL_FUNC;
                end
                `EXE_SRL:   begin
                        reg1_rden   <=  1'd0;
                        imm[4:0]    <=  shmat;
                        aluop       <=  `EXE_SRL_FUNC;
                end
                `EXE_SRA:   begin
                        reg1_rden   <=  1'd0;
                        imm[4:0]    <=  shmat;
                        aluop       <=  `EXE_SRA_FUNC;
                end
                `EXE_MOVN:  begin
                        if (reg2 == 32'd0)  begin
                            reg_wb  <=  1'b0;
                        end else begin
                            reg_wb  <=  1'b1;
                            aluop   <=  `EXE_MOVN_FUNC;
                        end
                end
                `EXE_MOVZ:  begin
                        if (reg2 == 32'd0)  begin
                            reg_wb  <=  1'b1;
                            aluop   <=  `EXE_MOVZ_FUNC;
                        end else begin
                            reg_wb  <=  1'b0;
                        end
                end
                `EXE_MFHI:  begin
                        reg1_rden   <=  1'b0;
                        reg2_rden   <=  1'b0;
                        aluop       <=  `EXE_MFHI_FUNC;
                end
                `EXE_MFLO:  begin
                        reg1_rden   <=  1'b0;
                        reg2_rden   <=  1'b0;
                        aluop       <=  `EXE_MFLO_FUNC; 
                end
                `EXE_MTHI:  begin
                        reg2_rden   <=  1'b0;
                        reg_wb      <=  1'b0;
                        aluop       <=  `EXE_MTHI_FUNC;
                end
                `EXE_MTLO:  begin
                        reg2_rden   <=  1'b0;
                        reg_wb      <=  1'b0;
                        aluop       <=  `EXE_MTLO_FUNC;
                end
                `EXE_ADD:   begin
                        aluop   <=  `EXE_ADD_FUNC;
                end
                `EXE_ADDU:  begin
                        aluop   <=  `EXE_ADDU_FUNC;
                end
                `EXE_SUB:   begin
                        aluop   <=  `EXE_SUB_FUNC;
                end
                `EXE_SUBU:  begin
                        aluop   <=  `EXE_SUBU_FUNC;
                end
                `EXE_SLT:   begin
                        aluop   <=  `EXE_SLT_FUNC;
                end
                `EXE_SLTU:  begin
                        aluop   <=  `EXE_SLTU_FUNC;
                end
                default:    
                        aluop       <=  7'd0;
            endcase
        end else if (op == `EXE_SPECIAL2) begin     //由FUNC字段决定,操作码为011100的指令
            reg1_rden   <=  1'd1;
            reg2_rden   <=  1'd1;
            reg_wb      <=  1'd1;
            case (func)
                `EXE_CLZ:   begin
                        aluop   <=  `EXE_CLZ_FUNC;
                end
                `EXE_CLO:   begin
                        aluop   <=  `EXE_CLO_FUNC;
                end
                default:    begin
                        aluop   <=  7'd0;
                end
            endcase
        end else begin
            reg1_rden   <= 1'd1;  //需要读取操作数1 rs寄存器的值
            reg2_rden   <= 1'd0;  //不需要读取操作数2 rt寄存器值,
            imm         <= {16'h0, inst[15:0]};   
            reg_wb      <= 1'd1;
            reg_wb_addr <= inst[20:16];
            case (op)
                `EXE_ORI:   begin           //或指令  rs寄存器值是操作数1,imm是操作数2,结果放到rt寄存器
                        aluop   <=  `EXE_ORI_OP;           
                end
                `EXE_ANDI:  begin
                        aluop   <=  `EXE_ANDI_OP;
                end 
                `EXE_XORI:  begin
                        aluop   <=  `EXE_XORI_OP;
                end
                `EXE_LUI:   begin
                        reg1_rden   <= 1'b0;
                        aluop   <=  `EXE_LUI_OP;
                end
                `EXE_ADDI:  begin
                        aluop   <=  `EXE_ADDI_OP;
                end
                `EXE_ADDIU: begin
                        aluop   <=  `EXE_ADDIU_OP;
                end
                `EXE_SLTI:  begin
                        aluop   <=  `EXE_SLTI_OP;
                end
                `EXE_SLTIU: begin
                        aluop   <=  `EXE_SLTIU_OP;
                end
                default:
                        aluop   <=  7'd0;    
            endcase
        end
    end
end

always @ (*) begin
    if (rst) begin
        reg1 <= 32'd0;
    end else if (reg1_rden == 1'd1 && ex_wr_en == 1'd1 && ex_wr_addr == reg1_addr) begin    //执行阶段旁路
        reg1 <= ex_wr_data;
    end else if (reg1_rden == 1'd1 && mem_wr_en == 1'd1 && mem_wr_addr == reg1_addr) begin   //访存阶段旁路
        reg1 <= mem_wr_data;
    end else if (reg1_rden == 1'd1) begin   //从通用寄存器获取操作数
        reg1 <= reg1_data;
    end else if (reg1_rden == 1'd0) begin   //从指令中获取操作数
        reg1 <= imm;
    end else begin
        reg1 <= 32'd0;
    end
end
    
always @ (*) begin
    if (rst) begin
        reg2 <= 32'd0;
    end else if (reg2_rden == 1'd1 && ex_wr_en == 1'd1 && ex_wr_addr == reg2_addr) begin    //执行阶段旁路
        reg2 <= ex_wr_data;
    end else if (reg2_rden == 1'd1 && mem_wr_en == 1'd1 && mem_wr_addr == reg2_addr) begin   //访存阶段旁路
        reg2 <= mem_wr_data;
    end else if (reg2_rden == 1'd1) begin   //从通用寄存器获取操作数
        reg2 <= reg2_data;
    end else if (reg2_rden == 1'd0) begin   //从指令中获取操作数
        reg2 <= imm;
    end else begin
        reg2 <= 32'd0;
    end
end
    
endmodule
`include "defines.v"
//执行阶段,根据译码阶段得到的操作码和操作数进行运算,得到结果
module ex(
    input                       rst,
    input [`AluOpBus]           aluop,
    input [`RegDataBus]         reg1,
    input [`RegDataBus]         reg2,
    input                       reg_wb_i,
    input [`RegAddrBus]         reg_wb_addr_i,
    output reg                  reg_wb_o,
    output reg [`RegAddrBus]    reg_wb_addr_o,
    output reg [`RegDataBus]    reg_wb_data,    //写回数据到目的寄存器
    //HILO寄存器
    input [`RegDataBus]         hi_reg_i,       //读取HI寄存器数据
    input [`RegDataBus]         lo_reg_i,       //读取LO寄存器数据
    output reg [`RegDataBus]    hi_reg_o,       //写入HI寄存器数据
    output reg [`RegDataBus]    lo_reg_o,       //写入LO寄存器数据
    output reg                  hi_wren,        //HI寄存器写使能        
    output reg                  lo_wren,        //LO寄存器写使能        
    //  HILO寄存器旁路                          
    input [`RegDataBus]         wb_hi_i,
    input [`RegDataBus]         wb_lo_i,
    input                       wb_hi_wren_i,  //有指令写HI,从写回阶段给出旁路(隔一条指令)
    input                       wb_lo_wren_i,  //有指令写LO,从写回阶段给出旁路(隔一条指令)
    input [`RegDataBus]         mem_hi_i,
    input [`RegDataBus]         mem_lo_i,
    input                       mem_hi_wren_i,  //有指令写HI,从访存阶段给出旁路(上一条指令)
    input                       mem_lo_wren_i  //有指令写LO,从访存阶段给出旁路(上一条指令)
    );

wire [31:0] mfhi_res = mem_hi_wren_i ? mem_hi_i : wb_hi_wren_i ? wb_hi_i : hi_reg_i; 
wire [31:0] mflo_res = mem_lo_wren_i ? mem_lo_i : wb_lo_wren_i ? wb_lo_i : lo_reg_i; 

//需要转换成补码的指令
wire [31:0] reg2_mux   =   ((aluop==`EXE_SUB_FUNC)||(aluop==`EXE_SUBU_FUNC)||(aluop==`EXE_SLT_FUNC)) ? (~reg2+1) : reg2;
wire [31:0] res        =   reg1 + reg2_mux;    //判断加减的结果是否溢出,减法转换成加法
//overflow flag 两个正数相加得负或两个负数相加得正则溢出
wire        of         =   ((!reg1[31]&&!reg2_mux[31]&&res[31])||(reg1[31]&&reg2_mux[31]&&!res[31])); 
//计算clz和clo的结果,0~32
wire [31:0]  clz_res    =   reg1[31] ? 0 : reg1[30] ? 1 : reg1[29] ? 2 : reg1[28] ? 3 : reg1[27] ? 4 : reg1[26] ? 5 :
                             reg1[25] ? 6 : reg1[24] ? 7 : reg1[23] ? 8 : reg1[22] ? 9 : reg1[21] ? 10 : reg1[20] ? 11 :
			                 reg1[19] ? 12 : reg1[18] ? 13 : reg1[17] ? 14 : reg1[16] ? 15 : reg1[15] ? 16 : reg1[14] ? 17 : 
							 reg1[13] ? 18 : reg1[12] ? 19 : reg1[11] ? 20 : reg1[10] ? 21 : reg1[9] ? 22 : reg1[8] ? 23 : 
						     reg1[7] ? 24 : reg1[6] ? 25 : reg1[5] ? 26 : reg1[4] ? 27 : reg1[3] ? 28 : reg1[2] ? 29 : 
							 reg1[1] ? 30 : reg1[0] ? 31 : 32 ;
wire [31:0] reg1_i     =    ~reg1;
wire [31:0] clo_res    =    reg1_i[31] ? 0 : reg1_i[30] ? 1 : reg1_i[29] ? 2 :reg1_i[28] ? 3 : reg1_i[27] ? 4 : 
                             reg1_i[26] ? 5 : reg1_i[25] ? 6 : reg1_i[24] ? 7 : reg1_i[23] ? 8 : reg1_i[22] ? 9 :
                             reg1_i[21] ? 10 : reg1_i[20] ? 11 : reg1_i[19] ? 12 : reg1_i[18] ? 13 : reg1_i[17] ? 14 : 
							 reg1_i[16] ? 15 : reg1_i[15] ? 16 : reg1_i[14] ? 17 : reg1_i[13] ? 18 : reg1_i[12] ? 19 :
							 reg1_i[11] ? 20 : reg1_i[10] ? 21 : reg1_i[9] ? 22 : reg1_i[8] ? 23 : reg1_i[7] ? 24 :
							 reg1_i[6] ? 25 : reg1_i[5] ? 26 : reg1_i[4] ? 27 : reg1_i[3] ? 28 : reg1_i[2] ? 29 : 
							 reg1_i[1] ? 30 : reg1_i[0] ? 31 : 32 ;
//计算reg1 < reg2的补码比较
assign reg1_lt_reg2 = ((aluop == `EXE_SLT_FUNC) || (aluop == `EXE_SLTI_OP)) ? ((reg1[31] && !reg2[31]) || 
                        (!reg1[31] && !reg2[31] && res[31]) || (reg1[31] && reg2[31] && res[31])) : (reg1 < reg2);
			                   
    always @ (*) begin
        if (rst) begin
            reg_wb_o        <= 1'd0;
            reg_wb_addr_o   <= 5'd0;
            reg_wb_data     <= 32'd0;
            hi_reg_o        <= 32'd0;
            lo_reg_o        <= 32'd0;
            hi_wren         <= 1'b0;
            lo_wren         <= 1'b0;
        end else begin
            reg_wb_o        <= reg_wb_i;
            reg_wb_addr_o   <= reg_wb_addr_i;
            reg_wb_data     <= 32'd0;
            hi_wren         <= 1'b0;
            lo_wren         <= 1'b0;
            hi_reg_o        <= 32'd0;
            lo_reg_o        <= 32'd0;
            case (aluop) 
                `EXE_ORI_OP,`EXE_OR_FUNC:       begin
                       reg_wb_data      <=  reg1 | reg2;
                end
                `EXE_ANDI_OP,`EXE_AND_FUNC:     begin
                        reg_wb_data     <=  reg1 & reg2;
                end
                `EXE_XORI_OP,`EXE_XOR_FUNC:     begin
                        reg_wb_data     <=  reg1 ^ reg2;
                end
                `EXE_LUI_OP:                    begin
                        reg_wb_data     <=  {reg2[15:0],reg2[31:16]};
                end
                `EXE_NOR_FUNC:                  begin
                        reg_wb_data     <=  ~(reg1 | reg2);
                end
                `EXE_SLL_FUNC,`EXE_SLLV_FUNC:   begin
                        reg_wb_data     <=  reg2 << reg1[4:0];
                end
                `EXE_SRL_FUNC,`EXE_SRLV_FUNC:   begin
                        reg_wb_data     <=  reg2 >> reg1[4:0];
                end
                `EXE_SRA_FUNC,`EXE_SRAV_FUNC:   begin       //算术移位也可以直接使用>>>
                        reg_wb_data     <=  ({32{reg2[31]}} << (6'd32 - {1'b0,reg1[4:0]})) | reg2 >> reg1[4:0];
                end
                `EXE_MOVN_FUNC,`EXE_MOVZ_FUNC:  begin
                        reg_wb_data     <=  reg1;
                end
                `EXE_MFHI_FUNC:                 begin
                        reg_wb_data     <=  mfhi_res;       
                end
                `EXE_MFLO_FUNC:                 begin
                        reg_wb_data     <=  mflo_res;
                end
                `EXE_MTHI_FUNC:                 begin
                        hi_wren         <=  1'b1;
                        hi_reg_o        <=  reg1;
                        lo_reg_o        <=  lo_reg_i;
                end
                `EXE_MTLO_FUNC:                 begin
                        lo_wren         <=  1'b1;
                        lo_reg_o        <=  reg1;
                        hi_reg_o        <=  hi_reg_i;
                end
                `EXE_ADD_FUNC,`EXE_SUB_FUNC,
                `EXE_ADDI_OP:                   begin       //加法减法都是加法实现
                        reg_wb_data     <=  res;
                        reg_wb_o        <=  of ? 0 : 1;
                end
                `EXE_ADDU_FUNC,`EXE_SUBU_FUNC,
                `EXE_ADDIU_OP:                  begin       //无符号数无需判断溢出,直接截断保存
                        reg_wb_data     <=  res;
                end
                `EXE_CLZ_FUNC:                  begin
                        reg_wb_data     <=  clz_res;
                end     
                `EXE_CLO_FUNC:                  begin
                        reg_wb_data     <=  clo_res;
                end      
                `EXE_SLT_FUNC,`EXE_SLTU_FUNC,
                `EXE_SLTI_OP,`EXE_SLTIU_OP:     begin
                        reg_wb_data     <=  reg1_lt_reg2;
                end
                default:                        begin
                        reg_wb_o        <= 1'd0;
                        reg_wb_addr_o   <= 5'd0;
                        reg_wb_data     <= 32'd0;
                        hi_reg_o        <= 32'd0;
                        lo_reg_o        <= 32'd0;
                        hi_wren         <= 1'b0;
                        lo_wren         <= 1'b0;
                end
            endcase
        end
    end

endmodule

仿真测试

34010001        给reg1赋值0000,0001
3c02ffff            给reg2赋值ffff,0000
0022182b       SLTU      (reg1 < reg2) => reg3        无符号
0022182a       SLT        (reg1 < reg2) => reg3        有符号
2844ffff           SLTI       (reg2 < 0000ffff) => reg4    有符号
2c44ffff           SLTIU     (reg2 < 0000ffff) => reg4    无符号 

由仿真结果可知,符合我们预期结果,这四条比较指令也没问题。

下一步实现乘除指令!

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

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

相关文章

告别繁琐,拥抱FileGee——你的高效生活助手!

前言 科技决不是一种自私自利的享乐。有幸能够致力于科技研究的人&#xff0c;首先应该拿自己的学识为人类服务。——马克思&#xff0c;这句话提醒我们&#xff0c;在数字化时代&#xff0c;高效管理自己的数据与时间同样重要。FileGee&#xff0c;正是在这样的背景下应运而生…

【最大上升子序列和】

题目 前置芝士 1. erase 函数 erase(iterator pos)&#xff1a;删除单个元素&#xff0c;其中 pos 是要删除元素的迭代器。 erase(iterator first, iterator last)&#xff1a;删除从 first 到 last&#xff08;不包括 last&#xff09;之间的所有元素。 2. unique 函数 uniqu…

emmc协议

一、简介 1.1 简介 嵌入式多媒体卡&#xff08;Embedded Multimedia Card, eMMC&#xff09;是由 JEDEC 协会所订立&#xff0c;将 MMC controller 和 NAND Flash 封装到一个芯片中&#xff0c;简化存储器的使用和电路板的设计。 1.2 信号 singledescriptionclkclockdata…

Qt22双缓冲机制

Qt22双缓冲机制 知识点drawwidgetdrawwidget.hdrawwidget.cpp mainwindowmainwindow.hmainwindow.cpp main.cpp运行图 知识点 双缓冲就是在内存区申请一块缓存&#xff1b;然后显卡直接从这块内存读取数据.。 这样就不用鼠标边画&#xff0c;经过IO来读取这个环节&#xff1b;…

2024杭电6

1001.造花&#xff08;简单版&#xff09; 题意&#xff1a; 菊花图&#xff1a;n-1个节点都连接同一节点的树。 给定一棵树&#xff0c;删掉一个节点和连向这个点的所有边&#xff0c;使剩下两个连通块都构成菊花图&#xff0c;问是否可以做到。 题解&#xff1a; 菊花图只有…

算法练习题07:无重复字符的最长子串

我们可以使用 滑动窗口 的方法来解决这个问题。这是一种高效的算法&#xff0c;能在 O(n) 的时间复杂度内完成任务。以下是具体的解题思路&#xff1a; 1. 滑动窗口的概念 滑动窗口的想法是使用两个指针&#xff08;通常称为左指针 i 和右指针 j&#xff09;来表示一个窗口。…

秋招/春招投递公司记录表格

最近在准备秋招&#xff0c;在各个平台投递秋招简历&#xff0c;什么官网&#xff0c;邮箱&#xff0c;boss&#xff0c;应届生各个平台上&#xff0c;投递的平台比较多&#xff0c;比较乱&#xff0c;因此自己想将这些平台投递记录都收集到一个表格上&#xff0c;所以在腾讯文…

基于Java+MySQL实现在线书店订购系统

一、引言 1.1 编写目的 编写详细设计说明书是软件开发过程必不可少的部分&#xff0c;其目的是为了使开发人员在完成概要设计说明书的基础上完成概要设计规定的各项模块的具体实现的设计工作。同时也是开发人员和最终客户进行需求交流的有效手段。 1.2 背景 开发软件系统名…

数据结构——排序上

1.排序的概念及其运用 1.1排序的概念 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作 稳定性&#xff1a;假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键字的记录&a…

多目标应用:基于自组织分群的多目标粒子群优化算法(SS-MOPSO)的移动机器人路径规划研究(提供MATLAB代码)

一、机器人路径规划介绍 移动机器人&#xff08;Mobile robot&#xff0c;MR&#xff09;的路径规划是 移动机器人研究的重要分支之&#xff0c;是对其进行控制的基础。根据环境信息的已知程度不同&#xff0c;路径规划分为基于环境信息已知的全局路径规划和基于环境信息未知或…

美国海外仓可以用哪家海外仓系统好?

随着全球贸易的增长&#xff0c;美国已经成为了海外仓储业务的一个重要市场。美国海外仓的数量不断增加&#xff0c;竞争也愈加激烈。为应对这种竞争&#xff0c;并优化仓储和供应链管理&#xff0c;WMS&#xff08;仓库管理系统&#xff09;成为了海外仓的重要工具。 一、WMS…

Wx64ST:一款轻松可修改的C语言Shellcode模板

关于windows_x64_shellcode_template windows_x64_shellcode_template简称为Wx64ST&#xff0c;它是一款功能强大的Shellcode模板&#xff0c;该模板基于C语言编写&#xff0c;其简单、可扩展和易于修改等特性可以帮助广大安全研究人员轻松开发适用于Windows x64的Shellcode。…

kali (linux) 安装配置 共享文件夹 samba

一、samba 安装 sudo apt-get install samba 二、启动samba 服务 systemctl enable nmb systemctl enable smb systemctl start nmb systemctl start smb 三、查看 samba状态 systemctl status nmb systemctl status smb 四、创建共享文件夹 &#xff0c;并修改权限 …

技术指南:5分钟零成本实现本地AI知识库搭建

你一定经历过各种通用大模型一本正经胡说八道的时候吧&#xff0c;AI一通丝滑输出让人真假难辨&#xff0c;防不胜防。这种情况被称为AI幻觉。 大模型产生幻觉不幸“翻车”的原因很大程度上是“先天不足”&#xff0c;例如训练时来自特定领域的训练数据就比较缺失或存在偏差等…

20-22 - 打造专业的编译环境

---- 整理自狄泰软件唐佐林老师课程 文章目录 1. 大型项目的编译&#xff08;无第三方库&#xff09;1.1 大型项目的目录结构&#xff08;无第三方库&#xff09;1.2 项目结构设计分析1.3 需要打造的编译环境1.4 解决方案设计 2. 第 1 阶段任务2.1 关键的实现要点2.2 模块 make…

MES管理系统如何提升产品质量与可追溯性

在智能制造的新纪元里&#xff0c;MES管理系统正逐步崭露头角&#xff0c;成为驱动制造业转型升级的幕后英雄。MES管理系统不仅重新定义了生产过程的管理与控制方式&#xff0c;还以数据为驱动&#xff0c;引领着制造业迈向更高效、更智能、更可持续的未来。 智能制造的赋能者&…

U-Mail垃圾邮件过滤网关‍是如何过滤垃圾邮件的?

随着互联网的普及&#xff0c;垃圾邮件已经成为计算机网络安全的又一个公害。因此&#xff0c;反垃圾邮件已经成为互联网应用研究中一个重要课题。为了防止垃圾邮件首先要学会保护自己的邮件地址&#xff0c;避免在网上随意登记和使用邮件地址&#xff0c;预防垃圾邮件骚扰。其…

ALV Tree Control树控件

ALV Tree Control CL_GUI_ALV_TREE 效果&#xff1a; 自定义函数调用&#xff0c;在函数里画屏幕定义树控件显示 FUNCTION ZFI_YSYWLX_HELP_NEW . *"---------------------------------------------------------------------- *"*"本地接口&#xff1a; *&qu…

zset使用lua实现取最高分数中的随机成员

zset使用lua实现取最高分数中的随机成员 这种场景适用队列中不想要先入先出、先入后出因为zset的命令都是带有排序功能的&#xff0c;所以取值时要不从大到小要不从小到大所以我使用lua实现随机取成员使用lua是因为可以保持原子性在执行过程中Lua脚本是不会被其他命令或请求打…