首页 > 解决方案 > Verilog。尝试使用 3-AluControl 位扩展数据路径和解码器以进行乘法和 bltz MIPS 指令

问题描述

我目前正在为我的大学做一项关于 verilog 的作业,我们需要在其中实现一个单周期 MIPS 处理器。问题是,我们在 ALU 上只获得了 3 个控制位,只是我的团队不知道如何在 verilog 中实现 MIPS 的乘法和 bltz 命令,因为不知道如何扩展数据路径和解码器最低限度,以便我们可以实现这些命令。

目前我很沮丧,因为我不知道如何在 Verilog 中做到这一点。我也可以发布必要的代码。遗憾的是,由于消毒剂的存在,我们无法再添加任何细节。

如果我们知道如何扩展数据路径和解码器以获取这些额外的 R-Type 指令而不弄乱 ALU 控制位将非常感激,我真的不需要整个乘法、mflo、mfhi 和 bltz 代码写,我们只需要了解如何实际扩展必要的模块以在这 3 个控制位中完成所有工作。

我感谢大家给予我们的任何帮助。任何事情都非常感谢。

数据路径.v

module Datapath(
    input         clk, reset,
    input         memtoreg,
    input         dobranch,
    input         alusrcbimm,
    input  [4:0]  destreg,
    input         regwrite,
    input         jump,
    input  [2:0]  alucontrol,
    output        zero,
    output [31:0] pc,
    input  [31:0] instr,
    output [31:0] aluout,
    output [31:0] writedata,
    input  [31:0] readdata
);
    wire [31:0] pc;
    wire [31:0] signimm;
    wire [31:0] srca, srcb, srcbimm;
    wire [31:0] result;

    // Fetch: Reiche PC an Instruktionsspeicher weiter und update PC
    ProgramCounter pcenv(clk, reset, dobranch, signimm, jump, instr[25:0], pc);

    // Execute:
    // (a) Wähle Operanden aus
    SignExtension se(instr[15:0], signimm);
    assign srcbimm = alusrcbimm ? signimm : srcb;
    // (b) Führe Berechnung in der ALU durch
      ArithmeticLogicUnit alu(srca, srcbimm, alucontrol, aluout, zero);
    // (c) Wähle richtiges Ergebnis aus
    assign result = memtoreg ? readdata : aluout;

    // Memory: Datenwort das zur (möglichen) Speicherung an den Datenspeicher übertragen wird
    assign writedata = srcb;

    // Write-Back: Stelle Operanden bereit und schreibe das jeweilige Resultat zurück
    RegisterFile gpr(clk, regwrite, instr[25:21], instr[20:16],
                   destreg, result, srca, srcb);
endmodule

