mips - 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