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