From ad3ec2e5040f20ea483aa96be90e74874d3722c1 Mon Sep 17 00:00:00 2001 From: vhaudiquet Date: Thu, 5 Oct 2023 11:16:06 +0200 Subject: [PATCH] Debugging instructions (system mostly) --- README.md | 3 + src/cpu/instruction.h | 3 + src/cpu/rv32cpu.c | 321 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 316 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index d6f88cf..5620154 100644 --- a/README.md +++ b/README.md @@ -6,5 +6,8 @@ Juraj's Blog, mostly: - https://jborza.com/post/2021-04-04-riscv-supervisor-mode/ - https://jborza.com/emulation/2021/04/22/ecalls-and-syscalls.html +RISC-V SBI Specifications: +- https://github.com/riscv-non-isa/riscv-sbi-doc/releases + Buildroot fork for nommu linux: - https://github.com/regymm/buildroot diff --git a/src/cpu/instruction.h b/src/cpu/instruction.h index 51a1255..bb171b4 100644 --- a/src/cpu/instruction.h +++ b/src/cpu/instruction.h @@ -60,4 +60,7 @@ #define FUNC3_OR 0x7 #define FUNC3_AND 0x8 +#define IMM_ECALL 0x0 +#define IMM_EBREAK 0x1 + #endif diff --git a/src/cpu/rv32cpu.c b/src/cpu/rv32cpu.c index 8ee2816..090b1ea 100644 --- a/src/cpu/rv32cpu.c +++ b/src/cpu/rv32cpu.c @@ -35,6 +35,8 @@ typedef struct INSTRUCTION uint8_t rs2; } instruction_t; +static void cpu_print_instruction(instruction_t* instruction); + void cpu_init() { cpu0 = malloc(sizeof(rv32_cpu_t)); @@ -99,6 +101,9 @@ static void cpu_decode(raw_instruction_t raw_instruction, instruction_t* output) // Bits of rd are immediate bits 4:0 output->immediate |= raw_instruction.rd; break; + case OPCODE_NOP: + // TODO : Decode NOP instructions + break; default: fprintf(stderr, "Error: Unknown instruction opcode 0x%x, could not decode\n", raw_instruction.opcode); exit(EXIT_FAILURE); @@ -300,12 +305,12 @@ static void cpu_execute(rv32_cpu_t* cpu, instruction_t* instruction) break; case FUNC3_SLLI: // Sign-extend immediate in rs2 from 5 bits to 32 bits - immediate = (cpu->regs.x[instruction->rs2] & 0x1F) | (cpu->regs.x[instruction->rs2] & 0x10 ? 0xFFFFFFE0 : 0); + immediate = (instruction->rs2 & 0x1F) | (instruction->rs2 & 0x10 ? 0xFFFFFFE0 : 0); cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] << immediate; break; case FUNC3_SRLI_SRAI: // Sign-extend immediate in rs2 from 5 bits to 32 bits - immediate = (cpu->regs.x[instruction->rs2] & 0x1F) | (cpu->regs.x[instruction->rs2] & 0x10 ? 0xFFFFFFE0 : 0); + immediate = (instruction->rs2 & 0x1F) | (instruction->rs2 & 0x10 ? 0xFFFFFFE0 : 0); // Analyse func7 to know which is it switch(instruction->func7) { @@ -314,10 +319,7 @@ static void cpu_execute(rv32_cpu_t* cpu, instruction_t* instruction) break; case FUNC7_SRAI: // Arithmetic slide - uint32_t sign_bit = cpu->regs.x[instruction->rs1] & 0x80000000; - cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] >> immediate; - if(sign_bit) - cpu->regs.x[instruction->rd] |= ~(0xFFFFFFFF >> immediate); + cpu->regs.x[instruction->rd] = ((int32_t) cpu->regs.x[instruction->rs1]) >> immediate; break; default: fprintf(stderr, "FATAL: Unknown func7 0x%x for arithlog immediate SRLI/SRAI instruction, could not execute\n", instruction->func7); @@ -392,10 +394,7 @@ static void cpu_execute(rv32_cpu_t* cpu, instruction_t* instruction) case FUNC7_SRA: // Slide Right Arithmetical uint32_t sra_value = cpu->regs.x[instruction->rs2] & 0x1F; - uint32_t sign_bit = cpu->regs.x[instruction->rs1] & 0x80000000; - cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] >> sra_value; - if(sign_bit) - cpu->regs.x[instruction->rd] |= ~(0xFFFFFFFF >> sra_value); + cpu->regs.x[instruction->rd] = ((int32_t) cpu->regs.x[instruction->rs1]) >> sra_value; break; default: fprintf(stderr, "FATAL: Unknown func7 0x%x for arithlog SRL/SRA instruction, could not execute\n", instruction->func7); @@ -413,11 +412,24 @@ static void cpu_execute(rv32_cpu_t* cpu, instruction_t* instruction) case OPCODE_NOP: { // TODO : Implement PAUSE, FENCE, FENCE.TSO + fprintf(stderr, "Warning: Unsupported NOP instruction\n"); break; } case OPCODE_SYSTEM: { - // TODO : Implement ECALL, EBREAK + switch(instruction->immediate) + { + case IMM_ECALL: + fprintf(stderr, "ECALL: a7(sbi ext id) = %d, a6(sbi funct id) = %d\n", cpu->regs.a7, cpu->regs.a6); + break; + case IMM_EBREAK: + fprintf(stderr, "EBREAK\n"); + break; + default: + fprintf(stderr, "FATAL: Unknown SYSTEM instruction while executing (IMM=0x%x)\n", instruction->immediate); + exit(EXIT_FAILURE); + break; + } break; } default: @@ -444,9 +456,296 @@ void cpu_loop(rv32_cpu_t* cpu) instruction_t instruction; cpu_decode(raw_instruction, &instruction); + cpu_print_instruction(&instruction); + // Execute cpu_execute(cpu, &instruction); cpu->pc += 4; } } + +static void cpu_print_instruction(instruction_t* instruction) +{ + switch(instruction->opcode) + { + case OPCODE_LUI: + { + // Load Upper Immediate (load immediate(31:12 bits) in rd) + printf("lui x%u, 0x%x\n", instruction->rd, instruction->immediate); + break; + } + case OPCODE_AUIPC: + { + // Add Upper Immediate to PC + printf("auipc x%u, 0x%x\n", instruction->rd, instruction->immediate); + break; + } + case OPCODE_JAL: + { + // Jump And Link + // Sign extend immediate from 21 bits to 32 bits + uint32_t immediate = (instruction->immediate & 0x1FFFFF) | (instruction->immediate & 0x100000 ? 0xFFE00000 : 0); + printf("jal x%u, 0x%x\n", instruction->rd, immediate); + break; + } + case OPCODE_JALR: + { + // Jump And Link Register + // Sign extend immediate from 12 bits to 32 bits + uint32_t immediate = (instruction->immediate & 0xFFF) | (instruction->immediate & 0x800 ? 0xFFFFF000 : 0); + printf("jalr x%u, x%u, 0x%x\n", instruction->rd, instruction->rs1, immediate); + break; + } + case OPCODE_BRANCH: + { + // Branches ; to know which one, we must analyse func3 + // Sign extend immediate from 13 bits to 32 bits + uint32_t immediate = (instruction->immediate & 0xFFF) | (instruction->immediate & 0x1000 ? 0xFFFFE000 : 0); + immediate -= 4; + + switch(instruction->func3) + { + case FUNC3_BEQ: + // Branch EQual + printf("beq x%u, x%u, 0x%x\n", instruction->rs1, instruction->rs2, immediate); + break; + case FUNC3_BNE: + // Branch Not Equal + printf("bne x%u, x%u, 0x%x\n", instruction->rs1, instruction->rs2, immediate); + break; + case FUNC3_BLT: + // Branch Less Than + printf("blt x%u, x%u, %d\n", instruction->rs1, instruction->rs2, (int32_t) immediate); + break; + case FUNC3_BLTU: + // Branch Less Than Unsigned + printf("bltu x%u, x%u, 0x%x\n", instruction->rs1, instruction->rs2, immediate); + break; + case FUNC3_BGE: + // Branch Greater Equal + printf("bge x%u, x%u, %d\n", instruction->rs1, instruction->rs2, (int32_t) immediate); + break; + case FUNC3_BGEU: + // Branch Greater Equal Unsigned + printf("bgeu x%u, x%u, 0x%x\n", instruction->rs1, instruction->rs2, immediate); + break; + default: + fprintf(stderr, "Warning: Unknown func3 0x%x for branch instruction\n", instruction->func3); + break; + } + break; + } + case OPCODE_LOAD: + { + // Loads ; to know which one, we must analyse func3 + // Sign extend immediate from 12 bits to 32 bits + uint32_t immediate = (instruction->immediate & 0xFFF) | (instruction->immediate & 0x800 ? 0xFFFFF000 : 0); + + switch(instruction->func3) + { + case FUNC3_LB: + printf("lb x%u, x%u, 0x%x\n", instruction->rd, instruction->rs1, immediate); + break; + case FUNC3_LH: + // Load Halfword (16-bits) + printf("lh x%u, x%u, 0x%x\n", instruction->rd, instruction->rs1, immediate); + break; + case FUNC3_LW: + // Load Word (32-bits) + printf("lw x%u, x%u, 0x%x\n", instruction->rd, instruction->rs1, immediate); + break; + case FUNC3_LBU: + // Load Byte Unsigned (8-bits) + printf("lbu x%u, x%u, 0x%x\n", instruction->rd, instruction->rs1, immediate); + break; + case FUNC3_LHU: + // Load Halfword Unsigned (16-bits) + printf("lhu x%u, x%u, 0x%x\n", instruction->rd, instruction->rs1, immediate); + break; + default: + fprintf(stderr, "Warning: Unknown func3 0x%x for load instruction\n", instruction->func3); + break; + } + break; + } + case OPCODE_STORE: + { + // Store ; to know which one, we must analyse func3 + // Sign extend immediate from 12 bits to 32 bits + uint32_t immediate = (instruction->immediate & 0xFFF) | (instruction->immediate & 0x800 ? 0xFFFFF000 : 0); + + switch(instruction->func3) + { + case FUNC3_SB: + // Store Byte (8-bits) + printf("sb x%u, x%u, 0x%x\n", instruction->rs1, instruction->rs2, immediate); + break; + case FUNC3_SH: + // Store Halfword (16-bits) + printf("sh x%u, x%u, 0x%x\n", instruction->rs1, instruction->rs2, immediate); + break; + case FUNC3_SW: + // Store Word (32-bits) + printf("sw x%u, x%u, 0x%x\n", instruction->rs1, instruction->rs2, immediate); + break; + default: + fprintf(stderr, "Warning: Unknown func3 0x%x for store instruction\n", instruction->func3); + break; + } + + break; + } + case OPCODE_ARITHLOG_IMM: + { + // Arithmetic and logic instructions on immediate values + // To find out which operation, we must analyse func3 + // Sign extend immediate from 12 bits to 32 bits + uint32_t immediate = (instruction->immediate & 0xFFF) | (instruction->immediate & 0x800 ? 0xFFFFF000 : 0); + + switch(instruction->func3) + { + case FUNC3_ADDI: + // ADD Immediate + printf("addi x%u, x%u, 0x%x\n", instruction->rd, instruction->rs1, immediate); + break; + case FUNC3_SLTI: + // Set Less Than Immediate + printf("slti x%u, x%u, 0x%x\n", instruction->rd, instruction->rs1, immediate); + break; + case FUNC3_SLTIU: + printf("sltiu x%u, x%u, 0x%x\n", instruction->rd, instruction->rs1, immediate); + break; + case FUNC3_XORI: + // XOR Immediate + printf("xori x%u, x%u, 0x%x\n", instruction->rd, instruction->rs1, immediate); + break; + case FUNC3_ORI: + // OR Immediate + printf("ori x%u, x%u, 0x%x\n", instruction->rd, instruction->rs1, immediate); + break; + case FUNC3_ANDI: + // AND Immediate + printf("andi x%u, x%u, 0x%x\n", instruction->rd, instruction->rs1, immediate); + break; + case FUNC3_SLLI: + // Sign-extend immediate in rs2 from 5 bits to 32 bits + immediate = (instruction->rs2 & 0x1F) | (instruction->rs2 & 0x10 ? 0xFFFFFFE0 : 0); + printf("slli x%u, x%u, %u\n", instruction->rd, instruction->rs1, immediate); + break; + case FUNC3_SRLI_SRAI: + // Sign-extend immediate in rs2 from 5 bits to 32 bits + immediate = (instruction->rs2 & 0x1F) | (instruction->rs2 & 0x10 ? 0xFFFFFFE0 : 0); + // Analyse func7 to know which is it + switch(instruction->func7) + { + case FUNC7_SRLI: + printf("srli x%u, x%u, %u\n", instruction->rd, instruction->rs1, immediate); + break; + case FUNC7_SRAI: + // Arithmetic slide + printf("srai x%u, x%u, %u\n", instruction->rd, instruction->rs1, immediate); + break; + default: + fprintf(stderr, "Warning: Unknown func7 0x%x for arithlog immediate SRLI/SRAI instruction\n", instruction->func7); + break; + } + break; + default: + fprintf(stderr, "Warning: Unknown func3 0x%x for arithlog immediate instruction, could not execute\n", instruction->func3); + break; + } + break; + } + case OPCODE_ARITHLOG: + { + // Arithmetic and logic instructions + // To find out which operation, we must analyse func3 and func7 + switch(instruction->func3) + { + case FUNC3_ADD_SUB: + switch(instruction->func7) + { + case FUNC7_ADD: + printf("add x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + break; + case FUNC7_SUB: + printf("sub 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); + break; + } + break; + case FUNC3_SLL: + // Slide Left Logical + printf("sll x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + break; + case FUNC3_SLT: + // Set Less Than + printf("slt x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + break; + case FUNC3_SLTIU: + // Set Less Than Unsigned + printf("sltu x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + break; + case FUNC3_XOR: + printf("xor x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + break; + case FUNC3_OR: + printf("or x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + break; + case FUNC3_AND: + printf("and x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + break; + case FUNC3_SRL_SRA: + switch(instruction->func7) + { + case FUNC7_SRL: + // Slide Right Logical + printf("srl x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); + break; + case FUNC7_SRA: + // Slide Right Arithmetical + printf("sra 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); + break; + } + break; + default: + fprintf(stderr, "Warning: Unknown func3 0x%x for arithlog instruction\n", instruction->func3); + exit(EXIT_FAILURE); + break; + } + break; + } + case OPCODE_NOP: + { + // TODO : Implement PAUSE, FENCE, FENCE.TSO + fprintf(stderr, "Warning: Unsupported NOP instruction\n"); + break; + } + case OPCODE_SYSTEM: + { + switch(instruction->immediate) + { + case IMM_ECALL: + printf("ecall\n"); + break; + case IMM_EBREAK: + printf("ebreak\n"); + break; + default: + fprintf(stderr, "Warning: Unknown SYSTEM instruction (IMM=0x%x)\n", instruction->immediate); + break; + } + break; + } + default: + fprintf(stderr, "Warning: Unknown instruction opcode 0x%x while printing\n", instruction->opcode); + break; + } +}