Files
LF-Build-RISCV/chapter5/RISCcore2.v
2025-08-22 07:14:22 +03:00

205 lines
7.5 KiB
Verilog

module RISCcore2 (
input rst,
input clk,
output reg [31:0] pc,
output wire [31:0] next_pc, // Changed to wire
output wire [31:0] instr
);
// IMem - reduced size for simplicity
reg [31:0] imem [0:63];
initial begin
$readmemh("program.hex", imem);
end
assign instr = imem[pc[31:2]]; // Word-aligned access
// Instruction decoder
wire [6:0] opcode = instr[6:0];
wire [4:0] rs1 = instr[19:15];
wire [4:0] rs2 = instr[24:20];
wire [4:0] rd = instr[11:7];
wire [2:0] funct3 = instr[14:12];
wire [6:0] funct7 = instr[31:25];
// Instruction type detection
wire isUType = (opcode == 7'b0110111) || (opcode == 7'b0010111); // LUI, AUIPC
wire isIType = (opcode == 7'b0000011) || (opcode == 7'b0000111) || // LOAD
(opcode == 7'b0010011) || (opcode == 7'b0011011) || // OP-IMM
(opcode == 7'b1100111); // JALR
wire isRType = (opcode == 7'b0110011) || (opcode == 7'b0111011); // OP
wire isSType = (opcode == 7'b0100011) || (opcode == 7'b0100111); // STORE
wire isBType = (opcode == 7'b1100011); // BRANCH
wire isJType = (opcode == 7'b1101111); // JAL
// Immediate generation
wire [31:0] Iimm = {{20{instr[31]}}, instr[31:20]};
wire [31:0] Simm = {{20{instr[31]}}, instr[31:25], instr[11:7]};
wire [31:0] Bimm = {{19{instr[31]}}, instr[31], instr[7], instr[30:25], instr[11:8], 1'b0};
wire [31:0] Uimm = {instr[31:12], 12'b0};
wire [31:0] Jimm = {{11{instr[31]}}, instr[31], instr[19:12], instr[20], instr[30:21], 1'b0};
// Register file
reg [31:0] rf [0:31];
// Initialize register file (x0 always zero)
integer i;
initial begin
for (i = 0; i < 32; i = i + 1) begin
rf[i] = 32'b0;
end
end
// Read ports
wire [31:0] rs1_val = (rs1 != 0) ? rf[rs1] : 32'b0;
wire [31:0] rs2_val = (rs2 != 0) ? rf[rs2] : 32'b0;
// Instruction decoding
wire isADDI = (isIType) && (funct3 == 3'b000);
wire isADD = (isRType) && (funct3 == 3'b000) && (funct7 == 7'b0000000);
// Branch instructions
wire isBEQ = (isBType) && (funct3 == 3'b000);
wire isBNE = (isBType) && (funct3 == 3'b001);
wire isBLT = (isBType) && (funct3 == 3'b100);
wire isBGE = (isBType) && (funct3 == 3'b101);
wire isBLTU = (isBType) && (funct3 == 3'b110);
wire isBGEU = (isBType) && (funct3 == 3'b111);
//store load instructions
wire isLB = (isIType) && (funct3 == 3'b000);
wire isLH = (isIType) && (funct3 == 3'b001);
wire isLW = (isIType) && (funct3 == 3'b010);
wire isLBU = (isIType) && (funct3 == 3'b100);
wire isLHU = (isIType) && (funct3 == 3'b101);
wire isSB = (isSType) && (funct3 == 3'b000);
wire isSH = (isSType) && (funct3 == 3'b001);
wire isSW = (isSType) && (funct3 == 3'b010);
//sl and sr instructions
wire isSLT = (isRType) && (funct3 == 3'b010) && (funct7[5] == 1'b0);
wire isSLTU = (isRType) && (funct3 == 3'b011) && (funct7[5] == 1'b0);
wire isSLL = (isRType) && (funct3 == 3'b001) && (funct7[5] == 1'b0);
wire isSLTI = (isIType) && (funct3 == 3'b010);
wire isSLTIU = (isIType) && (funct3 == 3'b011);
wire isSRA = (isRType) && (funct3 == 3'b101) && (funct7[5] == 1'b1);
wire isSRL = (isRType) && (funct3 == 3'b101) && (funct7[5] == 1'b0);
wire isSRAI = (isIType) && (funct3 == 3'b101) && (funct7[5] == 1'b1);
wire isSLLI = (isIType) && (funct3 == 3'b001) && (funct7[5] == 1'b0);
wire isSRLI = (isIType) && (funct3 == 3'b101) && (funct7[5] == 1'b0);
//logic imms
wire isANDI = (isIType) && (funct3 == 3'b111);
wire isORI = (isIType) && (funct3 == 3'b110);
wire isXORI = (isIType) && (funct3 == 3'b100);
// logic
wire isAND = (isRType) && (funct3 == 3'b111) && (funct7[5] == 1'b0);
wire isOR = (isRType) && (funct3 == 3'b110) && (funct7[5] == 1'b0);
wire isXOR = (isRType) && (funct3 == 3'b100) && (funct7[5] == 1'b0);
wire isSUB = (isRType) && (funct3 == 3'b000) && (funct7[5] == 1'b1);
//lui auipc (opcode use)
wire isLUI = (opcode == 7'b0110111);
wire isAUIPC = (opcode == 7'b0010111);
wire isJAL = (opcode == 7'b1101111);
//jal UType
wire isJALR = (opcode == 7'b1100111) && (funct3 == 3'b000);
// ALU operations
//sltu and slt
wire [31:0] sltu_rslt = {31'b0, (rs1_val < rs2_val)};
wire [31:0] signed_slt = (rs1_val[31] && !rs2_val[31]) ? 1'b1 :
(!rs1_val[31] && rs2_val[31]) ? 1'b0 :
(rs1_val < rs2_val);
wire [31:0] slt_rslt = {31'b0, signed_slt};
wire [31:0] slti_rslt = ((rs1_val[31] == Iimm[31]) ? sltu_rslt : {31'b0, rs1_val[31]});
wire [63:0] SErs1_val = {32{rs1_val[31]}, (rs1_val < rs2_val)};
wire [63:0] sra_rslt = {SErs1_val >> rs2_val[4:0]};
wire [63:0] srai_rslt = {SErs1_val >> Iimm[4:0]};
wire [31:0] sltiu_rslt = {31'b0, (rs1_val < Iimm)};
wire [31:0] alu_result = (isADDI) ? (rs1_val + Iimm) :
(isADD) ? (rs1_val + rs2_val) :
(isSLT) ? slt_rslt :
(isSLTU) ? sltu_rslt :
(isSRA) ? sra_rslt :
(isSRAI) ? srai_rslt :
(isSLTI) ? slti_rslt :
(isANDI) ? (rs1_val & Iimm) :
(isORI) ? (rs1_val | Iimm) :
(isXORI) ? (rs1_val ^ Iimm) :
(isSLLI) ? (rs1_val << Iimm[5:0]) :
(isSRLI) ? (rs1_val >> Iimm[5:0]) :
(isAND) ? (rs1_val & rs2_val) :
(isOR) ? (rs1_val | rs2_val) :
(isXOR) ? (rs1_val ^ rs2_val) :
(isSUB) ? (rs1_val - rs2_val) :
(isSLL) ? (rs1_val << rs2_val[4:0]) :
(isSRL) ? (rs1_val >> rs2_val[4:0]) :
(isSLTIU) ? (sltiu_rslt) :
(isLUI) ? ({Iimm[31:12], 12'b0}) :
(isAUIPC) ? (pc + Iimm) :
(isJAL) ? (pc + 32'd4) :
(isJALR) ? (pc + 32'd4) :
(isSRA) ? (sra_rslt[31:0]) :
(isSRAI) ? (srai_rslt[31:0]) :
32'b0;
// Branch condition logic
wire signed [31:0] signed_rs1 = rs1_val;
wire signed [31:0] signed_rs2 = rs2_val;
wire branch_taken =
isBEQ ? (rs1_val == rs2_val) :
isBNE ? (rs1_val != rs2_val) :
isBLT ? (signed_rs1 < signed_rs2) :
isBGE ? (signed_rs1 >= signed_rs2) :
isBLTU ? (rs1_val < rs2_val) :
isBGEU ? (rs1_val >= rs2_val) :
1'b0;
// Next PC calculation - FIXED: using wire for continuous assignment
wire [31:0] branch_target = pc + Bimm;
wire [31:0] next_pc_base = pc + 32'h4;
assign next_pc = branch_taken ? branch_target : next_pc_base;
// Register write back
wire rf_write_enable = (rd != 0) && (isADDI || isADD);
wire [31:0] writeback_data = alu_result;
// PC update
always @(posedge clk) begin
if (rst) begin
pc <= 32'h0;
end else begin
pc <= next_pc;
end
end
// Register write back
always @(posedge clk) begin
if (rf_write_enable && !rst) begin
rf[rd] <= writeback_data;
$display("RF Write: x%d = %h", rd, writeback_data);
end
end
// Debug monitoring
always @(posedge clk) begin
if (!rst) begin
$display("PC=%08h, Instr=%08h, rs1=x%d(%h), rs2=x%d(%h), rd=x%d, branch_taken=%b",
pc, instr, rs1, rs1_val, rs2, rs2_val, rd, branch_taken);
if (pc[1:0] != 2'b00) begin
$display("WARNING: PC not word-aligned: %h", pc);
end
end
end
endmodule