Debugging instructions (system mostly)
This commit is contained in:
parent
981c35584c
commit
ad3ec2e504
@ -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…
Reference in New Issue
Block a user