0

I currently am doing a assignment for my university on verilog, where we need to implement a single-cycle MIPS processor. Issue is, we are only given 3 Control-Bits on the ALU, just my group has no idea how to implement the multiplication and the bltz command from MIPS in verilog exactly due to not knowing how we can extend the Datapath as well as the Decoder minimally so that we can implement these commands.

Currently i am getting frustrated, because i got no idea how to do this in Verilog. I can post the code necessary as well. We sadly cannot add any more ins and outs due to the Sanitizer.

If we could know, how to expand the Datapath and the Decoder to get these extra R-Type instructions in without messing with the ALU-Control bits would be really appreciated, i do not really need the entire multiplication, mflo, mfhi and bltz code written, we just need to understand how to actually expand the necessary modules to get everything done in these 3 Control-Bits.

I thank you all for any Help given to us. Anything is really appreciated.

Datapath.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

Decoder.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

Core.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

Memory.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

Processor.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

Sanitizer.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
Mark Lauer
  • 51
  • 1
  • 4
  • I am currently stuck on how to add in a multiplication module as well as the jump return module in the R-Type instruction set without touching the ALU control bits inside the decoder, i got some help by saying that i might need to add onto some wires that lead to their own module and have a multiplexer sort out what kind of result i want, yet i do not know what i should do here to be exact. – Mark Lauer Jul 03 '20 at 13:53
  • If you're referring to jump register, `jr`, it does not use the ALU: it simply copies the value in `rs` to the `pc`. Although it is an R-Type, regwrite must be 0 for `jr` as it does not update a general purpose register; only the `pc` is updated. – Erik Eidt Jul 03 '20 at 14:13
  • It is also true for multiplication, that regwrite must be 0 as this does not update a general purpose register (just `hi` & `lo`, which are separate). `mfhi/lo` do update a general purpose register, but don't need any alu operation to be done. – Erik Eidt Jul 03 '20 at 14:20

0 Answers0