|
|
|
@ -93,6 +93,7 @@ static void cpu_decode(raw_instruction_t raw_instruction, instruction_t* output) |
|
|
|
|
break; |
|
|
|
|
// R-type instructions
|
|
|
|
|
case OPCODE_ARITHLOG: |
|
|
|
|
case OPCODE_ATOMIC: |
|
|
|
|
break; |
|
|
|
|
// S-type instructions
|
|
|
|
|
case OPCODE_STORE: |
|
|
|
@ -118,21 +119,18 @@ static void cpu_execute(rv32_cpu_t* cpu, instruction_t* instruction) |
|
|
|
|
case OPCODE_LUI: |
|
|
|
|
{ |
|
|
|
|
// Load Upper Immediate (load immediate(31:12 bits) in rd)
|
|
|
|
|
if(instruction->rd) |
|
|
|
|
cpu->regs.x[instruction->rd] = instruction->immediate; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
case OPCODE_AUIPC: |
|
|
|
|
{ |
|
|
|
|
// Add Upper Immediate to PC
|
|
|
|
|
if(instruction->rd) |
|
|
|
|
cpu->regs.x[instruction->rd] = instruction->immediate + cpu->pc; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
case OPCODE_JAL: |
|
|
|
|
{ |
|
|
|
|
// Jump And Link
|
|
|
|
|
if(instruction->rd) |
|
|
|
|
cpu->regs.x[instruction->rd] = cpu->pc + 4; |
|
|
|
|
// Sign extend immediate from 21 bits to 32 bits
|
|
|
|
|
uint32_t immediate = (instruction->immediate & 0x1FFFFF) | (instruction->immediate & 0x100000 ? 0xFFE00000 : 0); |
|
|
|
@ -142,7 +140,6 @@ static void cpu_execute(rv32_cpu_t* cpu, instruction_t* instruction) |
|
|
|
|
case OPCODE_JALR: |
|
|
|
|
{ |
|
|
|
|
// Jump And Link Register
|
|
|
|
|
if(instruction->rd) |
|
|
|
|
cpu->regs.x[instruction->rd] = cpu->pc + 4; |
|
|
|
|
// Sign extend immediate from 12 bits to 32 bits
|
|
|
|
|
uint32_t immediate = (instruction->immediate & 0xFFF) | (instruction->immediate & 0x800 ? 0xFFFFF000 : 0); |
|
|
|
@ -460,6 +457,97 @@ static void cpu_execute(rv32_cpu_t* cpu, instruction_t* instruction) |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
case OPCODE_ATOMIC: |
|
|
|
|
{ |
|
|
|
|
// Atomic instructions (A extension)
|
|
|
|
|
// To find out which operation, we must analyse func7 (func3 == 0x2)
|
|
|
|
|
if(instruction->func3 != FUNC3_ATOMIC) |
|
|
|
|
{ |
|
|
|
|
fprintf(stderr, "FATAL: Unknown func3 0x%x for ATOMIC instruction, could not execute\n", instruction->func3); |
|
|
|
|
exit(EXIT_FAILURE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// FUNC7 contains 2 flag bits in lower part ; ignore them, we look for func7_5
|
|
|
|
|
uint32_t address = cpu->regs.x[instruction->rs1]; |
|
|
|
|
uint32_t* ptr = ((uint32_t*) &memory[mmu_translate(address)]); |
|
|
|
|
switch(instruction->func7 >> 2) |
|
|
|
|
{ |
|
|
|
|
case FUNC75_LRW: |
|
|
|
|
// Load-Reserved Word
|
|
|
|
|
cpu->regs.x[instruction->rd] = *ptr; |
|
|
|
|
// TODO register reservation set that subsumes the bytes in word
|
|
|
|
|
fprintf(stderr, "LR.W\n"); |
|
|
|
|
break; |
|
|
|
|
case FUNC75_SCW: |
|
|
|
|
// Store-Conditional Word
|
|
|
|
|
// TODO succeed only if the reservation is still valid and the reservation set contains the bytes written
|
|
|
|
|
*ptr = cpu->regs.x[instruction->rs2]; |
|
|
|
|
cpu->regs.x[instruction->rd] = 0; // TODO write 1 in rd on failure
|
|
|
|
|
fprintf(stderr, "SC.W\n"); |
|
|
|
|
break; |
|
|
|
|
case FUNC75_AMOSWAPW: |
|
|
|
|
// Atomic Memory Operation SWAP Word
|
|
|
|
|
cpu->regs.x[instruction->rd] = *ptr; |
|
|
|
|
// Put in RS1 addr the value of RS2
|
|
|
|
|
*ptr = cpu->regs.x[instruction->rs2]; |
|
|
|
|
// Put in RS2 the value of RS1 addr (which is in RD)
|
|
|
|
|
cpu->regs.x[instruction->rs2] = cpu->regs.x[instruction->rd]; |
|
|
|
|
break; |
|
|
|
|
case FUNC75_AMOADDW: |
|
|
|
|
// Atomic Memory Operation ADD Word
|
|
|
|
|
cpu->regs.x[instruction->rd] = *ptr; |
|
|
|
|
// Add rs1 addr and value of rs2
|
|
|
|
|
*ptr = cpu->regs.x[instruction->rd] + cpu->regs.x[instruction->rs2]; |
|
|
|
|
break; |
|
|
|
|
case FUNC75_AMOXORW: |
|
|
|
|
// Atomic Memory Operation XOR Word
|
|
|
|
|
cpu->regs.x[instruction->rd] = *ptr; |
|
|
|
|
// Xor rs1 addr and value of rs2
|
|
|
|
|
*ptr = cpu->regs.x[instruction->rd] ^ cpu->regs.x[instruction->rs2]; |
|
|
|
|
break; |
|
|
|
|
case FUNC75_AMOANDW: |
|
|
|
|
// Atomic Memory Operation AND Word
|
|
|
|
|
cpu->regs.x[instruction->rd] = *ptr; |
|
|
|
|
// AND rs1 addr and value of rs2
|
|
|
|
|
*ptr = cpu->regs.x[instruction->rd] & cpu->regs.x[instruction->rs2]; |
|
|
|
|
break; |
|
|
|
|
case FUNC75_AMOORW: |
|
|
|
|
// Atomic Memory Operation OR Word
|
|
|
|
|
cpu->regs.x[instruction->rd] = *ptr; |
|
|
|
|
// Or rs1 addr and value of rs2
|
|
|
|
|
*ptr = cpu->regs.x[instruction->rd] | cpu->regs.x[instruction->rs2]; |
|
|
|
|
break; |
|
|
|
|
case FUNC75_AMOMINW: |
|
|
|
|
// Atomic Memory Operation MIN Word
|
|
|
|
|
cpu->regs.x[instruction->rd] = *ptr; |
|
|
|
|
// Min rs1 addr and value of rs2
|
|
|
|
|
*ptr = ((int32_t) cpu->regs.x[instruction->rd]) < ((int32_t) cpu->regs.x[instruction->rs2]) ? cpu->regs.x[instruction->rd] : cpu->regs.x[instruction->rs2]; |
|
|
|
|
break; |
|
|
|
|
case FUNC75_AMOMAXW: |
|
|
|
|
// Atomic Memory Operation MAX Word
|
|
|
|
|
cpu->regs.x[instruction->rd] = *ptr; |
|
|
|
|
// Max rs1 addr and value of rs2
|
|
|
|
|
*ptr = ((int32_t) cpu->regs.x[instruction->rd]) > ((int32_t) cpu->regs.x[instruction->rs2]) ? cpu->regs.x[instruction->rd] : cpu->regs.x[instruction->rs2]; |
|
|
|
|
break; |
|
|
|
|
case FUNC75_AMOMINUW: |
|
|
|
|
// Atomic Memory Operation MIN Unsigned Word
|
|
|
|
|
cpu->regs.x[instruction->rd] = *ptr; |
|
|
|
|
// Min rs1 addr and value of rs2
|
|
|
|
|
*ptr = cpu->regs.x[instruction->rd] < cpu->regs.x[instruction->rs2] ? cpu->regs.x[instruction->rd] : cpu->regs.x[instruction->rs2]; |
|
|
|
|
break; |
|
|
|
|
case FUNC75_AMOMAXUW: |
|
|
|
|
// Atomic Memory Operation MAX Unsigned Word
|
|
|
|
|
cpu->regs.x[instruction->rd] = *ptr; |
|
|
|
|
// Max rs1 addr and value of rs2
|
|
|
|
|
*ptr = cpu->regs.x[instruction->rd] > cpu->regs.x[instruction->rs2] ? cpu->regs.x[instruction->rd] : cpu->regs.x[instruction->rs2]; |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
fprintf(stderr, "FATAL: Unknown func7 0x%x for ATOMIC/0x2 instruction, could not execute\n", instruction->func7); |
|
|
|
|
exit(EXIT_FAILURE); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
default: |
|
|
|
|
fprintf(stderr, "FATAL: Unknown instruction opcode 0x%x while executing; how could this decode ?\n", instruction->opcode); |
|
|
|
|
exit(EXIT_FAILURE); |
|
|
|
@ -490,6 +578,9 @@ 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; |
|
|
|
|
|
|
|
|
|
cpu->pc += 4; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -799,6 +890,70 @@ static void cpu_print_instruction(instruction_t* instruction) |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
case OPCODE_ATOMIC: |
|
|
|
|
{ |
|
|
|
|
// Atomic instructions (A extension)
|
|
|
|
|
// To find out which operation, we must analyse func7 (func3 == 0x2)
|
|
|
|
|
if(instruction->func3 != FUNC3_ATOMIC) |
|
|
|
|
{ |
|
|
|
|
fprintf(stderr, "Warning: Unknown func3 0x%x for ATOMIC instruction\n", instruction->func3); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// FUNC7 contains 2 flag bits in lower part ; ignore them, we look for func7_5
|
|
|
|
|
switch(instruction->func7 >> 2) |
|
|
|
|
{ |
|
|
|
|
case FUNC75_LRW: |
|
|
|
|
// Load-Reserved Word
|
|
|
|
|
printf("lr.w x%u, x%u\n", instruction->rd, instruction->rs1); |
|
|
|
|
break; |
|
|
|
|
case FUNC75_SCW: |
|
|
|
|
// Store-Conditional Word
|
|
|
|
|
printf("sc.w x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); |
|
|
|
|
break; |
|
|
|
|
case FUNC75_AMOSWAPW: |
|
|
|
|
// Atomic Memory Operation SWAP Word
|
|
|
|
|
printf("amoswap.w x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); |
|
|
|
|
break; |
|
|
|
|
case FUNC75_AMOADDW: |
|
|
|
|
// Atomic Memory Operation ADD Word
|
|
|
|
|
printf("amoadd.w x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); |
|
|
|
|
break; |
|
|
|
|
case FUNC75_AMOXORW: |
|
|
|
|
// Atomic Memory Operation XOR Word
|
|
|
|
|
printf("amoxor.w x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); |
|
|
|
|
break; |
|
|
|
|
case FUNC75_AMOANDW: |
|
|
|
|
// Atomic Memory Operation AND Word
|
|
|
|
|
printf("amoand.w x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); |
|
|
|
|
break; |
|
|
|
|
case FUNC75_AMOORW: |
|
|
|
|
// Atomic Memory Operation OR Word
|
|
|
|
|
printf("amoor.w x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); |
|
|
|
|
break; |
|
|
|
|
case FUNC75_AMOMINW: |
|
|
|
|
// Atomic Memory Operation MIN Word
|
|
|
|
|
printf("amomin.w x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); |
|
|
|
|
break; |
|
|
|
|
case FUNC75_AMOMAXW: |
|
|
|
|
// Atomic Memory Operation MAX Word
|
|
|
|
|
printf("amomax.w x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); |
|
|
|
|
break; |
|
|
|
|
case FUNC75_AMOMINUW: |
|
|
|
|
// Atomic Memory Operation MIN Unsigned Word
|
|
|
|
|
printf("amominu.w x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); |
|
|
|
|
break; |
|
|
|
|
case FUNC75_AMOMAXUW: |
|
|
|
|
// Atomic Memory Operation MAX Unsigned Word
|
|
|
|
|
printf("amomaxu.w x%u, x%u, x%u\n", instruction->rd, instruction->rs1, instruction->rs2); |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
fprintf(stderr, "FATAL: Unknown func7 0x%x for ATOMIC/0x2 instruction, could not execute\n", instruction->func7); |
|
|
|
|
exit(EXIT_FAILURE); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
default: |
|
|
|
|
fprintf(stderr, "Warning: Unknown instruction opcode 0x%x while printing\n", instruction->opcode); |
|
|
|
|
break; |
|
|
|
|