LordGregGreg
11-04-2007, 09:35 AM
Ok, so verilog is a hardware development language, which means i can write a program to create actual hard ware. Yeah, i know, funny how that works. But, hers the scoop, I need to program me a processor, and it needs to be able to handle most mips (assembly language) commands.
So far, it compiles, lol, and might work. I need to make a test bench, i dont need help, and this is just for some people to look at and say "wow, thats cool, im glad i dont have to do that"
oh yeah, its a piplined processor, but thats about as good as it gets, everyhting else is basic and simple and just.. low performance.
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: World Domination
// Engineer: Greg Hendrickson
//
// Create Date: 23:09:34 11/03/2007
// Design Name: Pipelined CPU Stage 1
// Module Name: CPU
// Project Name: Comp Arch Final Project
// Target Devices: Desktop
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Revision 0.02 - Syntax errors fixed
// Revision 0.03 - Logical Errors Fixed
// Revision 0.04 - Rest of code understood
// Revision 0.05 - Added in and understood forwarding the a and b
// Revision 0.06 - Could not find any errors in the forwarding code
// Revision 0.07 - Added in the stalls
// Revision 0.08 - Fixed minor "no-op" syntax error
// Revision 0.09 - Found and fixed instruction forwarding error. Cant do all at end (stall fails)
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module CPU (clock);
// Instruction opcodes
parameter LW = 6'b100011, SW = 6'b101011, BEQ=6'b000100, noop = 32'b00000_100000, ALUop=6''b0;
input clock;
reg[31:0] PC, Regs[0:31], IMemory[0:23], DMemory[0:23], // separate memories (they were 1023, i made them, 23)
IFIDIR, IDEXA, IDEXB, IDEXIR, EXMEMIR, EXMEMB, // pipeline registers
EXMEMALUOut, MEMWBValue, MEMWBIR; // pipeline registers
wire [4:0] IDEXrs, IDEXrt, EXMEMrd, MEMWBrd, MEMWBrt; // Access register fields
wire [5:0] EXMEMop, MEMWBop, IDEXop; // Access opcodes
wire [31:0] Ain, Bin; // the ALU inputs
// declare the bypass signals
wire bypassAfromMEM, bypassAfromALUinWB,bypassBfromMEM, bypassBfromALUinWB,
bypassAfromLWinWB, bypassBfromLWinWB;
// These assignment define fields from the pipeline registers
assign IDEXrs = IDEXIR[25:21]; // rs field
assign IDEXrt = IDEXIR[15:11]; // rt field
assign EXMEMrd = EXMEMIR[15:11]; // rd field
assign MEMWBrd = MEMWBIR[15:11]; //rd field [changed from 20;16] TO 15;11 //double checked, yes
assign MEMWBrt = MEMWBIR[25:20]; //rt field--used for loads
assign EXMEMop = EXMEMIR[31:26]; // the opocde
assign MEMWBop = MEMWBIR[31:26]; // the opcode
assign IDEXop = IDEXIR[31:26] ; // the opcode
// Inputs to the ALU come directly from the ID/EX pipeline registers
assign Ain = IDEXA;
assign Bin = IDEXB;
// The bypass to input A from the MEM stage for an ALU operation
assign bypassAfromMEM = (IDEXrs == EXMEMrd) & (IDEXrs!=0) & (EXMEMop==ALUop); // yes, bypass
// The bypass to input Bfrom the MEM stage for an ALU operation
assign bypassBfromMEM = (IDEXrt== EXMEMrd)&(IDEXrt!=0) & (EXMEMop==ALUop); // yes, bypass
// The bypass to input A from the WB stage for an ALU operation
assign bypassAfromALUinWB =( IDEXrs == MEMWBrd) & (IDEXrs!=0) & (MEMWBop==ALUop);
// The bypass to input B from the WB stage for an ALU operation
assign bypassBfromALUinWB = (IDEXrt==MEMWBrd) & (IDEXrt!=0) & (MEMWBop==ALUop);
// The bypass to input A from the WB stage for an LW operation
assign bypassAfromLWinWB =( IDEXrs ==MEMWBIR[20:16]) & (IDEXrs!=0) & (MEMWBop==LW);
// The bypass to input B from the WB stage for an LW operation
assign bypassBfromLWinWB = (IDEXrt==MEMWBIR[20:16]) & (IDEXrt!=0) & (MEMWBop==LW);
// The A input to the ALU is bypassed from MEM if there is a bypass there,
// Otherwise from WB if there is a bypass there, and otherwise comes from the IDEX register
assign Ain = bypassAfromMEM? EXMEMALUOut :
(bypassAfromALUinWB | bypassAfromLWinWB)? MEMWBValue : IDEXA;
// The B input to the ALU is bypassed from MEM if there is a bypass there,
// Otherwise from WB if there is a bypass there, and otherwise comes from the IDEX register
assign Bin = bypassBfromMEM? EXMEMALUOut :
(bypassBfromALUinWB | bypassBfromLWinWB)? MEMWBValue: IDEXB;
// The signal for detecting a stall based on the use of a result from LW
assign stall = (MEMWBIR[31:26]==LW) && // source instruction is a load
((((IDEXop==LW)|(IDEXop==SW)) && (IDEXrs==MEMWBrd)) | // stall for address calc
((IDEXop==ALUop) && ((IDEXrs==MEMWBrd)|(IDEXrt==MEMWBrd)))); // ALU use
reg [5:0] i; //used to initialize registers
initial begin
PC = 0;
IFIDIR=noop; IDEXIR=noop; EXMEMIR=noop; MEMWBIR=noop; // put no-ops in pipeline registers
for (i=0;i<=31;i=i+1) Regs[i] = i; //initialize registers--just so they aren?t cares
end
always @ (posedge clock) begin
// Remember that ALL these actions happen every pipestage and with the use of <= they happen in parallel!
// first instruction in the pipeline is being fetched
if (~stall) begin // the first three pipeline stages stall if there is a load hazard
IFIDIR <= IMemory[PC>>2];
PC <= PC + 4;
//end // Fetch & increment PC
// second instruction in pipeline is fetching registers
IDEXA <= Regs[IFIDIR[25:21]]; IDEXB <= Regs[IFIDIR[20:16]]; // get two registers
// third instruction is doing address calculation or ALU operation
if ((IDEXop==LW) |(IDEXop==SW)) // address calculation
EXMEMALUOut <= IDEXA +{{16{IDEXIR[15]}}, IDEXIR[15:0]};
else if (IDEXop==ALUop) case (IDEXIR[5:0]) //case for the various R-type instructions
32: EXMEMALUOut <= Ain + Bin; //add operation
16: EXMEMALUOut <= Ain - Bin; //subtract operation
8: EXMEMALUOut <= Ain & Bin; //and operation
7: EXMEMALUOut <= ~(Ain & Bin); //nadd operation
4: EXMEMALUOut <= Ain | Bin; //or operation
3: EXMEMALUOut <= ~(Ain | Bin); //nor operation
2: EXMEMALUOut <= ((Ain - Bin)==0)?1:0; //seqz operation
1: EXMEMALUOut <= Ain < Bin ? 1:0; //slt operation
default: ; //other R-type operations: subtract, SLT, etc.
endcase
IDEXIR <= IFIDIR; EXMEMIR <= IDEXIR; EXMEMB <= IDEXB;// passing along instructions
end
else EXMEMIR <= noop; //Freeze first three stages of pipeline; inject a nop into the EX output
//Mem stage of pipeline
if (EXMEMop==ALUop)
MEMWBValue <= EXMEMALUOut; //pass along ALU result
else if (EXMEMop == LW)
MEMWBValue <= DMemory[EXMEMALUOut>>2];
else if (EXMEMop == SW)
DMemory[EXMEMALUOut>>2] <=EXMEMB; //store [from top, it is 15:0)stage3
// the WB stage
if ((MEMWBop==ALUop) & (MEMWBrd != 0)) // update registers if ALU operation and destination not 0
Regs[MEMWBrd] <= MEMWBValue; // ALU operation
else if ((EXMEMop == LW)& (MEMWBrt != 0)) // Update registers if load and destination not 0
Regs[MEMWBrt] <= MEMWBValue;
MEMWBIR <= EXMEMIR; //pass along
end
endmodule
So far, it compiles, lol, and might work. I need to make a test bench, i dont need help, and this is just for some people to look at and say "wow, thats cool, im glad i dont have to do that"
oh yeah, its a piplined processor, but thats about as good as it gets, everyhting else is basic and simple and just.. low performance.
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: World Domination
// Engineer: Greg Hendrickson
//
// Create Date: 23:09:34 11/03/2007
// Design Name: Pipelined CPU Stage 1
// Module Name: CPU
// Project Name: Comp Arch Final Project
// Target Devices: Desktop
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Revision 0.02 - Syntax errors fixed
// Revision 0.03 - Logical Errors Fixed
// Revision 0.04 - Rest of code understood
// Revision 0.05 - Added in and understood forwarding the a and b
// Revision 0.06 - Could not find any errors in the forwarding code
// Revision 0.07 - Added in the stalls
// Revision 0.08 - Fixed minor "no-op" syntax error
// Revision 0.09 - Found and fixed instruction forwarding error. Cant do all at end (stall fails)
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module CPU (clock);
// Instruction opcodes
parameter LW = 6'b100011, SW = 6'b101011, BEQ=6'b000100, noop = 32'b00000_100000, ALUop=6''b0;
input clock;
reg[31:0] PC, Regs[0:31], IMemory[0:23], DMemory[0:23], // separate memories (they were 1023, i made them, 23)
IFIDIR, IDEXA, IDEXB, IDEXIR, EXMEMIR, EXMEMB, // pipeline registers
EXMEMALUOut, MEMWBValue, MEMWBIR; // pipeline registers
wire [4:0] IDEXrs, IDEXrt, EXMEMrd, MEMWBrd, MEMWBrt; // Access register fields
wire [5:0] EXMEMop, MEMWBop, IDEXop; // Access opcodes
wire [31:0] Ain, Bin; // the ALU inputs
// declare the bypass signals
wire bypassAfromMEM, bypassAfromALUinWB,bypassBfromMEM, bypassBfromALUinWB,
bypassAfromLWinWB, bypassBfromLWinWB;
// These assignment define fields from the pipeline registers
assign IDEXrs = IDEXIR[25:21]; // rs field
assign IDEXrt = IDEXIR[15:11]; // rt field
assign EXMEMrd = EXMEMIR[15:11]; // rd field
assign MEMWBrd = MEMWBIR[15:11]; //rd field [changed from 20;16] TO 15;11 //double checked, yes
assign MEMWBrt = MEMWBIR[25:20]; //rt field--used for loads
assign EXMEMop = EXMEMIR[31:26]; // the opocde
assign MEMWBop = MEMWBIR[31:26]; // the opcode
assign IDEXop = IDEXIR[31:26] ; // the opcode
// Inputs to the ALU come directly from the ID/EX pipeline registers
assign Ain = IDEXA;
assign Bin = IDEXB;
// The bypass to input A from the MEM stage for an ALU operation
assign bypassAfromMEM = (IDEXrs == EXMEMrd) & (IDEXrs!=0) & (EXMEMop==ALUop); // yes, bypass
// The bypass to input Bfrom the MEM stage for an ALU operation
assign bypassBfromMEM = (IDEXrt== EXMEMrd)&(IDEXrt!=0) & (EXMEMop==ALUop); // yes, bypass
// The bypass to input A from the WB stage for an ALU operation
assign bypassAfromALUinWB =( IDEXrs == MEMWBrd) & (IDEXrs!=0) & (MEMWBop==ALUop);
// The bypass to input B from the WB stage for an ALU operation
assign bypassBfromALUinWB = (IDEXrt==MEMWBrd) & (IDEXrt!=0) & (MEMWBop==ALUop);
// The bypass to input A from the WB stage for an LW operation
assign bypassAfromLWinWB =( IDEXrs ==MEMWBIR[20:16]) & (IDEXrs!=0) & (MEMWBop==LW);
// The bypass to input B from the WB stage for an LW operation
assign bypassBfromLWinWB = (IDEXrt==MEMWBIR[20:16]) & (IDEXrt!=0) & (MEMWBop==LW);
// The A input to the ALU is bypassed from MEM if there is a bypass there,
// Otherwise from WB if there is a bypass there, and otherwise comes from the IDEX register
assign Ain = bypassAfromMEM? EXMEMALUOut :
(bypassAfromALUinWB | bypassAfromLWinWB)? MEMWBValue : IDEXA;
// The B input to the ALU is bypassed from MEM if there is a bypass there,
// Otherwise from WB if there is a bypass there, and otherwise comes from the IDEX register
assign Bin = bypassBfromMEM? EXMEMALUOut :
(bypassBfromALUinWB | bypassBfromLWinWB)? MEMWBValue: IDEXB;
// The signal for detecting a stall based on the use of a result from LW
assign stall = (MEMWBIR[31:26]==LW) && // source instruction is a load
((((IDEXop==LW)|(IDEXop==SW)) && (IDEXrs==MEMWBrd)) | // stall for address calc
((IDEXop==ALUop) && ((IDEXrs==MEMWBrd)|(IDEXrt==MEMWBrd)))); // ALU use
reg [5:0] i; //used to initialize registers
initial begin
PC = 0;
IFIDIR=noop; IDEXIR=noop; EXMEMIR=noop; MEMWBIR=noop; // put no-ops in pipeline registers
for (i=0;i<=31;i=i+1) Regs[i] = i; //initialize registers--just so they aren?t cares
end
always @ (posedge clock) begin
// Remember that ALL these actions happen every pipestage and with the use of <= they happen in parallel!
// first instruction in the pipeline is being fetched
if (~stall) begin // the first three pipeline stages stall if there is a load hazard
IFIDIR <= IMemory[PC>>2];
PC <= PC + 4;
//end // Fetch & increment PC
// second instruction in pipeline is fetching registers
IDEXA <= Regs[IFIDIR[25:21]]; IDEXB <= Regs[IFIDIR[20:16]]; // get two registers
// third instruction is doing address calculation or ALU operation
if ((IDEXop==LW) |(IDEXop==SW)) // address calculation
EXMEMALUOut <= IDEXA +{{16{IDEXIR[15]}}, IDEXIR[15:0]};
else if (IDEXop==ALUop) case (IDEXIR[5:0]) //case for the various R-type instructions
32: EXMEMALUOut <= Ain + Bin; //add operation
16: EXMEMALUOut <= Ain - Bin; //subtract operation
8: EXMEMALUOut <= Ain & Bin; //and operation
7: EXMEMALUOut <= ~(Ain & Bin); //nadd operation
4: EXMEMALUOut <= Ain | Bin; //or operation
3: EXMEMALUOut <= ~(Ain | Bin); //nor operation
2: EXMEMALUOut <= ((Ain - Bin)==0)?1:0; //seqz operation
1: EXMEMALUOut <= Ain < Bin ? 1:0; //slt operation
default: ; //other R-type operations: subtract, SLT, etc.
endcase
IDEXIR <= IFIDIR; EXMEMIR <= IDEXIR; EXMEMB <= IDEXB;// passing along instructions
end
else EXMEMIR <= noop; //Freeze first three stages of pipeline; inject a nop into the EX output
//Mem stage of pipeline
if (EXMEMop==ALUop)
MEMWBValue <= EXMEMALUOut; //pass along ALU result
else if (EXMEMop == LW)
MEMWBValue <= DMemory[EXMEMALUOut>>2];
else if (EXMEMop == SW)
DMemory[EXMEMALUOut>>2] <=EXMEMB; //store [from top, it is 15:0)stage3
// the WB stage
if ((MEMWBop==ALUop) & (MEMWBrd != 0)) // update registers if ALU operation and destination not 0
Regs[MEMWBrd] <= MEMWBValue; // ALU operation
else if ((EXMEMop == LW)& (MEMWBrt != 0)) // Update registers if load and destination not 0
Regs[MEMWBrt] <= MEMWBValue;
MEMWBIR <= EXMEMIR; //pass along
end
endmodule