Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 73 additions & 20 deletions rtl/core_modules/alu.v
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,81 @@ module alu (
output reg [31:0] ALUoutput
);

wire signed [31:0] rs1_signed = $signed(rs1);
wire signed [31:0] rs2_signed = $signed(rs2);
wire signed [63:0] rs1_signed_ext = {{32{rs1[31]}}, rs1};
wire signed [63:0] rs2_signed_ext = {{32{rs2[31]}}, rs2};
wire [63:0] rs1_unsigned_ext = {32'b0, rs1};
wire [63:0] rs2_unsigned_ext = {32'b0, rs2};
wire signed [63:0] mul_signed = rs1_signed_ext * rs2_signed_ext;
wire signed [63:0] mul_mixed = rs1_signed_ext * $signed(rs2_unsigned_ext);
wire [63:0] mul_unsigned = rs1_unsigned_ext * rs2_unsigned_ext;
wire div_by_zero = (rs2 == 0);
wire div_overflow = (rs1 == 32'h80000000) && (rs2 == 32'hFFFFFFFF);

`ifdef FORMAL
// Simplified ALU for formal verification - only basic operations
always @(*) begin
case (instr_id)
INSTR_ADD: ALUoutput = rs1 + rs2;
INSTR_SUB: ALUoutput = rs1 - rs2;
INSTR_XOR: ALUoutput = rs1 ^ rs2;
INSTR_OR: ALUoutput = rs1 | rs2;
INSTR_AND: ALUoutput = rs1 & rs2;
INSTR_ADDI: ALUoutput = rs1 + imm;
INSTR_XORI: ALUoutput = rs1 ^ imm;
INSTR_ORI: ALUoutput = rs1 | imm;
INSTR_ANDI: ALUoutput = rs1 & imm;
default: ALUoutput = 32'h0;
endcase
end
`else
// Full ALU implementation for synthesis
always @(*) begin
case (instr_id)
INSTR_ADD: ALUoutput = $signed(rs1) + $signed(rs2); // Addition
INSTR_SUB: ALUoutput = $signed(rs1) - $signed(rs2); // Subtraction
INSTR_XOR: ALUoutput = rs1 ^ rs2; // Bitwise XOR
INSTR_OR: ALUoutput = rs1 | rs2; // Bitwise OR
INSTR_AND: ALUoutput = rs1 & rs2; // Bitwise AND
INSTR_SLL: ALUoutput = rs1 << rs2[4:0]; // Logical left shift
INSTR_SRL: ALUoutput = rs1 >> rs2[4:0]; // Logical right shift
INSTR_SRA: ALUoutput = $signed(rs1) >>> rs2[4:0]; // Arithmetic right shift
INSTR_SLT: ALUoutput = {31'b0, $signed(rs1) < $signed(rs2)}; // Set less than (signed comparison)
INSTR_SLTU: ALUoutput = {31'b0, rs1 < rs2}; // Set less than (unsigned comparison)
INSTR_ADDI: ALUoutput = $signed(rs1) + $signed(imm); // Add immediate
INSTR_XORI: ALUoutput = rs1 ^ imm; // Bitwise XOR with immediate
INSTR_ORI: ALUoutput = rs1 | imm; // Bitwise OR with immediate
INSTR_ANDI: ALUoutput = rs1 & imm; // Bitwise AND with immediate
INSTR_SLLI: ALUoutput = rs1 << imm[4:0]; // Logical left shift with immediate
INSTR_SRLI: ALUoutput = rs1 >> imm[4:0]; // Logical right shift with immediate
INSTR_SRAI: ALUoutput = $signed(rs1) >>> imm[4:0]; // Arithmetic right shift with immediate
INSTR_SLTI: ALUoutput = {31'b0, $signed(rs1) < $signed(imm)}; // Set less than immediate (signed comparison)
INSTR_SLTIU: ALUoutput = {31'b0, rs1 < imm}; // Set less than immediate (unsigned comparison)
default: ALUoutput = 0; // Default case: output zero
INSTR_ADD: ALUoutput = $signed(rs1) + $signed(rs2);
INSTR_SUB: ALUoutput = $signed(rs1) - $signed(rs2);
INSTR_XOR: ALUoutput = rs1 ^ rs2;
INSTR_OR: ALUoutput = rs1 | rs2;
INSTR_AND: ALUoutput = rs1 & rs2;
INSTR_SLL: ALUoutput = rs1 << rs2[4:0];
INSTR_SRL: ALUoutput = rs1 >> rs2[4:0];
INSTR_SRA: ALUoutput = $signed(rs1) >>> rs2[4:0];
INSTR_SLT: ALUoutput = {31'b0, $signed(rs1) < $signed(rs2)};
INSTR_SLTU: ALUoutput = {31'b0, rs1 < rs2};
INSTR_ADDI: ALUoutput = $signed(rs1) + $signed(imm);
INSTR_XORI: ALUoutput = rs1 ^ imm;
INSTR_ORI: ALUoutput = rs1 | imm;
INSTR_ANDI: ALUoutput = rs1 & imm;
INSTR_SLLI: ALUoutput = rs1 << imm[4:0];
INSTR_SRLI: ALUoutput = rs1 >> imm[4:0];
INSTR_SRAI: ALUoutput = $signed(rs1) >>> imm[4:0];
INSTR_SLTI: ALUoutput = {31'b0, $signed(rs1) < $signed(imm)}; // bugfix: returns 1 or 0
INSTR_SLTIU: ALUoutput = {31'b0, rs1 < imm}; // bugfix: returns 1 or 0
INSTR_MUL: ALUoutput = mul_signed[31:0];
INSTR_MULH: ALUoutput = mul_signed[63:32];
INSTR_MULHSU: ALUoutput = mul_mixed[63:32];
INSTR_MULHU: ALUoutput = mul_unsigned[63:32];
INSTR_DIV: begin
if (div_by_zero) ALUoutput = 32'hFFFFFFFF;
else if (div_overflow) ALUoutput = 32'h80000000;
else ALUoutput = rs1_signed / rs2_signed;
end
INSTR_DIVU: begin
if (div_by_zero) ALUoutput = 32'hFFFFFFFF;
else ALUoutput = rs1 / rs2;
end
INSTR_REM: begin
if (div_by_zero) ALUoutput = rs1;
else if (div_overflow) ALUoutput = 32'h00000000;
else ALUoutput = rs1_signed % rs2_signed;
end
INSTR_REMU: begin
if (div_by_zero) ALUoutput = rs1;
else ALUoutput = rs1 % rs2;
end
default: ALUoutput = 0;
endcase
end
`endif
endmodule
8 changes: 8 additions & 0 deletions rtl/core_modules/decoder.v
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ module decoder (
})
{7'h00, 3'h0} : instr_id = INSTR_ADD;
{7'h20, 3'h0} : instr_id = INSTR_SUB;
{7'h01, 3'h0} : instr_id = INSTR_MUL;
{7'h01, 3'h1} : instr_id = INSTR_MULH;
{7'h01, 3'h2} : instr_id = INSTR_MULHSU;
{7'h01, 3'h3} : instr_id = INSTR_MULHU;
{7'h00, 3'h4} : instr_id = INSTR_XOR;
{7'h00, 3'h6} : instr_id = INSTR_OR;
{7'h00, 3'h7} : instr_id = INSTR_AND;
Expand All @@ -68,6 +72,10 @@ module decoder (
{7'h20, 3'h5} : instr_id = INSTR_SRA;
{7'h00, 3'h2} : instr_id = INSTR_SLT;
{7'h00, 3'h3} : instr_id = INSTR_SLTU;
{7'h01, 3'h4} : instr_id = INSTR_DIV;
{7'h01, 3'h5} : instr_id = INSTR_DIVU;
{7'h01, 3'h6} : instr_id = INSTR_REM;
{7'h01, 3'h7} : instr_id = INSTR_REMU;
default: instr_id = INSTR_INVALID;
endcase
end
Expand Down
10 changes: 10 additions & 0 deletions rtl/include/instr_defines.vh
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ localparam [5:0] INSTR_SRA = 6'h08;
localparam [5:0] INSTR_SLT = 6'h09;
localparam [5:0] INSTR_SLTU = 6'h0A;

// R-type M extension
localparam [5:0] INSTR_MUL = 6'h30;
localparam [5:0] INSTR_MULH = 6'h31;
localparam [5:0] INSTR_MULHSU = 6'h32;
localparam [5:0] INSTR_MULHU = 6'h33;
localparam [5:0] INSTR_DIV = 6'h34;
localparam [5:0] INSTR_DIVU = 6'h35;
localparam [5:0] INSTR_REM = 6'h36;
localparam [5:0] INSTR_REMU = 6'h37;

// I-type arithmetic
localparam [5:0] INSTR_ADDI = 6'h0B;
localparam [5:0] INSTR_XORI = 6'h0C;
Expand Down
161 changes: 161 additions & 0 deletions sim/factorial.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
// RISC-V factorial program to exercise all M extension instructions
#include <stdint.h>
#include <stdbool.h>

#if defined(__linux__) || defined(__APPLE__)
#define HOST
#include <stdio.h>
#endif

#define N 6 // Compute factorial of 6 (6! = 720)
#define DATA_MEM_BASE 0x10000000
#define CPU_DONE_ADDR (DATA_MEM_BASE + 0xFF)
#define FACTORIAL_ADDR (DATA_MEM_BASE + 0x20)

int main() {
#ifdef HOST
uint32_t CPU_DONE = 0;
#else
#define CPU_DONE (* (volatile uint8_t *) CPU_DONE_ADDR)
#endif

uint32_t result = 1;
uint32_t i;
volatile int32_t sink32 = 0;
volatile uint32_t sinku32 = 0;

// MUL: result = result * i
for (i = 1; i <= N; i++) {
result = result * i;
}

// MULH: high 32 bits of signed * signed
volatile int32_t mulh_a = (int32_t)0x80000000;
volatile int32_t mulh_b = -2;
int32_t mulh_res = ((int64_t)mulh_a * (int64_t)mulh_b) >> 32;
#ifdef HOST
printf("MULH: high(0x%08x * %d) = %d\n", (uint32_t)mulh_a, mulh_b, mulh_res);
#endif
sink32 = mulh_res;

mulh_a = 0x7FFFFFFF;
mulh_b = 0x7FFFFFFF;
mulh_res = ((int64_t)mulh_a * (int64_t)mulh_b) >> 32;
#ifdef HOST
printf("MULH: high(%d * %d) = %d\n", mulh_a, mulh_b, mulh_res);
#endif
sink32 = mulh_res;

// MULHSU: high 32 bits of signed * unsigned
volatile int32_t mulhsu_a = -1;
volatile uint32_t mulhsu_b = 2;
int32_t mulhsu_res = ((int64_t)mulhsu_a * (uint64_t)mulhsu_b) >> 32;
#ifdef HOST
printf("MULHSU: high(%d * %u) = %d\n", mulhsu_a, mulhsu_b, mulhsu_res);
#endif
sink32 = mulhsu_res;

mulhsu_a = 0x80000000;
mulhsu_b = 2;
mulhsu_res = ((int64_t)mulhsu_a * (uint64_t)mulhsu_b) >> 32;
#ifdef HOST
printf("MULHSU: high(%d * %u) = %d\n", mulhsu_a, mulhsu_b, mulhsu_res);
#endif
sink32 = mulhsu_res;

// MULHU: high 32 bits of unsigned * unsigned
volatile uint32_t mulhu_a = 0xFFFFFFFF;
volatile uint32_t mulhu_b = 0xFFFFFFFF;
uint32_t mulhu_res = ((uint64_t)mulhu_a * (uint64_t)mulhu_b) >> 32;
#ifdef HOST
printf("MULHU: high(%u * %u) = %u\n", mulhu_a, mulhu_b, mulhu_res);
#endif
sinku32 = mulhu_res;

mulhu_a = 0x12345678;
mulhu_b = 0x9ABCDEF0;
mulhu_res = ((uint64_t)mulhu_a * (uint64_t)mulhu_b) >> 32;
#ifdef HOST
printf("MULHU: high(%u * %u) = %u\n", mulhu_a, mulhu_b, mulhu_res);
#endif
sinku32 = mulhu_res;

// DIV: signed division
volatile int32_t div_a = -2;
volatile int32_t div_b = 2;
int32_t div_res = div_a / div_b;
#ifdef HOST
printf("DIV: %d / %d = %d\n", div_a, div_b, div_res);
#endif
sink32 = div_res;

div_a = 10;
div_b = 0;
div_res = (div_b == 0) ? -1 : div_a / div_b;
#ifdef HOST
printf("DIV: %d / %d = %d\n", div_a, div_b, div_res);
#endif
sink32 = div_res;

// DIVU: unsigned division
volatile uint32_t divu_a = 10;
volatile uint32_t divu_b = 2;
uint32_t divu_res = divu_a / divu_b;
#ifdef HOST
printf("DIVU: %u / %u = %u\n", divu_a, divu_b, divu_res);
#endif
sinku32 = divu_res;

divu_a = 10;
divu_b = 0;
divu_res = (divu_b == 0) ? 0xFFFFFFFF : divu_a / divu_b;
#ifdef HOST
printf("DIVU: %u / %u = %u\n", divu_a, divu_b, divu_res);
#endif
sinku32 = divu_res;

// REM: signed remainder
volatile int32_t rem_a = -2;
volatile int32_t rem_b = 3;
int32_t rem_res = rem_a % rem_b;
#ifdef HOST
printf("REM: %d %% %d = %d\n", rem_a, rem_b, rem_res);
#endif
sink32 = rem_res;

rem_a = 10;
rem_b = 0;
rem_res = (rem_b == 0) ? rem_a : rem_a % rem_b;
#ifdef HOST
printf("REM: %d %% %d = %d\n", rem_a, rem_b, rem_res);
#endif
sink32 = rem_res;

// REMU: unsigned remainder
volatile uint32_t remu_a = 10;
volatile uint32_t remu_b = 3;
uint32_t remu_res = remu_a % remu_b;
#ifdef HOST
printf("REMU: %u %% %u = %u\n", remu_a, remu_b, remu_res);
#endif
sinku32 = remu_res;

remu_a = 10;
remu_b = 0;
remu_res = (remu_b == 0) ? remu_a : remu_a % remu_b;
#ifdef HOST
printf("REMU: %u %% %u = %u\n", remu_a, remu_b, remu_res);
#endif
sinku32 = remu_res;

#ifdef HOST
printf("Factorial(%d) = %u\n", N, result);
#else
// Store result to memory
volatile uint32_t *mem_ptr = (volatile uint32_t *)FACTORIAL_ADDR;
*mem_ptr = result;
#endif

CPU_DONE = 1;
return 0;
}
Loading
Loading