RISC-V CORE
This commit is contained in:
286
FINAL/RISCCore.v
Normal file
286
FINAL/RISCCore.v
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
module RISCCore (
|
||||||
|
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 = (pc[31:2] < 64) ? imem[pc[31:2]] : 32'h00000013; // Word-aligned access
|
||||||
|
|
||||||
|
//Data Mem
|
||||||
|
reg [31:0] dmem [0:31];
|
||||||
|
wire [31:0] ld_data;
|
||||||
|
wire [4:0] word_addr = mem_addr[6:2];
|
||||||
|
|
||||||
|
integer j;
|
||||||
|
initial begin
|
||||||
|
for(j = 0; j < 32; j = j + 1) begin
|
||||||
|
dmem[j] = 32'b0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign ld_data = (word_addr < 32) ? dmem[word_addr] : 32'b0;
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// Initialize register file (x0 always zero)
|
||||||
|
reg [31:0] rf [0:31]; //Register file
|
||||||
|
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 = (opcode == 7'b0010011) && (funct3 == 3'b000);
|
||||||
|
wire isADD = (opcode == 7'b0110011) && (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 = (opcode == 7'b0000011) && (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 = (opcode == 7'b0100011) && (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 = (opcode == 7'b0110011) && (funct3 == 3'b001) && (funct7 == 7'b0000000);
|
||||||
|
wire isSLTI = (isIType) && (funct3 == 3'b010);
|
||||||
|
wire isSLTIU = (isIType) && (funct3 == 3'b011);
|
||||||
|
|
||||||
|
wire isSRL = (opcode == 7'b0110011) && (funct3 == 3'b101) && (funct7 == 7'b0000000);
|
||||||
|
wire isSRA = (opcode == 7'b0110011) && (funct3 == 3'b101) && (funct7 == 7'b0100000);
|
||||||
|
|
||||||
|
wire isSLLI = (opcode == 7'b0010011) && (funct3 == 3'b001) && (funct7[6:1] == 6'b000000);
|
||||||
|
wire isSRLI = (opcode == 7'b0010011) && (funct3 == 3'b101) && (funct7[6:1] == 6'b000000);
|
||||||
|
wire isSRAI = (opcode == 7'b0010011) && (funct3 == 3'b101) && (funct7[6:1] == 6'b010000);
|
||||||
|
|
||||||
|
//logic imms
|
||||||
|
wire isANDI = (opcode == 7'b0010011) && (funct3 == 3'b111);
|
||||||
|
wire isORI = (opcode == 7'b0010011) && (funct3 == 3'b110);
|
||||||
|
wire isXORI = (opcode == 7'b0010011) && (funct3 == 3'b100);
|
||||||
|
// logic
|
||||||
|
wire isAND = (opcode == 7'b0110011) && (funct3 == 3'b111) && (funct7 == 7'b0000000);
|
||||||
|
wire isOR = (opcode == 7'b0110011) && (funct3 == 3'b110) && (funct7 == 7'b0000000);
|
||||||
|
wire isXOR = (opcode == 7'b0110011) && (funct3 == 3'b100) && (funct7 == 7'b0000000);
|
||||||
|
wire isSUB = (opcode == 7'b0110011) && (funct3 == 3'b000) && (funct7 == 7'b0100000);
|
||||||
|
//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);
|
||||||
|
|
||||||
|
//Mem address calculation
|
||||||
|
wire [31:0] mem_addr = (is_mem_op) ? alu_result : 32'b0;
|
||||||
|
|
||||||
|
//Mem address logic
|
||||||
|
//For simplicity we only implement all loads as word loads (lw)
|
||||||
|
//byte/halfword ignored
|
||||||
|
wire is_load = (opcode == 7'b0000011); // All load instructions
|
||||||
|
wire is_store = (opcode == 7'b0100011); // All store instructions
|
||||||
|
wire is_mem_op = is_store || is_load;
|
||||||
|
|
||||||
|
|
||||||
|
//Load operations
|
||||||
|
|
||||||
|
reg [31:0] load_data;
|
||||||
|
|
||||||
|
always @(*) begin
|
||||||
|
if (mem_addr[1:0] == 2'b00) begin
|
||||||
|
case (funct3)
|
||||||
|
3'b000: load_data = {{24{ld_data[7]}}, ld_data[7:0]};
|
||||||
|
3'b001: load_data = {{16{ld_data[15]}}, ld_data[15:0]};
|
||||||
|
3'b010: load_data = ld_data;
|
||||||
|
3'b100: load_data = {24'b0, ld_data[7:0]};
|
||||||
|
3'b101: load_data = {16'b0, ld_data[15:0]};
|
||||||
|
default: load_data = 32'b0;
|
||||||
|
endcase
|
||||||
|
end else begin
|
||||||
|
load_data = 32'b0;
|
||||||
|
if (is_load) begin // Only show error for actual loads
|
||||||
|
$display("ERROR: Misaligned memory address at addr %h", mem_addr);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
//Store operations
|
||||||
|
always @(*) begin
|
||||||
|
if (!rst && is_store && (word_addr < 32) && (mem_addr[1:0] == 2'b00)) begin
|
||||||
|
case (funct3)
|
||||||
|
3'b000: begin //SB: store byte 0
|
||||||
|
dmem[word_addr][7:0] = rs2_val[7:0];
|
||||||
|
end
|
||||||
|
3'b001: begin //SH: store halfword
|
||||||
|
dmem[word_addr][15:0] = rs2_val[15:0];
|
||||||
|
end
|
||||||
|
3'b010: begin //SW: store word
|
||||||
|
dmem[word_addr] = rs2_val;
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
$display("MEM Write: word_addr=%h, data=%h", word_addr, rs2_val);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
// 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 = (is_mem_op) ? (rs1_val + Iimm) : // Mem address computation
|
||||||
|
(isADDI) ? (rs1_val + Iimm) :
|
||||||
|
(isADD) ? (rs1_val + rs2_val) :
|
||||||
|
(isSLT) ? slt_rslt :
|
||||||
|
(isSLTU) ? sltu_rslt :
|
||||||
|
(isSLTI) ? slti_rslt :
|
||||||
|
(isANDI) ? (rs1_val & Iimm) :
|
||||||
|
(isORI) ? (rs1_val | Iimm) :
|
||||||
|
(isXORI) ? (rs1_val ^ Iimm) :
|
||||||
|
(isSLLI) ? (rs1_val << Iimm[4:0]) :
|
||||||
|
(isSRLI) ? (rs1_val >> Iimm[4: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 || isJALR) ? (pc + 32'd4) :
|
||||||
|
(isSRA) ? (sra_rslt[31:0]) :
|
||||||
|
(isSRAI) ? (srai_rslt[31:0]) :
|
||||||
|
32'b0;
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
wire [31:0] jalr_tgt_pc = rs1_val + Iimm;
|
||||||
|
|
||||||
|
assign next_pc = branch_taken ? branch_target :
|
||||||
|
isJAL ? branch_target :
|
||||||
|
isJALR ? jalr_tgt_pc :
|
||||||
|
next_pc_base;
|
||||||
|
|
||||||
|
// Register write back
|
||||||
|
wire rf_write_enable = (rd != 0) && (
|
||||||
|
isADDI || isADD || isSUB ||
|
||||||
|
isJAL || isJALR ||
|
||||||
|
isSLT || isSLTU || isSLTI || isSLTIU ||
|
||||||
|
isSLL || isSRL || isSRA || isSLLI || isSRLI || isSRAI ||
|
||||||
|
isLB || isLH || isLW || isLBU || isLHU ||
|
||||||
|
isXORI || isORI || isANDI ||
|
||||||
|
isXOR || isOR || isAND ||
|
||||||
|
is_load || isLUI || isAUIPC
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
wire [31:0] writeback_data = is_load ? load_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; // Use writeback_data instead of alu_result
|
||||||
|
$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
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (!rst && (opcode == 7'b0000011)) begin
|
||||||
|
$display("LOAD: byte_addr=%h, word_addr=%h, data=%h, funct3=%b",
|
||||||
|
mem_addr, word_addr, load_data, funct3);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
62
FINAL/RISCCore_tb.v
Normal file
62
FINAL/RISCCore_tb.v
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
`timescale 1ns/1ps
|
||||||
|
|
||||||
|
module RISCCore_tb;
|
||||||
|
reg clk;
|
||||||
|
reg rst;
|
||||||
|
wire [31:0] pc;
|
||||||
|
wire [31:0] next_pc;
|
||||||
|
wire [31:0] instr;
|
||||||
|
|
||||||
|
// Instantiate the RISC-V core
|
||||||
|
RISCCore uut (
|
||||||
|
.rst(rst),
|
||||||
|
.clk(clk),
|
||||||
|
.pc(pc),
|
||||||
|
.next_pc(next_pc),
|
||||||
|
.instr(instr)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Clock generation
|
||||||
|
always #5 clk = ~clk;
|
||||||
|
|
||||||
|
// Initialize signals
|
||||||
|
initial begin
|
||||||
|
clk = 0;
|
||||||
|
rst = 1;
|
||||||
|
|
||||||
|
// Reset sequence
|
||||||
|
#10 rst = 0;
|
||||||
|
|
||||||
|
// Run for enough clock cycles
|
||||||
|
#500;
|
||||||
|
|
||||||
|
// Display final register values
|
||||||
|
$display("\n=== FINAL REGISTER STATE ===");
|
||||||
|
$display("x1 (ra) = %h", uut.rf[1]);
|
||||||
|
$display("x2 (sp) = %h", uut.rf[2]);
|
||||||
|
$display("x3 (gp) = %h", uut.rf[3]);
|
||||||
|
$display("x4 (tp) = %h", uut.rf[4]);
|
||||||
|
$display("x5 (t0) = %h", uut.rf[5]);
|
||||||
|
$display("x6 (t1) = %h", uut.rf[6]);
|
||||||
|
$display("x7 (t2) = %h", uut.rf[7]);
|
||||||
|
$display("x8 (s0) = %h", uut.rf[8]);
|
||||||
|
$display("x10 (a0) = %h", uut.rf[10]);
|
||||||
|
|
||||||
|
// Display memory contents
|
||||||
|
$display("\n=== MEMORY STATE ===");
|
||||||
|
begin : memory_display
|
||||||
|
integer i;
|
||||||
|
for (i = 0; i < 10; i = i + 1) begin
|
||||||
|
$display("mem[%0d] = %h", i, uut.dmem[i]);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
// Simple monitor
|
||||||
|
initial begin
|
||||||
|
$monitor("Time=%0t: PC=%h, Instr=%h", $time, uut.pc, uut.instr);
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
12
FINAL/program.hex
Normal file
12
FINAL/program.hex
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
00000093 // addi x1, x0, 0 - x1 = 0
|
||||||
|
00100113 // addi x2, x0, 1 - x2 = 1
|
||||||
|
00200193 // addi x3, x0, 2 - x3 = 2
|
||||||
|
003081b3 // add x3, x1, x3 - x3 = 0 + 2 = 2
|
||||||
|
00420233 // add x4, x4, x4 - x4 = x4 + x4 (should be 0)
|
||||||
|
00228463 // beq x5, x2, 8 - branch if x5 == x2 (should not take)
|
||||||
|
00400463 // beq x0, x4, 8 - branch if 0 == 0 (should take)
|
||||||
|
00a00513 // addi x10, x0, 10 - x10 = 10 (should be skipped)
|
||||||
|
fff00513 // addi x10, x0, -1 - x10 = -1 (should execute)
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
1318
FINAL/risc_tb
Executable file
1318
FINAL/risc_tb
Executable file
File diff suppressed because it is too large
Load Diff
286
chapter5/RISCCore.v
Normal file
286
chapter5/RISCCore.v
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
module RISCCore (
|
||||||
|
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 = (pc[31:2] < 64) ? imem[pc[31:2]] : 32'h00000013; // Word-aligned access
|
||||||
|
|
||||||
|
//Data Mem
|
||||||
|
reg [31:0] dmem [0:31];
|
||||||
|
wire [31:0] ld_data;
|
||||||
|
wire [4:0] word_addr = mem_addr[6:2];
|
||||||
|
|
||||||
|
integer j;
|
||||||
|
initial begin
|
||||||
|
for(j = 0; j < 32; j = j + 1) begin
|
||||||
|
dmem[j] = 32'b0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign ld_data = (word_addr < 32) ? dmem[word_addr] : 32'b0;
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// Initialize register file (x0 always zero)
|
||||||
|
reg [31:0] rf [0:31]; //Register file
|
||||||
|
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 = (opcode == 7'b0010011) && (funct3 == 3'b000);
|
||||||
|
wire isADD = (opcode == 7'b0110011) && (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 = (opcode == 7'b0000011) && (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 = (opcode == 7'b0100011) && (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 = (opcode == 7'b0110011) && (funct3 == 3'b001) && (funct7 == 7'b0000000);
|
||||||
|
wire isSLTI = (isIType) && (funct3 == 3'b010);
|
||||||
|
wire isSLTIU = (isIType) && (funct3 == 3'b011);
|
||||||
|
|
||||||
|
wire isSRL = (opcode == 7'b0110011) && (funct3 == 3'b101) && (funct7 == 7'b0000000);
|
||||||
|
wire isSRA = (opcode == 7'b0110011) && (funct3 == 3'b101) && (funct7 == 7'b0100000);
|
||||||
|
|
||||||
|
wire isSLLI = (opcode == 7'b0010011) && (funct3 == 3'b001) && (funct7[6:1] == 6'b000000);
|
||||||
|
wire isSRLI = (opcode == 7'b0010011) && (funct3 == 3'b101) && (funct7[6:1] == 6'b000000);
|
||||||
|
wire isSRAI = (opcode == 7'b0010011) && (funct3 == 3'b101) && (funct7[6:1] == 6'b010000);
|
||||||
|
|
||||||
|
//logic imms
|
||||||
|
wire isANDI = (opcode == 7'b0010011) && (funct3 == 3'b111);
|
||||||
|
wire isORI = (opcode == 7'b0010011) && (funct3 == 3'b110);
|
||||||
|
wire isXORI = (opcode == 7'b0010011) && (funct3 == 3'b100);
|
||||||
|
// logic
|
||||||
|
wire isAND = (opcode == 7'b0110011) && (funct3 == 3'b111) && (funct7 == 7'b0000000);
|
||||||
|
wire isOR = (opcode == 7'b0110011) && (funct3 == 3'b110) && (funct7 == 7'b0000000);
|
||||||
|
wire isXOR = (opcode == 7'b0110011) && (funct3 == 3'b100) && (funct7 == 7'b0000000);
|
||||||
|
wire isSUB = (opcode == 7'b0110011) && (funct3 == 3'b000) && (funct7 == 7'b0100000);
|
||||||
|
//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);
|
||||||
|
|
||||||
|
//Mem address calculation
|
||||||
|
wire [31:0] mem_addr = (is_mem_op) ? alu_result : 32'b0;
|
||||||
|
|
||||||
|
//Mem address logic
|
||||||
|
//For simplicity we only implement all loads as word loads (lw)
|
||||||
|
//byte/halfword ignored
|
||||||
|
wire is_load = (opcode == 7'b0000011); // All load instructions
|
||||||
|
wire is_store = (opcode == 7'b0100011); // All store instructions
|
||||||
|
wire is_mem_op = is_store || is_load;
|
||||||
|
|
||||||
|
|
||||||
|
//Load operations
|
||||||
|
|
||||||
|
reg [31:0] load_data;
|
||||||
|
|
||||||
|
always @(*) begin
|
||||||
|
if (mem_addr[1:0] == 2'b00) begin
|
||||||
|
case (funct3)
|
||||||
|
3'b000: load_data = {{24{ld_data[7]}}, ld_data[7:0]};
|
||||||
|
3'b001: load_data = {{16{ld_data[15]}}, ld_data[15:0]};
|
||||||
|
3'b010: load_data = ld_data;
|
||||||
|
3'b100: load_data = {24'b0, ld_data[7:0]};
|
||||||
|
3'b101: load_data = {16'b0, ld_data[15:0]};
|
||||||
|
default: load_data = 32'b0;
|
||||||
|
endcase
|
||||||
|
end else begin
|
||||||
|
load_data = 32'b0;
|
||||||
|
if (is_load) begin // Only show error for actual loads
|
||||||
|
$display("ERROR: Misaligned memory address at addr %h", mem_addr);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
//Store operations
|
||||||
|
always @(*) begin
|
||||||
|
if (!rst && is_store && (word_addr < 32) && (mem_addr[1:0] == 2'b00)) begin
|
||||||
|
case (funct3)
|
||||||
|
3'b000: begin //SB: store byte 0
|
||||||
|
dmem[word_addr][7:0] = rs2_val[7:0];
|
||||||
|
end
|
||||||
|
3'b001: begin //SH: store halfword
|
||||||
|
dmem[word_addr][15:0] = rs2_val[15:0];
|
||||||
|
end
|
||||||
|
3'b010: begin //SW: store word
|
||||||
|
dmem[word_addr] = rs2_val;
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
$display("MEM Write: word_addr=%h, data=%h", word_addr, rs2_val);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
// 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 = (is_mem_op) ? (rs1_val + Iimm) : // Mem address computation
|
||||||
|
(isADDI) ? (rs1_val + Iimm) :
|
||||||
|
(isADD) ? (rs1_val + rs2_val) :
|
||||||
|
(isSLT) ? slt_rslt :
|
||||||
|
(isSLTU) ? sltu_rslt :
|
||||||
|
(isSLTI) ? slti_rslt :
|
||||||
|
(isANDI) ? (rs1_val & Iimm) :
|
||||||
|
(isORI) ? (rs1_val | Iimm) :
|
||||||
|
(isXORI) ? (rs1_val ^ Iimm) :
|
||||||
|
(isSLLI) ? (rs1_val << Iimm[4:0]) :
|
||||||
|
(isSRLI) ? (rs1_val >> Iimm[4: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 || isJALR) ? (pc + 32'd4) :
|
||||||
|
(isSRA) ? (sra_rslt[31:0]) :
|
||||||
|
(isSRAI) ? (srai_rslt[31:0]) :
|
||||||
|
32'b0;
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
wire [31:0] jalr_tgt_pc = rs1_val + Iimm;
|
||||||
|
|
||||||
|
assign next_pc = branch_taken ? branch_target :
|
||||||
|
isJAL ? branch_target :
|
||||||
|
isJALR ? jalr_tgt_pc :
|
||||||
|
next_pc_base;
|
||||||
|
|
||||||
|
// Register write back
|
||||||
|
wire rf_write_enable = (rd != 0) && (
|
||||||
|
isADDI || isADD || isSUB ||
|
||||||
|
isJAL || isJALR ||
|
||||||
|
isSLT || isSLTU || isSLTI || isSLTIU ||
|
||||||
|
isSLL || isSRL || isSRA || isSLLI || isSRLI || isSRAI ||
|
||||||
|
isLB || isLH || isLW || isLBU || isLHU ||
|
||||||
|
isXORI || isORI || isANDI ||
|
||||||
|
isXOR || isOR || isAND ||
|
||||||
|
is_load || isLUI || isAUIPC
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
wire [31:0] writeback_data = is_load ? load_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; // Use writeback_data instead of alu_result
|
||||||
|
$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
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (!rst && (opcode == 7'b0000011)) begin
|
||||||
|
$display("LOAD: byte_addr=%h, word_addr=%h, data=%h, funct3=%b",
|
||||||
|
mem_addr, word_addr, load_data, funct3);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
55
chapter5/RISCCore_0.2tb.v
Normal file
55
chapter5/RISCCore_0.2tb.v
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
module RISCCore_tb;
|
||||||
|
reg clk;
|
||||||
|
reg rst;
|
||||||
|
wire [31:0] pc;
|
||||||
|
wire [31:0] next_pc;
|
||||||
|
wire [31:0] instr;
|
||||||
|
|
||||||
|
// Instantiate the RISC-V core
|
||||||
|
RISCCore uut (
|
||||||
|
.rst(rst),
|
||||||
|
.clk(clk),
|
||||||
|
.pc(pc),
|
||||||
|
.next_pc(next_pc),
|
||||||
|
.instr(instr)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Clock generation
|
||||||
|
always #5 clk = ~clk;
|
||||||
|
|
||||||
|
// Test sequence
|
||||||
|
initial begin
|
||||||
|
// Initialize signals
|
||||||
|
clk = 0;
|
||||||
|
rst = 1;
|
||||||
|
|
||||||
|
// Apply reset
|
||||||
|
#10 rst = 0;
|
||||||
|
|
||||||
|
// Run for 100 clock cycles
|
||||||
|
#1000;
|
||||||
|
|
||||||
|
// Display final register values
|
||||||
|
$display("\n=== Final Register Values ===");
|
||||||
|
for (integer i = 0; i < 32; i = i + 1) begin
|
||||||
|
if (uut.rf[i] != 0) begin
|
||||||
|
$display("x%d = %h", i, uut.rf[i]);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// Display final memory contents
|
||||||
|
$display("\n=== Final Memory Contents ===");
|
||||||
|
for (integer i = 0; i < 32; i = i + 1) begin
|
||||||
|
if (uut.dmem[i] != 0) begin
|
||||||
|
$display("Mem[%d] = %h", i, uut.dmem[i]);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
// Monitor important signals
|
||||||
|
initial begin
|
||||||
|
$monitor("Time=%0t, PC=%h, Instr=%h", $time, pc, instr);
|
||||||
|
end
|
||||||
|
endmodule
|
62
chapter5/RISCCore_tb.v
Normal file
62
chapter5/RISCCore_tb.v
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
`timescale 1ns/1ps
|
||||||
|
|
||||||
|
module RISCCore_tb;
|
||||||
|
reg clk;
|
||||||
|
reg rst;
|
||||||
|
wire [31:0] pc;
|
||||||
|
wire [31:0] next_pc;
|
||||||
|
wire [31:0] instr;
|
||||||
|
|
||||||
|
// Instantiate the RISC-V core
|
||||||
|
RISCCore uut (
|
||||||
|
.rst(rst),
|
||||||
|
.clk(clk),
|
||||||
|
.pc(pc),
|
||||||
|
.next_pc(next_pc),
|
||||||
|
.instr(instr)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Clock generation
|
||||||
|
always #5 clk = ~clk;
|
||||||
|
|
||||||
|
// Initialize signals
|
||||||
|
initial begin
|
||||||
|
clk = 0;
|
||||||
|
rst = 1;
|
||||||
|
|
||||||
|
// Reset sequence
|
||||||
|
#10 rst = 0;
|
||||||
|
|
||||||
|
// Run for enough clock cycles
|
||||||
|
#500;
|
||||||
|
|
||||||
|
// Display final register values
|
||||||
|
$display("\n=== FINAL REGISTER STATE ===");
|
||||||
|
$display("x1 (ra) = %h", uut.rf[1]);
|
||||||
|
$display("x2 (sp) = %h", uut.rf[2]);
|
||||||
|
$display("x3 (gp) = %h", uut.rf[3]);
|
||||||
|
$display("x4 (tp) = %h", uut.rf[4]);
|
||||||
|
$display("x5 (t0) = %h", uut.rf[5]);
|
||||||
|
$display("x6 (t1) = %h", uut.rf[6]);
|
||||||
|
$display("x7 (t2) = %h", uut.rf[7]);
|
||||||
|
$display("x8 (s0) = %h", uut.rf[8]);
|
||||||
|
$display("x10 (a0) = %h", uut.rf[10]);
|
||||||
|
|
||||||
|
// Display memory contents
|
||||||
|
$display("\n=== MEMORY STATE ===");
|
||||||
|
begin : memory_display
|
||||||
|
integer i;
|
||||||
|
for (i = 0; i < 10; i = i + 1) begin
|
||||||
|
$display("mem[%0d] = %h", i, uut.dmem[i]);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
// Simple monitor
|
||||||
|
initial begin
|
||||||
|
$monitor("Time=%0t: PC=%h, Instr=%h", $time, uut.pc, uut.instr);
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
287
chapter5/RISCcore0.2.v
Normal file
287
chapter5/RISCcore0.2.v
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
module RISCCore (
|
||||||
|
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 = (pc[31:2] < 64) ? imem[pc[31:2]] : 32'h00000013; // Word-aligned access
|
||||||
|
|
||||||
|
//Data Mem
|
||||||
|
reg [31:0] dmem [0:31];
|
||||||
|
wire [31:0] ld_data;
|
||||||
|
wire [4:0] word_addr = mem_addr[6:2];
|
||||||
|
|
||||||
|
integer j;
|
||||||
|
initial begin
|
||||||
|
for(j = 0; j < 32; j = j + 1) begin
|
||||||
|
dmem[j] = 32'b0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign ld_data = (word_addr < 32) ? dmem[word_addr] : 32'b0;
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// Initialize register file (x0 always zero)
|
||||||
|
reg [31:0] rf [0:31]; //Register file
|
||||||
|
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 = (opcode == 7'b0010011) && (funct3 == 3'b000);
|
||||||
|
wire isADD = (opcode == 7'b0110011) && (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 = (opcode == 7'b0000011) && (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 = (opcode == 7'b0100011) && (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 = (opcode == 7'b0110011) && (funct3 == 3'b001) && (funct7 == 7'b0000000);
|
||||||
|
wire isSLTI = (isIType) && (funct3 == 3'b010);
|
||||||
|
wire isSLTIU = (isIType) && (funct3 == 3'b011);
|
||||||
|
|
||||||
|
wire isSRL = (opcode == 7'b0110011) && (funct3 == 3'b101) && (funct7 == 7'b0000000);
|
||||||
|
wire isSRA = (opcode == 7'b0110011) && (funct3 == 3'b101) && (funct7 == 7'b0100000);
|
||||||
|
|
||||||
|
wire isSLLI = (opcode == 7'b0010011) && (funct3 == 3'b001) && (funct7[6:1] == 6'b000000);
|
||||||
|
wire isSRLI = (opcode == 7'b0010011) && (funct3 == 3'b101) && (funct7[6:1] == 6'b000000);
|
||||||
|
wire isSRAI = (opcode == 7'b0010011) && (funct3 == 3'b101) && (funct7[6:1] == 6'b010000);
|
||||||
|
|
||||||
|
//logic imms
|
||||||
|
wire isANDI = (opcode == 7'b0010011) && (funct3 == 3'b111);
|
||||||
|
wire isORI = (opcode == 7'b0010011) && (funct3 == 3'b110);
|
||||||
|
wire isXORI = (opcode == 7'b0010011) && (funct3 == 3'b100);
|
||||||
|
// logic
|
||||||
|
wire isAND = (opcode == 7'b0110011) && (funct3 == 3'b111) && (funct7 == 7'b0000000);
|
||||||
|
wire isOR = (opcode == 7'b0110011) && (funct3 == 3'b110) && (funct7 == 7'b0000000);
|
||||||
|
wire isXOR = (opcode == 7'b0110011) && (funct3 == 3'b100) && (funct7 == 7'b0000000);
|
||||||
|
wire isSUB = (opcode == 7'b0110011) && (funct3 == 3'b000) && (funct7 == 7'b0100000);
|
||||||
|
//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);
|
||||||
|
|
||||||
|
//Mem address calculation
|
||||||
|
wire [31:0] mem_addr = alu_result;
|
||||||
|
|
||||||
|
//Mem address logic
|
||||||
|
//For simplicity we only implement all loads as word loads (lw)
|
||||||
|
//byte/halfword ignored
|
||||||
|
wire is_load = (opcode == 7'b0000011); // All load instructions
|
||||||
|
wire is_store = (opcode == 7'b0100011); // All store instructions
|
||||||
|
wire is_mem_op = is_store || is_load;
|
||||||
|
|
||||||
|
|
||||||
|
//Load operations
|
||||||
|
|
||||||
|
reg [31:0] load_data;
|
||||||
|
always @(*) begin
|
||||||
|
if (mem_addr[1:0] == 2'b00) begin
|
||||||
|
case (funct3)
|
||||||
|
3'b000: load_data = {{24{ld_data[7]}}, ld_data[7:0]}; //LB sign-extended byte 0
|
||||||
|
3'b001: load_data = {{16{ld_data[15]}}, ld_data[15:0]}; //LH sign-extended halfword
|
||||||
|
3'b010: load_data = ld_data; //LW full word
|
||||||
|
3'b100: load_data = {24'b0, ld_data[7:0]}; //LBU zero-extended byte 0
|
||||||
|
3'b101: load_data = {16'b0, ld_data[15:0]}; // LHU zero-extended halfword
|
||||||
|
default: load_data = 32'b0;
|
||||||
|
endcase
|
||||||
|
end else begin
|
||||||
|
load_data = 32'b0; // Misaligned access not supported
|
||||||
|
$display("ERROR: Misaligned memory address at addr %h", mem_addr);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
//Store operations
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (!rst && (word_addr < 32) && (mem_addr[1:0] == 2'b00)) begin
|
||||||
|
case (funct3)
|
||||||
|
3'b000: begin //SB: store byte 0
|
||||||
|
dmem[word_addr][7:0] <= rs2_val[7:0];
|
||||||
|
end
|
||||||
|
3'b001: begin //SH: store halfword
|
||||||
|
dmem[word_addr][15:0] <= rs2_val[15:0];
|
||||||
|
end
|
||||||
|
3'b010: begin //SW: store word
|
||||||
|
dmem[word_addr] <= rs2_val;
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
$display("MEM Write: word_addr=%h, data=%h", word_addr, rs2_val);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
// 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 = (is_mem_op) ? (rs1_val + Iimm) & 32'hFFFFFFFC : // Mem address computation (force word alignment)
|
||||||
|
(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[4:0]) :
|
||||||
|
(isSRLI) ? (rs1_val >> Iimm[4: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 || isJALR) ? (pc + 32'd4) :
|
||||||
|
(isSRA) ? (sra_rslt[31:0]) :
|
||||||
|
(isSRAI) ? (srai_rslt[31:0]) :
|
||||||
|
(is_load) ? (load_data) : //For register writeback
|
||||||
|
32'b0;
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
wire [31:0] jalr_tgt_pc = rs1_val + Iimm;
|
||||||
|
|
||||||
|
assign next_pc = branch_taken ? branch_target :
|
||||||
|
isJAL ? branch_target :
|
||||||
|
isJALR ? jalr_tgt_pc :
|
||||||
|
next_pc_base;
|
||||||
|
|
||||||
|
// Register write back
|
||||||
|
wire rf_write_enable = (rd != 0) && (
|
||||||
|
isADDI || isADD || isSUB ||
|
||||||
|
isJAL || isJALR ||
|
||||||
|
isSLT || isSLTU || isSLTI || isSLTIU ||
|
||||||
|
isSLL || isSRL || isSRA || isSLLI || isSRLI || isSRAI ||
|
||||||
|
isLB || isLH || isLW || isLBU || isLHU ||
|
||||||
|
isXORI || isORI || isANDI ||
|
||||||
|
isXOR || isOR || isAND ||
|
||||||
|
is_load || isLUI || isAUIPC
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
wire [31:0] writeback_data = is_load ? load_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; // Use writeback_data instead of alu_result
|
||||||
|
$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
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (!rst && (opcode == 7'b0000011)) begin
|
||||||
|
$display("LOAD: byte_addr=%h, word_addr=%h, data=%h, funct3=%b",
|
||||||
|
mem_addr, word_addr, load_data, funct3);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
@@ -11,7 +11,16 @@ module RISCcore2 (
|
|||||||
initial begin
|
initial begin
|
||||||
$readmemh("program.hex", imem);
|
$readmemh("program.hex", imem);
|
||||||
end
|
end
|
||||||
assign instr = imem[pc[31:2]]; // Word-aligned access
|
assign instr = (pc[31:2] < 64) ? imem[pc[31:2]] : 32'h00000013; // Word-aligned access
|
||||||
|
|
||||||
|
//Data Mem
|
||||||
|
reg [31:0] dmem [0:63];
|
||||||
|
integer j;
|
||||||
|
initial begin
|
||||||
|
for(j = 0; j < 64; j = j + 1) begin
|
||||||
|
dmem[j] = 32'b0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
// Instruction decoder
|
// Instruction decoder
|
||||||
wire [6:0] opcode = instr[6:0];
|
wire [6:0] opcode = instr[6:0];
|
||||||
@@ -39,8 +48,6 @@ module RISCcore2 (
|
|||||||
wire [31:0] Jimm = {{11{instr[31]}}, instr[31], instr[19:12], instr[20], instr[30:21], 1'b0};
|
wire [31:0] Jimm = {{11{instr[31]}}, instr[31], instr[19:12], instr[20], instr[30:21], 1'b0};
|
||||||
|
|
||||||
// Register file
|
// Register file
|
||||||
reg [31:0] rf [0:31];
|
|
||||||
|
|
||||||
// Initialize register file (x0 always zero)
|
// Initialize register file (x0 always zero)
|
||||||
integer i;
|
integer i;
|
||||||
initial begin
|
initial begin
|
||||||
@@ -109,7 +116,58 @@ module RISCcore2 (
|
|||||||
|
|
||||||
wire isJALR = (opcode == 7'b1100111) && (funct3 == 3'b000);
|
wire isJALR = (opcode == 7'b1100111) && (funct3 == 3'b000);
|
||||||
|
|
||||||
|
//Mem address calculation
|
||||||
|
wire [31:0] mem_addr = alu_result;
|
||||||
|
wire [31:0] word_addr = mem_addr[31:2];
|
||||||
|
|
||||||
|
//Mem address logic
|
||||||
|
//For simplicity we only implement all loads as word loads (lw)
|
||||||
|
//byte/halfword ignored
|
||||||
|
wire is_load = (opcode == 7'b0000011); // All load instructions
|
||||||
|
wire is_store = (opcode == 7'b0100011); // All store instructions
|
||||||
|
wire is_mem_op = is_store || is_load;
|
||||||
|
|
||||||
|
assign loaded_data = (mem_addr[31:2] < 64) ? dmem[mem_addr[31:2]] : 32'b0;
|
||||||
|
|
||||||
|
reg [31:0] load_data;
|
||||||
|
always @(*) begin
|
||||||
|
if (mem_addr[1:0] == 2'b00) begin
|
||||||
|
case (funct3)
|
||||||
|
3'b000: load_data = {{24{loaded_data[7]}}, loaded_data[7:0]}; //LB sign-extended byte 0
|
||||||
|
3'b001: load_data = {{16{loaded_data[15]}}, loaded_data[15:0]}; //LH sign-extended halfword
|
||||||
|
3'b010: load_data = loaded_data; //LW full word
|
||||||
|
3'b100: load_data = {24'b0, loaded_data[7:0]}; //LBU zero-extended byte 0
|
||||||
|
3'b101: load_data = {16'b0, loaded_data[15:0]}; // LHU zero-extended halfword
|
||||||
|
default: load_data = 32'b0;
|
||||||
|
endcase
|
||||||
|
end else begin
|
||||||
|
load_data = 32'b0; // Misaligned access not supported
|
||||||
|
$display("ERROR: Misaligned memory address at addr %h", mem_addr);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
//Store operations
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (!rst && (word_addr < 64) && (mem_addr[1:0] == 2'b00)) begin
|
||||||
|
case (funct3)
|
||||||
|
3'b000: begin //SB: store byte 0
|
||||||
|
dmem[word_addr][7:0] <= rs2_val[7:0];
|
||||||
|
end
|
||||||
|
3'b001: begin //SH: store halfword
|
||||||
|
dmem[word_addr][15:0] <= rs2_val[15:0];
|
||||||
|
end
|
||||||
|
3'b010: begin //SW: store word
|
||||||
|
dmem[word_addr] <= rs2_val;
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
$display("MEM Write: word_addr=%h, data=%h", word_addr, rs2_val);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
// ALU operations
|
// ALU operations
|
||||||
|
|
||||||
//sltu and slt
|
//sltu and slt
|
||||||
wire [31:0] sltu_rslt = {31'b0, (rs1_val < rs2_val)};
|
wire [31:0] sltu_rslt = {31'b0, (rs1_val < rs2_val)};
|
||||||
wire [31:0] signed_slt = (rs1_val[31] && !rs2_val[31]) ? 1'b1 :
|
wire [31:0] signed_slt = (rs1_val[31] && !rs2_val[31]) ? 1'b1 :
|
||||||
@@ -124,7 +182,8 @@ module RISCcore2 (
|
|||||||
wire [63:0] srai_rslt = {SErs1_val >> Iimm[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] sltiu_rslt = {31'b0, (rs1_val < Iimm)};
|
||||||
|
|
||||||
wire [31:0] alu_result = (isADDI) ? (rs1_val + Iimm) :
|
wire [31:0] alu_result = (is_mem_op) ? (rs1_val + Iimm) : //Mem address computation first
|
||||||
|
(isADDI) ? (rs1_val + Iimm) :
|
||||||
(isADD) ? (rs1_val + rs2_val) :
|
(isADD) ? (rs1_val + rs2_val) :
|
||||||
(isSLT) ? slt_rslt :
|
(isSLT) ? slt_rslt :
|
||||||
(isSLTU) ? sltu_rslt :
|
(isSLTU) ? sltu_rslt :
|
||||||
@@ -145,13 +204,13 @@ module RISCcore2 (
|
|||||||
(isSLTIU) ? (sltiu_rslt) :
|
(isSLTIU) ? (sltiu_rslt) :
|
||||||
(isLUI) ? ({Iimm[31:12], 12'b0}) :
|
(isLUI) ? ({Iimm[31:12], 12'b0}) :
|
||||||
(isAUIPC) ? (pc + Iimm) :
|
(isAUIPC) ? (pc + Iimm) :
|
||||||
(isJAL) ? (pc + 32'd4) :
|
(isJAL || isJALR) ? (pc + 32'd4) :
|
||||||
(isJALR) ? (pc + 32'd4) :
|
|
||||||
(isSRA) ? (sra_rslt[31:0]) :
|
(isSRA) ? (sra_rslt[31:0]) :
|
||||||
(isSRAI) ? (srai_rslt[31:0]) :
|
(isSRAI) ? (srai_rslt[31:0]) :
|
||||||
|
(is_load) ? (load_data) : //For register writeback
|
||||||
32'b0;
|
32'b0;
|
||||||
|
|
||||||
// Branch condition logic
|
|
||||||
wire signed [31:0] signed_rs1 = rs1_val;
|
wire signed [31:0] signed_rs1 = rs1_val;
|
||||||
wire signed [31:0] signed_rs2 = rs2_val;
|
wire signed [31:0] signed_rs2 = rs2_val;
|
||||||
|
|
||||||
@@ -164,14 +223,42 @@ module RISCcore2 (
|
|||||||
isBGEU ? (rs1_val >= rs2_val) :
|
isBGEU ? (rs1_val >= rs2_val) :
|
||||||
1'b0;
|
1'b0;
|
||||||
|
|
||||||
|
|
||||||
|
// Store operations
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if(!rst) begin
|
||||||
|
if (is_store && (mem_addr[31:2] < 64)) begin
|
||||||
|
dmem[mem_addr[31:2]] <= rs2_val;
|
||||||
|
$display("MEM Write: address = %h, data=%h", mem_addr, rs2_val);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
// Next PC calculation - FIXED: using wire for continuous assignment
|
// Next PC calculation - FIXED: using wire for continuous assignment
|
||||||
wire [31:0] branch_target = pc + Bimm;
|
wire [31:0] branch_target = pc + Bimm;
|
||||||
wire [31:0] next_pc_base = pc + 32'h4;
|
wire [31:0] next_pc_base = pc + 32'h4;
|
||||||
assign next_pc = branch_taken ? branch_target : next_pc_base;
|
wire [31:0] jalr_tgt_pc = rs1_val + Iimm;
|
||||||
|
|
||||||
|
assign next_pc = branch_taken ? branch_target :
|
||||||
|
isJAL ? branch_target :
|
||||||
|
isJALR ? jalr_tgt_pc :
|
||||||
|
next_pc_base;
|
||||||
|
|
||||||
// Register write back
|
// Register write back
|
||||||
wire rf_write_enable = (rd != 0) && (isADDI || isADD);
|
wire rf_write_enable = (rd != 0) && (
|
||||||
wire [31:0] writeback_data = alu_result;
|
isADDI || isADD || isSUB ||
|
||||||
|
isJAL || isJALR ||
|
||||||
|
isSLT || isSLTU || isSLTI || isSLTIU ||
|
||||||
|
isSLL || isSRL || isSRA || isSLLI || isSRLI || isSRAI ||
|
||||||
|
isLB || isLH || isLW || isLBU || isLHU ||
|
||||||
|
isXORI || isORI || isANDI ||
|
||||||
|
isXOR || isOR || isAND ||
|
||||||
|
is_load || isLUI || isAUIPC
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
wire [31:0] writeback_data = is_load ? load_data : alu_result;
|
||||||
|
|
||||||
// PC update
|
// PC update
|
||||||
always @(posedge clk) begin
|
always @(posedge clk) begin
|
||||||
@@ -183,14 +270,14 @@ module RISCcore2 (
|
|||||||
end
|
end
|
||||||
|
|
||||||
// Register write back
|
// Register write back
|
||||||
always @(posedge clk) begin
|
always @(posedge clk) begin
|
||||||
if (rf_write_enable && !rst) begin
|
if (rf_write_enable && !rst) begin
|
||||||
rf[rd] <= writeback_data;
|
rf[rd] <= writeback_data; // Use writeback_data instead of alu_result
|
||||||
$display("RF Write: x%d = %h", rd, writeback_data);
|
$display("RF Write: x%d = %h", rd, writeback_data);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
// Debug monitoring
|
// Debug monitoring
|
||||||
always @(posedge clk) begin
|
always @(posedge clk) begin
|
||||||
if (!rst) begin
|
if (!rst) begin
|
||||||
$display("PC=%08h, Instr=%08h, rs1=x%d(%h), rs2=x%d(%h), rd=x%d, branch_taken=%b",
|
$display("PC=%08h, Instr=%08h, rs1=x%d(%h), rs2=x%d(%h), rd=x%d, branch_taken=%b",
|
||||||
@@ -201,4 +288,11 @@ module RISCcore2 (
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (!rst && (opcode == 7'b0000011)) begin
|
||||||
|
$display("LOAD: byte_addr=%h, word_addr=%h, data=%h, funct3=%b",
|
||||||
|
mem_addr, word_addr, load_data, funct3);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
@@ -1,15 +1,12 @@
|
|||||||
00100093 // addi x1, x0, 1 (x1 = 1)
|
00000093 // addi x1, x0, 0 - x1 = 0
|
||||||
00200113 // addi x2, x0, 2 (x2 = 2)
|
00100113 // addi x2, x0, 1 - x2 = 1
|
||||||
00300193 // addi x3, x0, 3 (x3 = 3)
|
00200193 // addi x3, x0, 2 - x3 = 2
|
||||||
00400213 // addi x4, x0, 4 (x4 = 4)
|
003081b3 // add x3, x1, x3 - x3 = 0 + 2 = 2
|
||||||
00500293 // addi x5, x0, 5 (x5 = 5)
|
00420233 // add x4, x4, x4 - x4 = x4 + x4 (should be 0)
|
||||||
00600313 // addi x6, x0, 6 (x6 = 6)
|
00228463 // beq x5, x2, 8 - branch if x5 == x2 (should not take)
|
||||||
00700393 // addi x7, x0, 7 (x7 = 7)
|
00400463 // beq x0, x4, 8 - branch if 0 == 0 (should take)
|
||||||
00800413 // addi x8, x0, 8 (x8 = 8)
|
00a00513 // addi x10, x0, 10 - x10 = 10 (should be skipped)
|
||||||
00900493 // addi x9, x0, 9 (x9 = 9)
|
fff00513 // addi x10, x0, -1 - x10 = -1 (should execute)
|
||||||
00510233 // add x4, x2, x5 (x4 = 2+3=5)
|
00000013 // nop
|
||||||
00620333 // add x6, x4, x6 (x6 = 5+6=11)
|
00000013 // nop
|
||||||
007303b3 // add x7, x6, x7 (x7 = 11+7=18)
|
00000013 // nop
|
||||||
00840433 // add x8, x8, x8 (x8 = 8+8=16)
|
|
||||||
009484b3 // add x9, x9, x9 (x9 = 9+9=18)
|
|
||||||
0000006f // jal x0, 0 (infinite loop)
|
|
||||||
|
64
chapter5/program0.1.hex
Normal file
64
chapter5/program0.1.hex
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
00000093 // addi x1, x0, 0 | x1 = 0
|
||||||
|
00100113 // addi x2, x0, 1 | x2 = 1
|
||||||
|
002081B3 // add x3, x1, x2 | x3 = x1 + x2 = 1
|
||||||
|
00400293 // addi x5, x0, 4 | x5 = 4 (memory address)
|
||||||
|
0051A023 // sw x5, 0(x3) | Store x5 at address x3 (1)
|
||||||
|
0001A303 // lw x6, 0(x3) | Load from address x3 to x6
|
||||||
|
00600393 // addi x7, x0, 6 | x7 = 6
|
||||||
|
40738433 // sub x8, x7, x7 | x8 = x7 - x7 = 0
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
||||||
|
00000013 // nop
|
1318
chapter5/risc_tb
Executable file
1318
chapter5/risc_tb
Executable file
File diff suppressed because it is too large
Load Diff
1815
chapter5/riscv
1815
chapter5/riscv
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user