From 378d0fa463d60f7192b1419350f2c4b4e85aca1a Mon Sep 17 00:00:00 2001 From: vhaudiquet Date: Thu, 5 Oct 2023 22:34:08 +0200 Subject: [PATCH] Added M (Multiplication) extension --- src/cpu/instruction.h | 31 ++++-- src/cpu/rv32cpu.c | 253 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 228 insertions(+), 56 deletions(-) diff --git a/src/cpu/instruction.h b/src/cpu/instruction.h index 76fcc8b..ddb8a6c 100644 --- a/src/cpu/instruction.h +++ b/src/cpu/instruction.h @@ -64,18 +64,33 @@ #define FUNC7_SRAI 0x20 /* OPCODE_ARITHLOG sub functions (func3 + func7) */ -#define FUNC3_ADD_SUB 0x0 +#define FUNC3_ADD_SUB_MUL 0x0 #define FUNC7_ADD 0x0 #define FUNC7_SUB 0x20 -#define FUNC3_SLL 0x1 -#define FUNC3_SLT 0x2 -#define FUNC3_SLTU 0x3 -#define FUNC3_XOR 0x4 -#define FUNC3_SRL_SRA 0x5 +#define FUNC3_SLL_MULH 0x1 +#define FUNC7_SLL 0x0 +#define FUNC3_SLT_MULHSU 0x2 +#define FUNC7_SLT 0x0 +#define FUNC3_SLTU_MULHU 0x3 +#define FUNC7_SLTU 0x0 +#define FUNC3_XOR_DIV 0x4 +#define FUNC7_XOR 0x0 +#define FUNC3_SRL_SRA_DIVU 0x5 #define FUNC7_SRL 0x0 #define FUNC7_SRA 0x20 -#define FUNC3_OR 0x6 -#define FUNC3_AND 0x7 +#define FUNC3_OR_REM 0x6 +#define FUNC7_OR 0x0 +#define FUNC3_AND_REMU 0x7 +#define FUNC7_AND 0x0 +/* RISC-V RV32 M Extension */ +#define FUNC7_MUL 0x1 +#define FUNC7_MULH 0x1 +#define FUNC7_MULHSU 0x1 +#define FUNC7_MULHU 0x1 +#define FUNC7_DIV 0x1 +#define FUNC7_DIVU 0x1 +#define FUNC7_REM 0x1 +#define FUNC7_REMU 0x1 /* OPCODE_SYSTEM sub functions (func3 + imm) */ #define FUNC3_ECALL_EBREAK 0x0 diff --git a/src/cpu/rv32cpu.c b/src/cpu/rv32cpu.c index 7c6d219..934fcb6 100644 --- a/src/cpu/rv32cpu.c +++ b/src/cpu/rv32cpu.c @@ -339,7 +339,7 @@ static void cpu_execute(rv32_cpu_t* cpu, instruction_t* instruction) // To find out which operation, we must analyse func3 and func7 switch(instruction->func3) { - case FUNC3_ADD_SUB: + case FUNC3_ADD_SUB_MUL: switch(instruction->func7) { case FUNC7_ADD: @@ -348,41 +348,122 @@ static void cpu_execute(rv32_cpu_t* cpu, instruction_t* instruction) case FUNC7_SUB: cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] - cpu->regs.x[instruction->rs2]; break; + case FUNC7_MUL: + cpu->regs.x[instruction->rd] = (uint32_t) (cpu->regs.x[instruction->rs1] * cpu->regs.x[instruction->rs2]); + break; default: - fprintf(stderr, "FATAL: Unknown func7 0x%x for arithlog ADD/SUB instruction, could not execute\n", instruction->func7); + fprintf(stderr, "FATAL: Unknown func7 0x%x for arithlog ADD/SUB/MUL instruction, could not execute\n", instruction->func7); exit(EXIT_FAILURE); break; } break; - case FUNC3_SLL: - // Slide Left Logical - uint32_t sll_value = cpu->regs.x[instruction->rs2] & 0x1F; - cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] << sll_value; + case FUNC3_SLL_MULH: + switch(instruction->func7) + { + case FUNC7_SLL: + // Slide Left Logical + uint32_t sll_value = cpu->regs.x[instruction->rs2] & 0x1F; + cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] << sll_value; + break; + case FUNC7_MULH: + // MULtiplication High (32 high bits) (signed * signed) + uint64_t mulh_result = (uint64_t) (((int64_t) cpu->regs.x[instruction->rs1]) * ((int64_t) cpu->regs.x[instruction->rs2])); + cpu->regs.x[instruction->rd] = (uint32_t) (mulh_result >> 32); + break; + default: + fprintf(stderr, "FATAL: Unknown func7 0x%x for arithlog SLL/MULH instruction, could not execute\n", instruction->func7); + exit(EXIT_FAILURE); + break; + } break; - case FUNC3_SLT: - // Set Less Than - if(((int32_t) cpu->regs.x[instruction->rs1]) < ((int32_t) cpu->regs.x[instruction->rs2])) - cpu->regs.x[instruction->rd] = 1; - else - cpu->regs.x[instruction->rd] = 0; + case FUNC3_SLT_MULHSU: + switch(instruction->func7) + { + case FUNC7_SLT: + // Set Less Than + if(((int32_t) cpu->regs.x[instruction->rs1]) < ((int32_t) cpu->regs.x[instruction->rs2])) + cpu->regs.x[instruction->rd] = 1; + else + cpu->regs.x[instruction->rd] = 0; + break; + case FUNC7_MULHSU: + // MULtiplication High (32 high bits) (signed * unsigned) + uint64_t mulhsu_result = (uint64_t) (((int64_t) cpu->regs.x[instruction->rs1]) * ((uint64_t) cpu->regs.x[instruction->rs2])); + cpu->regs.x[instruction->rd] = (uint32_t) (mulhsu_result >> 32); + break; + default: + fprintf(stderr, "FATAL: Unknown func7 0x%x for arithlog SLL/MULH instruction, could not execute\n", instruction->func7); + exit(EXIT_FAILURE); + break; + } break; - case FUNC3_SLTIU: - // Set Less Than Unsigned - if(cpu->regs.x[instruction->rs1] < cpu->regs.x[instruction->rs2]) - cpu->regs.x[instruction->rd] = 1; - else - cpu->regs.x[instruction->rd] = 0; + case FUNC3_SLTU_MULHU: + switch(instruction->func7) + { + case FUNC7_SLTU: + // Set Less Than Unsigned + if(cpu->regs.x[instruction->rs1] < cpu->regs.x[instruction->rs2]) + cpu->regs.x[instruction->rd] = 1; + else + cpu->regs.x[instruction->rd] = 0; + break; + case FUNC7_MULHU: + // MULtiplication High (32 high bits) (unsigned * unsigned) + uint64_t mulhu_result = (((uint64_t) cpu->regs.x[instruction->rs1]) * ((uint64_t) cpu->regs.x[instruction->rs2])); + cpu->regs.x[instruction->rd] = (uint32_t) (mulhu_result >> 32); + break; + default: + fprintf(stderr, "FATAL: Unknown func7 0x%x for arithlog SLTU/MULHU instruction, could not execute\n", instruction->func7); + exit(EXIT_FAILURE); + break; + } break; - case FUNC3_XOR: - cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] ^ cpu->regs.x[instruction->rs2]; + case FUNC3_XOR_DIV: + switch(instruction->func7) + { + case FUNC7_XOR: + cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] ^ cpu->regs.x[instruction->rs2]; + break; + case FUNC7_DIV: + cpu->regs.x[instruction->rd] = ((int32_t) cpu->regs.x[instruction->rs1]) / ((int32_t) cpu->regs.x[instruction->rs2]); + break; + default: + fprintf(stderr, "FATAL: Unknown func7 0x%x for arithlog XOR/DIV instruction, could not execute\n", instruction->func7); + exit(EXIT_FAILURE); + break; + } break; - case FUNC3_OR: - cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] | cpu->regs.x[instruction->rs2]; + case FUNC3_OR_REM: + switch(instruction->func7) + { + case FUNC7_OR: + cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] | cpu->regs.x[instruction->rs2]; + break; + case FUNC7_REM: + cpu->regs.x[instruction->rd] = ((int32_t) cpu->regs.x[instruction->rs1]) % ((int32_t) cpu->regs.x[instruction->rs2]); + break; + default: + fprintf(stderr, "FATAL: Unknown func7 0x%x for arithlog OR/REM instruction, could not execute\n", instruction->func7); + exit(EXIT_FAILURE); + break; + } break; - case FUNC3_AND: - cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] & cpu->regs.x[instruction->rs2]; + case FUNC3_AND_REMU: + switch(instruction->func7) + { + case FUNC7_AND: + cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] & cpu->regs.x[instruction->rs2]; + break; + case FUNC7_REMU: + cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] % cpu->regs.x[instruction->rs2]; + break; + default: + fprintf(stderr, "FATAL: Unknown func7 0x%x for arithlog AND/REMU instruction, could not execute\n", instruction->func7); + exit(EXIT_FAILURE); + break; + } break; - case FUNC3_SRL_SRA: + case FUNC3_SRL_SRA_DIVU: switch(instruction->func7) { case FUNC7_SRL: @@ -395,8 +476,11 @@ static void cpu_execute(rv32_cpu_t* cpu, instruction_t* instruction) uint32_t sra_value = cpu->regs.x[instruction->rs2] & 0x1F; cpu->regs.x[instruction->rd] = ((int32_t) cpu->regs.x[instruction->rs1]) >> sra_value; break; + case FUNC7_DIVU: + cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] / cpu->regs.x[instruction->rs2]; + break; default: - fprintf(stderr, "FATAL: Unknown func7 0x%x for arithlog SRL/SRA instruction, could not execute\n", instruction->func7); + fprintf(stderr, "FATAL: Unknown func7 0x%x for arithlog SRL/SRA/DIVU instruction, could not execute\n", instruction->func7); exit(EXIT_FAILURE); break; } @@ -579,7 +663,7 @@ void cpu_loop(rv32_cpu_t* cpu) // Execute cpu_execute(cpu, &instruction); - + // Reset value of zero, in case instruction tried to modify cpu->regs.zero = 0; @@ -787,7 +871,7 @@ static void cpu_print_instruction(instruction_t* instruction) // To find out which operation, we must analyse func3 and func7 switch(instruction->func3) { - case FUNC3_ADD_SUB: + case FUNC3_ADD_SUB_MUL: switch(instruction->func7) { case FUNC7_ADD: @@ -796,33 +880,105 @@ static void cpu_print_instruction(instruction_t* instruction) case FUNC7_SUB: printf("sub x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); break; + case FUNC7_MUL: + printf("mul x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + break; default: - fprintf(stderr, "Warning: Unknown func7 0x%x for arithlog ADD/SUB instruction, could not execute\n", instruction->func7); + fprintf(stderr, "Warning: Unknown func7 0x%x for arithlog ADD/SUB/MUL instruction\n", instruction->func7); break; } break; - case FUNC3_SLL: - // Slide Left Logical - printf("sll x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + case FUNC3_SLL_MULH: + switch(instruction->func7) + { + case FUNC7_SLL: + // Slide Left Logical + printf("sll x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + break; + case FUNC7_MULH: + // MULtiplication High (32 high bits) (signed * signed) + printf("mulh x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + break; + default: + fprintf(stderr, "Warning: Unknown func7 0x%x for arithlog SLL/MULH instruction\n", instruction->func7); + break; + } break; - case FUNC3_SLT: - // Set Less Than - printf("slt x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + case FUNC3_SLT_MULHSU: + switch(instruction->func7) + { + case FUNC7_SLT: + // Set Less Than + printf("slt x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + break; + case FUNC7_MULHSU: + // MULtiplication High (32 high bits) (signed * unsigned) + printf("mulhsu x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + break; + default: + fprintf(stderr, "Warning: Unknown func7 0x%x for arithlog SLL/MULH instruction\n", instruction->func7); + break; + } break; - case FUNC3_SLTIU: - // Set Less Than Unsigned - printf("sltu x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + case FUNC3_SLTU_MULHU: + switch(instruction->func7) + { + case FUNC7_SLTU: + // Set Less Than Unsigned + printf("sltu x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + break; + case FUNC7_MULHU: + // MULtiplication High (32 high bits) (unsigned * unsigned) + printf("mulhu x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + break; + default: + fprintf(stderr, "Warning: Unknown func7 0x%x for arithlog SLTU/MULHU instruction\n", instruction->func7); + break; + } break; - case FUNC3_XOR: - printf("xor x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + case FUNC3_XOR_DIV: + switch(instruction->func7) + { + case FUNC7_XOR: + printf("xor x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + break; + case FUNC7_DIV: + printf("div x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + break; + default: + fprintf(stderr, "Warning: Unknown func7 0x%x for arithlog XOR/DIV instruction\n", instruction->func7); + break; + } break; - case FUNC3_OR: - printf("or x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + case FUNC3_OR_REM: + switch(instruction->func7) + { + case FUNC7_OR: + printf("or x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + break; + case FUNC7_REM: + printf("rem x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + break; + default: + fprintf(stderr, "Warning: Unknown func7 0x%x for arithlog OR/REM instruction\n", instruction->func7); + break; + } break; - case FUNC3_AND: - printf("and x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + case FUNC3_AND_REMU: + switch(instruction->func7) + { + case FUNC7_AND: + printf("and x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + break; + case FUNC7_REMU: + printf("remu x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + break; + default: + fprintf(stderr, "Warning: Unknown func7 0x%x for arithlog AND/REMU instruction\n", instruction->func7); + break; + } break; - case FUNC3_SRL_SRA: + case FUNC3_SRL_SRA_DIVU: switch(instruction->func7) { case FUNC7_SRL: @@ -833,15 +989,16 @@ static void cpu_print_instruction(instruction_t* instruction) // Slide Right Arithmetical printf("sra x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); break; + case FUNC7_DIVU: + printf("divu x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + break; default: - fprintf(stderr, "Warning: Unknown func7 0x%x for arithlog SRL/SRA instruction\n", instruction->func7); - exit(EXIT_FAILURE); + fprintf(stderr, "Warning: Unknown func7 0x%x for arithlog SRL/SRA/DIVU instruction\n", instruction->func7); break; } break; default: fprintf(stderr, "Warning: Unknown func3 0x%x for arithlog instruction\n", instruction->func3); - exit(EXIT_FAILURE); break; } break;