module ProgramCounter(
    input         clk,
    input         reset,
    input         dobranch,
    input  [31:0] branchoffset,
    input         dojump,
    input  [25:0] jumptarget,
    output [31:0] progcounter
);
    reg  [31:0] pc;
    wire [31:0] incpc, branchpc, nextpc;

    // Inkrementiere Befehlszähler um 4 (word-aligned)
    Adder pcinc(.a(pc), .b(32'b100), .cin(1'b0), .y(incpc));
    // Berechne mögliches (PC-relatives) Sprungziel
    Adder pcbranch(.a(incpc), .b({branchoffset[29:0], 2'b00}), .cin(1'b0), .y(branchpc));
    // Wähle den nächsten Wert des Befehlszählers aus
    assign nextpc = dojump   ? {incpc[31:28], jumptarget, 2'b00} :
                    dobranch ? branchpc :
                               incpc;

    // Der Befehlszähler ist ein Speicherbaustein
    always @(posedge clk)
    begin
        if (reset) begin // Initialisierung mit Adresse 0x00400000
            pc <= 'h00400000;
        end else begin
            pc <= nextpc;
        end
    end

    // Ausgabe
    assign progcounter = pc;

endmodule

module RegisterFile(
    input         clk,
    input         we3,
    input  [4:0]  ra1, ra2, wa3,
    input  [31:0] wd3,
    output [31:0] rd1, rd2
);
    reg [31:0] registers[31:0];

    always @(posedge clk)
        if (we3) begin
            registers[wa3] <= wd3;
        end

    assign rd1 = (ra1 != 0) ? registers[ra1] : 0;
    assign rd2 = (ra2 != 0) ? registers[ra2] : 0;
endmodule

module Adder(
    input  [31:0] a, b,
    input         cin,
    output [31:0] y,
    output        cout
);
    assign {cout, y} = a + b + cin;
endmodule

module SignExtension(
    input  [15:0] a,
    output [31:0] y
);
    assign y = {{16{a[15]}}, a};
endmodule

module ArithmeticLogicUnit(
    input  [31:0] a, b,
    input  [2:0]  alucontrol,
    output [31:0] result,
    output        zero
);
    
    // TODO Implementierung der ALU
    reg [31:0] alu_result;
    
    assign result = alu_result;
    
    always @(*)
    begin
        case(alucontrol)
            
            3'b000: // SLT
            begin
                if (a < b)
                    alu_result = 1;
                else
                    alu_result = 0;
            end
            
            3'b001: // subtraction
            alu_result <= a - b;
            
            3'b101: // addition
            alu_result <= a + b;
            
            3'b110: // OR
            alu_result <= a | b;
            
            3'b111: // AND
            alu_result <= a & b;
            

            default: alu_result = a + b;
            
        endcase
        
        begin
            if (alu_result == 0)
                zero = 1'b1;
            else
                zero = 1'b0;
        end
    end
    

endmodule

解码器.v

module Decoder(
    input     [31:0] instr,      // Instruktionswort
    input            zero,       // Liefert aktuelle Operation im Datenpfad 0 als Ergebnis?
    output reg       memtoreg,   // Verwende ein geladenes Wort anstatt des ALU-Ergebis als Resultat
    output reg       memwrite,   // Schreibe in den Datenspeicher
    output reg       dobranch,   // Führe einen relativen Sprung aus
    output reg       alusrcbimm, // Verwende den immediate-Wert als zweiten Operanden
    output reg [4:0] destreg,    // Nummer des (möglicherweise) zu schreibenden Zielregisters
    output reg       regwrite,   // Schreibe ein Zielregister
    output reg       dojump,     // Führe einen absoluten Sprung aus
    output reg [2:0] alucontrol,  // ALU-Kontroll-Bits
    output reg [1:0] multcontrol // Mult-Kontroll-Bits
);
    // Extrahiere primären und sekundären Operationcode
    wire [5:0] op = instr[31:26];
    wire [5:0] funct = instr[5:0];

    always @*
    begin
        case (op)
            6'b000000: // Rtype Instruktion
                begin
                    regwrite = 1;
                    destreg = instr[15:11];
                    alusrcbimm = 0;
                    dobranch = 0;
                    memwrite = 0;
                    memtoreg = 0;
                    dojump = 0;
                    case (funct)
                        6'b100001: alucontrol = 3'b101; // TODO // Addition unsigned
                        6'b100011: alucontrol = 3'b001; // TODO // Subtraktion unsigned
                        6'b100100: alucontrol = 3'b111; // TODO // and
                        6'b100101: alucontrol = 3'b110; // TODO // or
                        6'b101011: alucontrol = 3'b000; // TODO // set-less-than unsigned
                        6'b011001: alucontrol = 3'b011; // TODO // multiplication unsigned
                        6'b010010: alucontrol = 3'b011; // TODO // move from low
                        6'b010000: alucontrol = 3'b011; //TODO //move from hi
                        default:   alucontrol = 3'b011; // TODO // undefiniert
                    endcase
                end
            6'b100011, // Lade Datenwort aus Speicher
            6'b101011: // Speichere Datenwort
                begin
                    regwrite = ~op[3];
                    destreg = instr[20:16];
                    alusrcbimm = 1;
                    dobranch = 0;
                    memwrite = op[3];
                    memtoreg = 1;
                    dojump = 0;
                    alucontrol = 3'b011; // TODO // Addition effektive Adresse: Basisregister + Offset
                end
            6'b000100: // Branch Equal
                begin
                    regwrite = 0;
                    destreg = 5'bx;
                    alusrcbimm = 0;
                    dobranch = zero; // Gleichheitstest
                    memwrite = 0;
                    memtoreg = 0;
                    dojump = 0;
                    alucontrol = 3'b001; // TODO // Subtraktion
                end
            6'b001001: // Addition immediate unsigned
                begin
                    regwrite = 1;
                    destreg = instr[20:16];
                    alusrcbimm = 1;
                    dobranch = 0;
                    memwrite = 0;
                    memtoreg = 0;
                    dojump = 0;
                    alucontrol = 3'b101; // TODO // Addition
                end
            6'b000010: // Jump immediate
                begin
                    regwrite = 0;
                    destreg = 5'bx;
                    alusrcbimm = 0;
                    dobranch = 0;
                    memwrite = 0;
                    memtoreg = 0;
                    dojump = 1;
                    alucontrol = 3'b011; // TODO
                end
            6'b001111: //Load upper immediate
                begin
                    regwrite = 1;
                    destres = instr[20:16];
                    alusrcbimm = 1;
                    dobranch = 0;
                    memwrite = 1;
                    memtoreg = 0;
                    dojump = 0;
                    alucontrol = 3'b011; // Bitshift.
                end
            6'b001101: //Bitwise or immediate
                begin
                    regwrite = 1;
                    destreg = instr[20:16];
                    alusrcbimm = 1;
                    dobranch = 0;
                    memwrite = 0;
                    memtoreg = 0;
                    dojump = 0;
                    alucontrol = 3'b110; //Bitwise or.
                end
            default: // Default Fall
                begin
                    regwrite = 1'bx;
                    destreg = 5'bx;
                    alusrcbimm = 1'bx;
                    dobranch = 1'bx;
                    memwrite = 1'bx;
                    memtoreg = 1'bx;
                    dojump = 1'bx;
                    alucontrol = 3'b011; // TODO
                end
        endcase
    end
endmodule

核心.v

module MIPScore(
    input clk,
    input reset,
    // Kommunikation Instruktionsspeicher
    output [31:0] pc,
    input  [31:0] instr,
    // Kommunikation Datenspeicher
    output        memwrite,
    output [31:0] aluout, multout, writedata, 
    input  [31:0] readdata
);
    wire       memtoreg, alusrcbimm, regwrite, dojump, dobranch, zero;
    wire [4:0] destreg;
    wire [2:0] alucontrol;

    Decoder decoder(instr, zero, memtoreg, memwrite,
                    dobranch, alusrcbimm, destreg,
                    regwrite, dojump, alucontrol);
    Datapath dp(clk, reset, memtoreg, dobranch,
                alusrcbimm, destreg, regwrite, dojump,
                alucontrol,
                zero, pc, instr,
                aluout, writedata, readdata);
endmodule

内存.v

// Read-only Instruktionsspeicher
module InstructionMemory(
    input  [5:0] addr,
    output [31:0] rd
);
    reg [31:0] INSTRROM[63:0];

    assign rd = INSTRROM[addr];
endmodule

// Beschreibarer Datenspeicher
module DataMemory(
    input clk,
    input we,
    input [5:0] addr,
    input [31:0] wd,
    output [31:0] rd
);
    reg [31:0] DATARAM[63:0];

    always @(posedge clk)
        if (we) begin
            DATARAM[addr] <= wd;
        end

    assign rd = DATARAM[addr];
endmodule

处理器.v

module Processor(
    input clk,
    input reset
);
    wire [31:0] pc, instr;
    wire [31:0] readdata, writedata;
    wire [31:0] dataaddr;
    wire datawrite;

    MIPScore mips(clk, reset,
        pc, instr,
        datawrite, dataaddr,
        writedata, readdata);

    // Binde Instruktions- und Datenspeicher an
    InstructionMemory imem(pc[7:2], instr);
    DataMemory dmem(clk, datawrite, dataaddr[7:2], writedata, readdata);
endmodule

消毒剂.v

module SanitizerHauptteil();

    // Instanziere das zu testende Verilog-Modul
  Processor proc(clk, reset);

    wire [31:0] a,b,s;
    wire zero;
    wire [2:0] ac;

    ArithmeticLogicUnit alu(
     .a(a), .b(b),
     .alucontrol(ac),
     .result(s),
     .zero(zero));


    integer idx;

    initial
        begin
            // Generiere eine Waveform-Ausgabe mit allen (nicht-Speicher) Variablen
            $dumpfile("simres.vcd");
            $dumpvars(0, proc.imem.INSTRROM[0]);
            $dumpvars(0, proc.dmem.DATARAM[0]);
            $dumpvars(0, proc.pc);
            $dumpvars(0, proc.instr);
            $dumpvars(0, proc.readdata);
            $dumpvars(0, proc.writedata);
            $dumpvars(0, proc.dataaddr);
            $dumpvars(0, proc.datawrite);
            $dumpvars(0, proc.mips);
            $dumpvars(0, proc.mips.decoder);
            $dumpvars(0, proc.mips.dp);
            $dumpvars(0, proc.mips.dp.gpr);
                for (idx = 0; idx < 32; idx = idx + 1) begin
                $dumpvars(0, proc.mips.dp.gpr.registers[idx]);
            end
                #1; $finish;
        end

endmodule

标签: mipsverilogdecoderinstructionsiverilog

解决方案


推荐阅读