Initial commit
Added base code, can run ELF files and simulate RV32I instructions
This commit is contained in:
63
src/cpu/instruction.h
Normal file
63
src/cpu/instruction.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#ifndef INSTRUCTION_H
|
||||
#define INSTRUCTION_H
|
||||
|
||||
/* RISC-V RV32 I Base Instruction Set */
|
||||
#define OPCODE_LUI 0x37
|
||||
#define OPCODE_AUIPC 0x17
|
||||
#define OPCODE_JAL 0x6F
|
||||
#define OPCODE_JALR 0x67
|
||||
#define OPCODE_BRANCH 0x63
|
||||
#define OPCODE_LOAD 0x3
|
||||
#define OPCODE_STORE 0x23
|
||||
#define OPCODE_ARITHLOG_IMM 0x13
|
||||
#define OPCODE_ARITHLOG 0x33
|
||||
#define OPCODE_NOP 0xF
|
||||
#define OPCODE_SYSTEM 0x73
|
||||
|
||||
/* OPCODE_BRANCH sub functions (func3) */
|
||||
#define FUNC3_BEQ 0x0
|
||||
#define FUNC3_BNE 0x1
|
||||
#define FUNC3_BLT 0x4
|
||||
#define FUNC3_BGE 0x5
|
||||
#define FUNC3_BLTU 0x6
|
||||
#define FUNC3_BGEU 0x7
|
||||
|
||||
/* OPCODE_LOAD sub functions (func3) */
|
||||
#define FUNC3_LB 0x0
|
||||
#define FUNC3_LH 0x1
|
||||
#define FUNC3_LW 0x2
|
||||
#define FUNC3_LBU 0x4
|
||||
#define FUNC3_LHU 0x5
|
||||
|
||||
/* OPCODE_STORE sub functions (func3) */
|
||||
#define FUNC3_SB 0x0
|
||||
#define FUNC3_SH 0x1
|
||||
#define FUNC3_SW 0x2
|
||||
|
||||
/* OPCODE_ARITHLOG_IMM sub functions (func3 + func7) */
|
||||
#define FUNC3_ADDI 0x0
|
||||
#define FUNC3_SLTI 0x2
|
||||
#define FUNC3_SLTIU 0x3
|
||||
#define FUNC3_XORI 0x4
|
||||
#define FUNC3_ORI 0x6
|
||||
#define FUNC3_ANDI 0x7
|
||||
#define FUNC3_SLLI 0x1
|
||||
#define FUNC3_SRLI_SRAI 0x5
|
||||
#define FUNC7_SRLI 0x0
|
||||
#define FUNC7_SRAI 0x20
|
||||
|
||||
/* OPCODE_ARITHLOG sub functions (func3 + func7) */
|
||||
#define FUNC3_ADD_SUB 0x0
|
||||
#define FUNC7_ADD 0x0
|
||||
#define FUNC7_SUB 0x20
|
||||
#define FUNC3_SLL 0x1
|
||||
#define FUNC3_SLT 0x2
|
||||
#define FUNC3_SLTU 0x3
|
||||
#define FUNC3_XOR 0x4
|
||||
#define FUNC3_SRL_SRA 0x5
|
||||
#define FUNC7_SRL 0x0
|
||||
#define FUNC7_SRA 0x20
|
||||
#define FUNC3_OR 0x7
|
||||
#define FUNC3_AND 0x8
|
||||
|
||||
#endif
|
452
src/cpu/rv32cpu.c
Normal file
452
src/cpu/rv32cpu.c
Normal file
@@ -0,0 +1,452 @@
|
||||
#include "rv32cpu.h"
|
||||
#include "instruction.h"
|
||||
|
||||
#include "memory/memory.h"
|
||||
#include "memory/mmu/mmu.h"
|
||||
#include "vriscv.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
rv32_cpu_t* cpu0;
|
||||
|
||||
typedef union RAW_INSTRUCTION
|
||||
{
|
||||
uint32_t data;
|
||||
struct
|
||||
{
|
||||
uint8_t opcode : 7;
|
||||
uint16_t rd : 5;
|
||||
uint16_t func3 : 3;
|
||||
uint16_t rs1 : 5;
|
||||
uint16_t rs2 : 5;
|
||||
uint16_t func7 : 7;
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed)) raw_instruction_t;
|
||||
|
||||
typedef struct INSTRUCTION
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint32_t immediate;
|
||||
uint8_t func3;
|
||||
uint8_t func7;
|
||||
uint8_t rd;
|
||||
uint8_t rs1;
|
||||
uint8_t rs2;
|
||||
} instruction_t;
|
||||
|
||||
void cpu_init()
|
||||
{
|
||||
cpu0 = malloc(sizeof(rv32_cpu_t));
|
||||
cpu0->regs.zero = 0;
|
||||
}
|
||||
|
||||
static void cpu_decode(raw_instruction_t raw_instruction, instruction_t* output)
|
||||
{
|
||||
output->opcode = raw_instruction.opcode;
|
||||
output->immediate = 0;
|
||||
output->func3 = raw_instruction.func3;
|
||||
output->func7 = raw_instruction.func7;
|
||||
output->rd = raw_instruction.rd;
|
||||
output->rs1 = raw_instruction.rs1;
|
||||
output->rs2 = raw_instruction.rs2;
|
||||
|
||||
// Decode immediate, and make sure opcode is correct
|
||||
switch(raw_instruction.opcode)
|
||||
{
|
||||
// U-type instructions
|
||||
case OPCODE_LUI:
|
||||
case OPCODE_AUIPC:
|
||||
output->immediate = raw_instruction.data & 0xFFFFF000;
|
||||
break;
|
||||
// J-type instructions
|
||||
case OPCODE_JAL:
|
||||
// Last bit (31) of data is immediate bit 20
|
||||
output->immediate = (raw_instruction.data & 0x80000000) >> 11;
|
||||
// Then following 10 bits (30-21) are immediate bits 10-1
|
||||
output->immediate |= (raw_instruction.data & 0x7FE00000) >> 20;
|
||||
// Following bit (20) is immediate bit 11
|
||||
output->immediate |= (raw_instruction.data & 0x200000) >> 10;
|
||||
// Last bits (19-12) are immediate bits 19-12
|
||||
output->immediate |= (raw_instruction.data & 0xFF000);
|
||||
break;
|
||||
// I-type instructions
|
||||
case OPCODE_JALR:
|
||||
case OPCODE_LOAD:
|
||||
case OPCODE_ARITHLOG_IMM:
|
||||
case OPCODE_SYSTEM:
|
||||
// Bits 31-20 are immediate bits 11-0
|
||||
output->immediate = (raw_instruction.data & 0xFFF00000) >> 20;
|
||||
break;
|
||||
// B-type instructions
|
||||
case OPCODE_BRANCH:
|
||||
// Last bit (31) of data is immediate bit 12
|
||||
output->immediate = (raw_instruction.data & 0x80000000) >> 19;
|
||||
// Then following 6 bits (30-25) are immediate bits 10-5
|
||||
output->immediate |= (raw_instruction.data & 0x7E000000) >> 20;
|
||||
// On rd field, last 4 bits (4:1) are immediate bits 4:1
|
||||
output->immediate |= (raw_instruction.rd & 0x1E);
|
||||
// On rd field, first bit (0) is immediate bit 11
|
||||
output->immediate |= (raw_instruction.rd & 0x01) << 11;
|
||||
break;
|
||||
// R-type instructions
|
||||
case OPCODE_ARITHLOG:
|
||||
break;
|
||||
// S-type instructions
|
||||
case OPCODE_STORE:
|
||||
// Bits 31-25 (func7) are immediate bits 11:5
|
||||
output->immediate = raw_instruction.func7 << 5;
|
||||
// Bits of rd are immediate bits 4:0
|
||||
output->immediate |= raw_instruction.rd;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Error: Unknown instruction opcode 0x%x, could not decode\n", raw_instruction.opcode);
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void cpu_execute(rv32_cpu_t* cpu, instruction_t* instruction)
|
||||
{
|
||||
switch(instruction->opcode)
|
||||
{
|
||||
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);
|
||||
cpu->pc += immediate - 4;
|
||||
break;
|
||||
}
|
||||
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);
|
||||
cpu->pc = ((cpu->regs.x[instruction->rs1] + immediate) & 0xFFFFFFFE) - 4;
|
||||
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
|
||||
if(cpu->regs.x[instruction->rs1] == cpu->regs.x[instruction->rs2])
|
||||
cpu->pc = immediate;
|
||||
break;
|
||||
case FUNC3_BNE:
|
||||
// Branch Not Equal
|
||||
if(cpu->regs.x[instruction->rs1] != cpu->regs.x[instruction->rs2])
|
||||
cpu->pc = immediate;
|
||||
break;
|
||||
case FUNC3_BLT:
|
||||
// Branch Less Than
|
||||
if(((int32_t) cpu->regs.x[instruction->rs1]) < ((int32_t) cpu->regs.x[instruction->rs2]))
|
||||
cpu->pc = immediate;
|
||||
break;
|
||||
case FUNC3_BLTU:
|
||||
// Branch Less Than Unsigned
|
||||
if(cpu->regs.x[instruction->rs1] < cpu->regs.x[instruction->rs2])
|
||||
cpu->pc = immediate;
|
||||
break;
|
||||
case FUNC3_BGE:
|
||||
// Branch Greater Equal
|
||||
if(((int32_t) cpu->regs.x[instruction->rs1]) >= ((int32_t) cpu->regs.x[instruction->rs2]))
|
||||
cpu->pc = immediate;
|
||||
break;
|
||||
case FUNC3_BGEU:
|
||||
// Branch Greater Equal Unsigned
|
||||
if(cpu->regs.x[instruction->rs1] >= cpu->regs.x[instruction->rs2])
|
||||
cpu->pc = immediate;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "FATAL: Unknown func3 0x%x for branch instruction, could not execute\n", instruction->func3);
|
||||
exit(EXIT_FAILURE);
|
||||
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);
|
||||
uint32_t address = cpu->regs.x[instruction->rs1] + immediate;
|
||||
|
||||
switch(instruction->func3)
|
||||
{
|
||||
case FUNC3_LB:
|
||||
// Load Byte (8-bits)
|
||||
cpu->regs.x[instruction->rd] = memory[mmu_translate(address)];
|
||||
// Sign extend from 8 bits to 32 bits
|
||||
cpu->regs.x[instruction->rd] |= (cpu->regs.x[instruction->rd] & 0x80 ? 0xFFFFFF00 : 0);
|
||||
break;
|
||||
case FUNC3_LH:
|
||||
// Load Halfword (16-bits)
|
||||
cpu->regs.x[instruction->rd] = *((uint16_t*) &memory[mmu_translate(address)]);
|
||||
// Sign extend from 16 bits to 32 bits
|
||||
cpu->regs.x[instruction->rd] |= (cpu->regs.x[instruction->rd] & 0x8000 ? 0xFFFF0000 : 0);
|
||||
break;
|
||||
case FUNC3_LW:
|
||||
// Load Word (32-bits)
|
||||
cpu->regs.x[instruction->rd] = *((uint32_t*) &memory[mmu_translate(address)]);
|
||||
break;
|
||||
case FUNC3_LBU:
|
||||
// Load Byte Unsigned (8-bits)
|
||||
cpu->regs.x[instruction->rd] = memory[mmu_translate(address)];
|
||||
break;
|
||||
case FUNC3_LHU:
|
||||
// Load Halfword Unsigned (16-bits)
|
||||
cpu->regs.x[instruction->rd] = *((uint16_t*) &memory[mmu_translate(address)]);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "FATAL: Unknown func3 0x%x for load instruction, could not execute\n", instruction->func3);
|
||||
exit(EXIT_FAILURE);
|
||||
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);
|
||||
uint32_t address = cpu->regs.x[instruction->rs1] + immediate;
|
||||
|
||||
switch(instruction->func3)
|
||||
{
|
||||
case FUNC3_SB:
|
||||
// Store Byte (8-bits)
|
||||
memory[mmu_translate(address)] = cpu->regs.x[instruction->rs2] & 0xFF;
|
||||
break;
|
||||
case FUNC3_SH:
|
||||
// Store Halfword (16-bits)
|
||||
*((uint16_t*) &memory[mmu_translate(address)]) = cpu->regs.x[instruction->rs2] & 0xFFFF;
|
||||
break;
|
||||
case FUNC3_SW:
|
||||
// Store Word (32-bits)
|
||||
*((uint32_t*) &memory[mmu_translate(address)]) = cpu->regs.x[instruction->rs2];
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "FATAL: Unknown func3 0x%x for store instruction, could not execute\n", instruction->func3);
|
||||
exit(EXIT_FAILURE);
|
||||
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
|
||||
cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] + immediate;
|
||||
break;
|
||||
case FUNC3_SLTI:
|
||||
// Set Less Than Immediate
|
||||
if(((int32_t) cpu->regs.x[instruction->rs1]) < ((int32_t) immediate))
|
||||
cpu->regs.x[instruction->rd] = 1;
|
||||
else
|
||||
cpu->regs.x[instruction->rd] = 0;
|
||||
break;
|
||||
case FUNC3_SLTIU:
|
||||
// Set Less Than Immediate Unsigned
|
||||
if(cpu->regs.x[instruction->rs1] < immediate)
|
||||
cpu->regs.x[instruction->rd] = 1;
|
||||
else
|
||||
cpu->regs.x[instruction->rd] = 0;
|
||||
break;
|
||||
case FUNC3_XORI:
|
||||
// XOR Immediate
|
||||
cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] ^ immediate;
|
||||
break;
|
||||
case FUNC3_ORI:
|
||||
// OR Immediate
|
||||
cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] | immediate;
|
||||
break;
|
||||
case FUNC3_ANDI:
|
||||
// AND Immediate
|
||||
cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] & immediate;
|
||||
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);
|
||||
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);
|
||||
// Analyse func7 to know which is it
|
||||
switch(instruction->func7)
|
||||
{
|
||||
case FUNC7_SRLI:
|
||||
cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] >> immediate;
|
||||
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);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "FATAL: Unknown func7 0x%x for arithlog immediate SRLI/SRAI instruction, could not execute\n", instruction->func7);
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "FATAL: Unknown func3 0x%x for arithlog immediate instruction, could not execute\n", instruction->func3);
|
||||
exit(EXIT_FAILURE);
|
||||
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:
|
||||
cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] + cpu->regs.x[instruction->rs2];
|
||||
break;
|
||||
case FUNC7_SUB:
|
||||
cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] - cpu->regs.x[instruction->rs2];
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "FATAL: Unknown func7 0x%x for arithlog ADD/SUB instruction, could not execute\n", instruction->func7);
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FUNC3_SLL:
|
||||
// Slide Left Logical
|
||||
uint32_t sll_value = cpu->regs.x[instruction->rs2] & 0x1F;
|
||||
cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] << sll_value;
|
||||
break;
|
||||
case FUNC3_SLT:
|
||||
// Set Less Than
|
||||
if(((int32_t) cpu->regs.x[instruction->rs1]) < ((int32_t) cpu->regs.x[instruction->rs2]))
|
||||
cpu->regs.x[instruction->rd] = 1;
|
||||
else
|
||||
cpu->regs.x[instruction->rd] = 0;
|
||||
break;
|
||||
case FUNC3_SLTIU:
|
||||
// Set Less Than Unsigned
|
||||
if(cpu->regs.x[instruction->rs1] < cpu->regs.x[instruction->rs2])
|
||||
cpu->regs.x[instruction->rd] = 1;
|
||||
else
|
||||
cpu->regs.x[instruction->rd] = 0;
|
||||
break;
|
||||
case FUNC3_XOR:
|
||||
cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] ^ cpu->regs.x[instruction->rs2];
|
||||
break;
|
||||
case FUNC3_OR:
|
||||
cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] | cpu->regs.x[instruction->rs2];
|
||||
break;
|
||||
case FUNC3_AND:
|
||||
cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] & cpu->regs.x[instruction->rs2];
|
||||
break;
|
||||
case FUNC3_SRL_SRA:
|
||||
switch(instruction->func7)
|
||||
{
|
||||
case FUNC7_SRL:
|
||||
// Slide Right Logical
|
||||
uint32_t srl_value = cpu->regs.x[instruction->rs2] & 0x1F;
|
||||
cpu->regs.x[instruction->rd] = cpu->regs.x[instruction->rs1] >> srl_value;
|
||||
break;
|
||||
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);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "FATAL: Unknown func7 0x%x for arithlog SRL/SRA instruction, could not execute\n", instruction->func7);
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "FATAL: Unknown func3 0x%x for arithlog instruction, could not execute\n", instruction->func3);
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OPCODE_NOP:
|
||||
{
|
||||
// TODO : Implement PAUSE, FENCE, FENCE.TSO
|
||||
break;
|
||||
}
|
||||
case OPCODE_SYSTEM:
|
||||
{
|
||||
// TODO : Implement ECALL, EBREAK
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fprintf(stderr, "FATAL: Unknown instruction opcode 0x%x while executing; how could this decode ?\n", instruction->opcode);
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_loop(rv32_cpu_t* cpu)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
// Fetch
|
||||
raw_instruction_t raw_instruction;
|
||||
if(cpu->pc > memory_size - 4)
|
||||
{
|
||||
fprintf(stderr, "Error: instruction fetch: pc is out of addressable memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
raw_instruction.data = *((uint32_t*) (&memory[cpu->pc]));
|
||||
|
||||
// Decode
|
||||
instruction_t instruction;
|
||||
cpu_decode(raw_instruction, &instruction);
|
||||
|
||||
// Execute
|
||||
cpu_execute(cpu, &instruction);
|
||||
|
||||
cpu->pc += 4;
|
||||
}
|
||||
}
|
194
src/cpu/rv32cpu.h
Normal file
194
src/cpu/rv32cpu.h
Normal file
@@ -0,0 +1,194 @@
|
||||
#ifndef RV32CPU_H
|
||||
#define RV32CPU_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* This is a structure encoding for the registers of
|
||||
* the rv32 cpu.
|
||||
* It allows access of register x0 using :
|
||||
* structname.x0, structname.zero, structname.x[0]
|
||||
* This way, access can be really flexible
|
||||
*/
|
||||
typedef struct RV32_CPU_REGS
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
union
|
||||
{
|
||||
uint32_t x0;
|
||||
uint32_t zero;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x1;
|
||||
uint32_t ra;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x2;
|
||||
uint32_t sp;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x3;
|
||||
uint32_t gp;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x4;
|
||||
uint32_t tp;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x5;
|
||||
uint32_t t0;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x6;
|
||||
uint32_t t1;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x7;
|
||||
uint32_t t2;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x8;
|
||||
uint32_t s0;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x9;
|
||||
uint32_t s1;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x10;
|
||||
uint32_t a0;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x11;
|
||||
uint32_t a1;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x12;
|
||||
uint32_t a2;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x13;
|
||||
uint32_t a3;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x14;
|
||||
uint32_t a4;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x15;
|
||||
uint32_t a5;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x16;
|
||||
uint32_t a6;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x17;
|
||||
uint32_t a7;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x18;
|
||||
uint32_t s2;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x19;
|
||||
uint32_t s3;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x20;
|
||||
uint32_t s4;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x21;
|
||||
uint32_t s5;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x22;
|
||||
uint32_t s6;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x23;
|
||||
uint32_t s7;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x24;
|
||||
uint32_t s8;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x25;
|
||||
uint32_t s9;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x26;
|
||||
uint32_t s10;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x27;
|
||||
uint32_t s11;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x28;
|
||||
uint32_t t3;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x29;
|
||||
uint32_t t4;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x30;
|
||||
uint32_t t5;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t x31;
|
||||
uint32_t t6;
|
||||
};
|
||||
};
|
||||
uint32_t x[32];
|
||||
};
|
||||
} rv32_cpu_regs_t;
|
||||
|
||||
typedef struct RV32_CPU
|
||||
{
|
||||
rv32_cpu_regs_t regs;
|
||||
uint32_t pc;
|
||||
} rv32_cpu_t;
|
||||
|
||||
extern rv32_cpu_t* cpu0;
|
||||
void cpu_init();
|
||||
void cpu_loop(rv32_cpu_t* cpu);
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user