Added A (Atomic) extension
This commit is contained in:
		@@ -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;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user