Added A (Atomic) extension
This commit is contained in:
parent
1b068529c8
commit
24ca9532d4
@ -14,6 +14,23 @@
|
||||
#define OPCODE_NOP 0xF
|
||||
#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) */
|
||||
#define FUNC3_BEQ 0x0
|
||||
#define FUNC3_BNE 0x1
|
||||
|
@ -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,22 +119,19 @@ 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;
|
||||
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;
|
||||
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;
|
||||
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);
|
||||
cpu->pc += immediate - 4;
|
||||
@ -142,8 +140,7 @@ 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;
|
||||
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);
|
||||
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;
|
||||
}
|
||||
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);
|
||||
@ -489,6 +577,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;
|
||||
|
Loading…
Reference in New Issue
Block a user