Updated Harvard, ALU, PC, Control, and Regfile

This commit is contained in:
jc4419 2020-12-08 01:46:01 +04:00
parent 8f5e582f33
commit 9de2b59bbb
5 changed files with 142 additions and 101 deletions

View file

@ -77,8 +77,6 @@ assign ALUOps = ALUOp;
always_comb begin
case(ALUOps)
ADD: begin
ALURes = $signed(A) + $signed(B);

View file

@ -3,10 +3,10 @@ module mips_cpu_control(
input logic[31:0] Instr,
input logic ALUCond,
output logic CtrlRegDst,
output logic[1:0] CtrlRegDst,
output logic[1:0] CtrlPC,
output logic CtrlMemRead,
output logic CtrlMemtoReg,
output logic[1:0] CtrlMemtoReg,
output logic[4:0] CtrlALUOp,
output logic[4:0] Ctrlshamt,
output logic CtrlMemWrite,
@ -19,7 +19,7 @@ module mips_cpu_control(
logic[5:0] funct;
logic[4:0] rt; */
/* assign op = Instr[31:26];
/* assign op = Instr[31:26];
assign funct = Instr[5:0];
assign rt = Instr[20:16]; */
@ -93,27 +93,31 @@ always_comb begin
//CtrlRegDst logic
if(op == (ADDIU | ANDI | LB | LBU | LH | LHU | LUI | LW | LWL | LWR | ORI | SLTI | SLTIU | XORI))begin
CtrlRegDst = 0; //Write address comes from rt
CtrlRegDst = 2'd0; //Write address comes from rt
end else if (op == (SPECIAL & (funct == (ADDU | AND | JALR | OR | SLL | SLLV | SLT | SLTU | SRA | SRAV | SRL | SRLV | SUBU | XOR))))begin
CtrlRegDst = 1; //Write address comes from rd
CtrlRegDst = 2'd1; //Write address comes from rd
end else if (op == JAL)begin
CtrlRegDst = 2'd2; //const reg 31, for writing to the link register
end else begin CtrlRegDst = 1'bx; end//Not all instructions are encompassed so, added incase for debug purposes
//CtrlPC logic
if(op == (BEQ | BGTZ | BLEZ | BNE | (REGIMM & (rt == (BGEZ | BGEZAL | BLTZ | BLTZAL)))))begin
if(ALUCond & (op == (BEQ | BGTZ | BLEZ | BNE | (REGIMM & (rt == (BGEZ | BGEZAL | BLTZ | BLTZAL))))))begin
CtrlPC = 2'd1; // Branches - Jumps relative to PC
end else if(op == (J | JAL))begin
CtrlPC = 2'd2; // Jumps within 256MB Region using 26-bit immediate in J type instruction
end else if(op == (JR | JALR))begin
CtrlPC = 2'd3; // Jumps using Register.
end else begin CtrlPC = 2'd0;end // No jumps, just increment to next word
end else begin CtrlPC = 2'd0;end // No jumps or branches, just increment to next word
//CtrlMemRead and CtrlMemtoReg logic -- Interesting quirk that they have the same logic. Makes sense bc you'd only want to select the read data out when the memory itself is read enabled.
if(op == (LB | LBU | LH | LHU | LW | LWL | LWR))begin
CtrlMemRead = 1;//Memory is read enabled
CtrlMemtoReg = 1;//write data port of memory is fed from data memory
CtrlMemtoReg = 2'd1;//write data port of memory is fed from data memory
end else if (op == (ADDIU | ANDI | ORI | SLTI | SLTIU | XORI | (SPECIAL & (funct == (ADDU | AND | DIV | DIVU | MTHI | MTLO | MULT | MULTU | OR | SLL | SLLV | SLT | SLTU | SRA | SRAV | SRL | SRLV | SUBU | XOR)))))begin
CtrlMemRead = 0;//Memory is read disabled
CtrlMemtoReg = 0;//write data port of memory if fed from ALURes
CtrlMemtoReg = 2'd0;//write data port of memory is fed from ALURes
end else if (op == (JAL | (SPECIAL &(funct == JALR))))begin
CtrlMemtoReg = 2'd2;//write data port of memory is fed from PC + 8
end else begin CtrlMemRead = 1'bx;end//Not all instructions are encompassed so, added incase for debug purposes
//CtrlALUOp Logic

View file

@ -9,104 +9,141 @@ module mips_cpu_harvard(
input logic clk_enable,
/* Combinatorial read access to instructions */
output logic[31:0] instr_address,
input logic[31:0] instr_readdata,
output logic[31:0] instr_address,//Port from PC out to instruction memory address input.
input logic[31:0] instr_readdata,//port from instruction memory out, going to various inputs.
/* Combinatorial read and single-cycle write access to instructions */
output logic[31:0] data_address,
output logic data_write,
output logic data_read,
output logic[31:0] data_writedata,
input logic[31:0] data_readdata
output logic[31:0] data_address,//Port from ALURes going into Data Memory 'Address' port
output logic data_write,//Control line from 'control' CtrlMemWrite enabling/disabling write access for Data Memory.
output logic data_read,//Control line from 'control' CtrlMemRead enabling/disabling read access for Data Memory.
output logic[31:0] data_writedata,//Data from Register file 'Read data 2' port, aka rt's data, going to 'Write data' port on Data Memory.
input logic[31:0] data_readdata//port from data memory out, going to the 'Write Register' port in regfile.
);
//Control Flags
logic Jump, Branch, ALUSrc, ALUZero, RegWrite;
logic[5:0] ALUOp = instr_readdata[31:26];
logic[30:0] ALUFlags; //Not sure if this is needed anymore
logic[1:0] RegDst, MemtoReg;
always_comb begin
instr_address = out_pc_out;
data_address = out_ALURes;
data_write = out_MemWrite;
data_read = out_MemRead;
data_writedata = out_readdata2;
end
//PC wires
logic[31:0] pc_curr;
logic[31:0] pc_curr_next = pc_curr + 3'd4; //Added due to compilation error
logic[31:0] pc_delay; //Added due to compilation error
logic[31:0] Jump_addr = {pc_curr_next[31:28], instr_readdata[25:0], 2'b00};
logic[31:0] pc_next = Jump ? Jump_addr : PCSrc ? {pc_curr_next + {{14{instr_readdata[15]}}, instr_readdata[15:0], 2'b00}} : pc_curr_next;
logic PCSrc = Branch && ALUZero;
logic[31:0] in_pc_in;
logic[4:0] in_readreg1;
logic[4:0] in_readreg2;
logic[4:0] in_writereg;
logic[31:0] in_writedata;
logic[5:0] in_opcode;
logic[31:0] in_B;
//Instruction MEM
assign instr_address = pc_delay;
always_comb begin
//deconstruction of instruction :)
logic[5:0] opcode = instr_readdata[31:26];
logic[4:0] rs = instr_readdata[25:21];
logic[4:0] rt = instr_readdata[20:16];
logic[4:0] rd = RegDst==2'b10 ? 5'b11111 : RegDst==2'b01 ? instr_readdata[15:11] : instr_readdata[20:16];
logic[15:0] immediate = instr_readdata[15:0];
logic[4:0] shamt = instr_readdata[10:6]; // Shamt needed for the sll instruction
in_readreg1 = instr_readdata[25:21];
in_readreg2 = instr_readdata[20:16];
in_opcode = instr_readdata[31:26];
//Picking what the next value of PC should be.
case(out_PC)
2'd0: begin
in_pc_in = out_pc_out + 32'd4;//No branch or jump or load, so no delay slot.
end
2'd1: begin
in_pc_in = //help
end
2'd2: begin
in_pc_in = //my brain hurts
end
2'd3: begin
in_pc_in = //I need to sleep......
end
endcase
//ALU Data
logic[31:0] alu_in1 = read_data1;
logic[31:0] alu_in2 = ALUSrc ? {{16{immediate[15]}},immediate} : read_data2;
logic[31:0] ALUOut;
//Picking what register should be written to.
case(out_RegDst)
2'd0:begin
in_writereg = instr_readdata[20:16];//GPR rt
end
2'd1:begin
in_writereg = instr_readdata[15:11];//GPR rd
end
2'd2:begin
in_writereg = 5'd31;//Link Register 31.
end
endcase
//Data MEM
assign data_address = ALUOut; //address to be written to comes from ALU
assign data_writedata = read_data2; //data to be written comes from reg read bus 2
//Picking which output should be written to regfile.
case(out_MemtoReg)
2'd0:begin
in_writedata = out_ALURes;//Output from ALU Result.
end
2'd1:begin
in_writedata = data_readdata;//Output from Data Memory.
end
2'd2:begin
in_writedata = (out_pc_out + 32'd8);//Output from PC +8.
end
endcase
//Writeback logic
logic[31:0] writeback = MemtoReg==2'b10 ? {pc_curr_next} : MemtoReg==2'b01 ? data_readdata : ALUOut;
always_ff @(posedge clk) begin
pc_delay <= pc_curr;
//Picking which output should be taken as the second operand for ALU.
case(out_ALUSrc)
1'b1:begin
in_B = {{16{instr_readdata[15]}},instr_readdata[15:0]};//Output from the 16-bit immediate values sign extened to 32bits.
end
1'b0:begin
in_B = out_readdata2;//Output from 'Read data 2' port of regfile.
end
endcase
end
pc pc(
.clk(clk),
.rst(reset),
.pc_in(pc_next),
.pc_out(pc_curr)
//PC inputs
.clk(clk),//clk taken from the Standard signals
.rst(reset),//clk taken from the Standard signals
.pc_in(in_pc_in),//what the pc will output on the next clock cycle taken from either: PC itself + 4(Normal/Default Operation); or 16-bit signed valued taken from Instr[15-0] sign extend to 32bit then shifted by 2 then added to PC + 4(Branch Operation); or 26-bit instruction address taken from J-type instr[25-0] shifted left by 2 then concatanated to form Jump Address (PC-region branch); or from the GPR rs.
//PC outputs
.pc_out(out_pc_out)//What the pc outputs at every clock edge that goes into the 'Read address' port of Instruction Memory.
);
mips_cpu_control control( //control flags block
.Instr(opcode), //opcode to be decoded
.Jump(Jump), //jump flag: 0 - increment or branch, 1 - J-type jump
.Branch(Branch), //branch flag: 0 - increment, 1 - branch if ALU.Zero == 1
.Memread(data_read), //tells data memory to read out data at dMEM[ALUout]
.Memtoreg(MemtoReg), //0: writeback = ALUout, 1: writeback = data_readdata
.Memwrite(data_write), //tells data memory to store data_writedata at data_writeaddress
.Alusrc(ALUSrc), //0: ALUin2 = read_data2, 1: ALUin2 = signextended(instr_readdata[15:0])
.Regwrite(RegWrite), //tells register file to write writeback to rd
.Regdst(RegDst) //select Rt, Rd or $ra to store to
mips_cpu_control control( //instance of the 'mips_cpu_control' module called 'control' in top level 'harvard'
//Inputs to control
.Instr(instr_readdata), //Full instruction taken from the Instruction Memory.
.ALUCond(out_ALUCond), //Active high condition check from ALU
//Outputs from control
.CtrlRegDst(out_RegDst),
.CtrlPC(out_PC),
.CtrlMemRead(out_MemRead),
.CtrlMemtoReg(out_MemtoReg),
.CtrlALUOp(out_ALUOp),
.Ctrlshamt(out_shamt),
.CtrlMemWrite(out_MemWrite),
.CtrlALUSrc(out_ALUSrc),
.CtrlRegWrite(out_RegWrite)
);
regfile regfile(
.clk(clk), //clock input for triggering write port
.readreg1(rs), //read port 1 selector
.readreg2(rt), //read port 2 selector
.writereg(rd), //write port selector
.writedata(writeback), //write port input data
.regwrite(RegWrite), //enable line for write port
.opcode(opcode), //opcode input for controlling partial load weirdness
.readdata1(read_data1), //read port 1 output
.readdata2(read_data2), //read port 2 output
.regv0(register_v0) //debug output of $v0 or $2 (first register for returning function results
mips_cpu_regfile regfile(
//Inputs to refile
.clk(clk), //clock input for triggering write port
.readreg1(in_readreg1), //read port 1 selector
.readreg2(in_readreg2), //read port 2 selector
.writereg(in_writereg), //write port selector
.writedata(in_writedata), //write port input data
.regwrite(out_RegWrite), //enable line for write port
.opcode(in_opcode), //opcode input for controlling partial load weirdness
//Outputs from regfile
.readdata1(out_readdata1), //read port 1 output
.readdata2(out_readdata2), //read port 2 output
.regv0(register_v0) //debug output of $v0 or $2 (first register for returning function results
);
/*
alucontrol alucontrol(
.ALUOp(ALUOp), //opcode of instruction
.funct(immediate[5:0]), //funct of instruction
.aluflags(ALUFlags) //ALU Control flags
);
*/
mips_cpu_alu alu(
//.ALUFlags(ALUFlags), //selects the operation carried out by the ALU
.A(alu_in1), //operand 1
.B(alu_in2), //operand 2
.ALUCond(ALUZero), //is the result zero, used for checks
.ALURes(ALUOut), //output/result of operation
.shamt(shamt),
.ALUOp(ALUOp)
//Inputs to ALU
.A(out_readdata1), //operand 1 taken from 'Read data 1' aka the data stored in GPR rs.
.B(in_B), //operand 2 taken either from: 'Read data 2' aka the data stored in rt; or 16-bit immediate sign extended to 32 bits.
.ALUOp(out_ALUOp), //Operation selection for ALU decided, and output by control.
.shamt(out_shamt), //Shift amount required for shift instruction taken from control.
//Outputs from ALU
.ALUCond(out_ALUCond), //condition used by control to decide on branch instructions.
.ALURes(out_ALURes) //output/result of operation that goes to either: 'Address' port of Data Memory; or 'Write Data' port of the register file.
);
endmodule : mips_cpu_harvard
endmodule

View file

@ -9,17 +9,19 @@ reg[31:0] pc_curr;
initial begin
pc_curr = 32'hBFC00000;
end : initial
end // initial
always_comb begin
if (rst) begin
pc_curr = 32'hBFC00000;
end else begin
pc_curr = pc_in;
end
pc_out = pc_curr;
end
always_ff @(posedge clk) begin
pc_curr <= pc_in;
pc_out <= pc_curr;
end
endmodule : pc
endmodule // pc

View file

@ -1,8 +1,8 @@
module regfile(
module mips_cpu_regfile(
input logic clk, //clock input for triggering write port
input logic[4:0] readreg1, //read port 1 selector
input logic[4:0] readreg2, //read port 2 selector
input logic[4:0] writereg, //write port selector
input logic[4:0] readreg1, //read port 1 register selector
input logic[4:0] readreg2, //read port 2 register selector
input logic[4:0] writereg, //write port register selector
input logic[31:0] writedata, //write port input data
input logic regwrite, //enable line for write port
input[5:0] opcode, //opcode input for controlling partial load weirdness
@ -80,4 +80,4 @@ always_ff @(negedge clk) begin
end
end
endmodule : regfile
endmodule