Debugging instructions (system mostly)

master
vhaudiquet 1 year ago
parent 981c35584c
commit ad3ec2e504
  1. 3
      README.md
  2. 3
      src/cpu/instruction.h
  3. 321
      src/cpu/rv32cpu.c

@ -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

@ -60,4 +60,7 @@
#define FUNC3_OR 0x7
#define FUNC3_AND 0x8
#define IMM_ECALL 0x0
#define IMM_EBREAK 0x1
#endif

@ -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;
}
}

Loading…
Cancel
Save