Added A (Atomic) extension

master
vhaudiquet 1 year ago
parent 1b068529c8
commit 24ca9532d4
  1. 17
      src/cpu/instruction.h
  2. 171
      src/cpu/rv32cpu.c

@ -14,6 +14,23 @@
#define OPCODE_NOP 0xF #define OPCODE_NOP 0xF
#define OPCODE_SYSTEM 0x73 #define OPCODE_SYSTEM 0x73
/* RISC-V RV32 A Extension */
#define OPCODE_ATOMIC 0x2F
/* OPCODE_ATOMIC sub functions (func3 + func7) */
#define FUNC3_ATOMIC 0x2
#define FUNC75_LRW 0x2
#define FUNC75_SCW 0x3
#define FUNC75_AMOSWAPW 0x1
#define FUNC75_AMOADDW 0x0
#define FUNC75_AMOXORW 0x4
#define FUNC75_AMOANDW 0xC
#define FUNC75_AMOORW 0x8
#define FUNC75_AMOMINW 0x10
#define FUNC75_AMOMAXW 0x14
#define FUNC75_AMOMINUW 0x18
#define FUNC75_AMOMAXUW 0x1C
/* OPCODE_BRANCH sub functions (func3) */ /* OPCODE_BRANCH sub functions (func3) */
#define FUNC3_BEQ 0x0 #define FUNC3_BEQ 0x0
#define FUNC3_BNE 0x1 #define FUNC3_BNE 0x1

@ -93,6 +93,7 @@ static void cpu_decode(raw_instruction_t raw_instruction, instruction_t* output)
break; break;
// R-type instructions // R-type instructions
case OPCODE_ARITHLOG: case OPCODE_ARITHLOG:
case OPCODE_ATOMIC:
break; break;
// S-type instructions // S-type instructions
case OPCODE_STORE: case OPCODE_STORE:
@ -118,22 +119,19 @@ static void cpu_execute(rv32_cpu_t* cpu, instruction_t* instruction)
case OPCODE_LUI: case OPCODE_LUI:
{ {
// Load Upper Immediate (load immediate(31:12 bits) in rd) // Load Upper Immediate (load immediate(31:12 bits) in rd)
if(instruction->rd) cpu->regs.x[instruction->rd] = instruction->immediate;
cpu->regs.x[instruction->rd] = instruction->immediate;
break; break;
} }
case OPCODE_AUIPC: case OPCODE_AUIPC:
{ {
// Add Upper Immediate to PC // Add Upper Immediate to PC
if(instruction->rd) cpu->regs.x[instruction->rd] = instruction->immediate + cpu->pc;
cpu->regs.x[instruction->rd] = instruction->immediate + cpu->pc;
break; break;
} }
case OPCODE_JAL: case OPCODE_JAL:
{ {
// Jump And Link // Jump And Link
if(instruction->rd) cpu->regs.x[instruction->rd] = cpu->pc + 4;
cpu->regs.x[instruction->rd] = cpu->pc + 4;
// Sign extend immediate from 21 bits to 32 bits // Sign extend immediate from 21 bits to 32 bits
uint32_t immediate = (instruction->immediate & 0x1FFFFF) | (instruction->immediate & 0x100000 ? 0xFFE00000 : 0); uint32_t immediate = (instruction->immediate & 0x1FFFFF) | (instruction->immediate & 0x100000 ? 0xFFE00000 : 0);
cpu->pc += immediate - 4; cpu->pc += immediate - 4;
@ -142,8 +140,7 @@ static void cpu_execute(rv32_cpu_t* cpu, instruction_t* instruction)
case OPCODE_JALR: case OPCODE_JALR:
{ {
// Jump And Link Register // Jump And Link Register
if(instruction->rd) cpu->regs.x[instruction->rd] = cpu->pc + 4;
cpu->regs.x[instruction->rd] = cpu->pc + 4;
// Sign extend immediate from 12 bits to 32 bits // Sign extend immediate from 12 bits to 32 bits
uint32_t immediate = (instruction->immediate & 0xFFF) | (instruction->immediate & 0x800 ? 0xFFFFF000 : 0); uint32_t immediate = (instruction->immediate & 0xFFF) | (instruction->immediate & 0x800 ? 0xFFFFF000 : 0);
cpu->pc = ((cpu->regs.x[instruction->rs1] + immediate) & 0xFFFFFFFE) - 4; cpu->pc = ((cpu->regs.x[instruction->rs1] + immediate) & 0xFFFFFFFE) - 4;
@ -460,6 +457,97 @@ static void cpu_execute(rv32_cpu_t* cpu, instruction_t* instruction)
break; 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: default:
fprintf(stderr, "FATAL: Unknown instruction opcode 0x%x while executing; how could this decode ?\n", instruction->opcode); fprintf(stderr, "FATAL: Unknown instruction opcode 0x%x while executing; how could this decode ?\n", instruction->opcode);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@ -490,6 +578,9 @@ void cpu_loop(rv32_cpu_t* cpu)
// Execute // Execute
cpu_execute(cpu, &instruction); cpu_execute(cpu, &instruction);
// Reset value of zero, in case instruction tried to modify
cpu->regs.zero = 0;
cpu->pc += 4; cpu->pc += 4;
} }
} }
@ -799,6 +890,70 @@ static void cpu_print_instruction(instruction_t* instruction)
} }
break; 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: default:
fprintf(stderr, "Warning: Unknown instruction opcode 0x%x while printing\n", instruction->opcode); fprintf(stderr, "Warning: Unknown instruction opcode 0x%x while printing\n", instruction->opcode);
break; break;

Loading…
Cancel
Save