slrve/srve_core_h.h

97 lines
4.2 KiB
C
Raw Permalink Normal View History

// This file is included by srve_core.h to define the structures for either a
// 64-bit or 32-bit core. It is only included once for each bit size.
// Some definitions in here are still common to both 64-bit and 32-bit code so
// they are only defined once.
#ifndef SRVE_CORE_H_COMMON
#define SRVE_CORE_H_COMMON
// This is similar to the rv_bus_cb type in Max Nurzia's RISC-V emulator.
typedef int (*srve_memfunc_t)(void* memory, uint64_t address, void* buffer, unsigned int storing, unsigned int size);
typedef struct srve_debugsymbol srve_debugsymbol_t;
struct srve_debugsymbol {
uint64_t addr;
char* name;
srve_debugsymbol_t* next;
};
#endif
typedef STRUCT_SRVE_CORE SRVE_CORE_T;
// Type of a function which handles an instruction, returning 0 on success or
// non-zero on failure. These functions are called inbetween fetching and
// incrementing the instruction pointer, and there is generally one function
// per major instruction (per instruction-group) with the function pointers
// stored in the core structure. This allows for easy replacement of functions
// for special debugging purposes (e.g. for tracking jump instructions only or
// for checking load/store instructions for alignment).
typedef int (*SRVE_CORE_INSTRFUNC_T)(SRVE_CORE_T* core, uint32_t instr);
STRUCT_SRVE_CORE {
void* memory;
srve_memfunc_t memfunc;
srve_debugsymbol_t* symbols; // This is managed externally, but is a sorted list that can be checked for debug names
SRVE_UREG_T ip; // Instruction pointer
SRVE_UREG_T ip_next; // Next instruction pointer
SRVE_UREG_T pagetable; // Address of the page table (not quite the same format as when accessed in satp)
SRVE_UREG_T mepc; // Stored machine mode instruction pointer (program counter)
SRVE_UREG_T sepc; // System mode exception instruction pointer
SRVE_UREG_T stvec; // Vector handler address (& flags in bottom two bits)
SRVE_UREG_T sscratch; // Scratch register
SRVE_UREG_T scause;
SRVE_UREG_T tracing;
SRVE_SREG_T registers[32];
SRVE_CORE_INSTRFUNC_T instrfuncs[128]; // There are 128 possible major instructions
};
int SRVE_CORE_INIT(SRVE_CORE_T* core, srve_memfunc_t memfunc, void* memdata, SRVE_UREG_T ip);
// This instruction function is invoked for any unimplemented functions.
int SRVE_CORE_INSTR_BAD(SRVE_CORE_T* core, uint32_t instr);
// The main ALU instructions are divided between two major opcodes, one dealing
// with registers only and the other where immediate values are combined with
// registers.
int SRVE_CORE_INSTR_REGALU(SRVE_CORE_T* core, uint32_t instr);
int SRVE_CORE_INSTR_IMMALU(SRVE_CORE_T* core, uint32_t instr);
// The typical memory-to-register load instructions are all one major opcode
int SRVE_CORE_INSTR_LOAD(SRVE_CORE_T* core, uint32_t instr);
int SRVE_CORE_INSTR_STORE(SRVE_CORE_T* core, uint32_t instr);
int SRVE_CORE_INSTR_LUI(SRVE_CORE_T* core, uint32_t instr);
int SRVE_CORE_INSTR_AUIPC(SRVE_CORE_T* core, uint32_t instr);
// The syscall instruction seems to be extended for other "system" features too
int SRVE_CORE_INSTR_SYSTEM(SRVE_CORE_T* core, uint32_t instr);
int SRVE_CORE_INSTR_BRANCH(SRVE_CORE_T* core, uint32_t instr);
int SRVE_CORE_INSTR_JAL(SRVE_CORE_T* core, uint32_t instr);
int SRVE_CORE_INSTR_JALR(SRVE_CORE_T* core, uint32_t instr);
int SRVE_CORE_DOALU(SRVE_CORE_T* core, SRVE_SREG_T* outputvar, SRVE_SREG_T lhs, int op, SRVE_SREG_T rhs, int modifier);
// Returns the "physical" address of the given "virtual" address.
SRVE_UREG_T SRVE_CORE_TRANSLATE(SRVE_CORE_T* core, SRVE_UREG_T vaddr);
int SRVE_CORE_LOAD(SRVE_CORE_T* core, uint64_t addr, void* buffer, unsigned int size);
int SRVE_CORE_STORE(SRVE_CORE_T* core, uint64_t addr, void* buffer, unsigned int size);
int SRVE_CORE_READCSR(SRVE_CORE_T* core, int addr, SRVE_UREG_T* outputvar);
int SRVE_CORE_WRITECSR(SRVE_CORE_T* core, int addr, SRVE_UREG_T value);
int SRVE_CORE_FETCH(SRVE_CORE_T* core, uint32_t* instrvar);
// Looks through debug symbols to find a function name, returns the associated
// symbol or a dummy string if the symbol table or function doesn't exist. This
// is usually called with the instruction pointer as the address to reveal where
// the program is currently at.
const char* SRVE_CORE_FUNCNAME(SRVE_CORE_T* core, SRVE_UREG_T addr);
SRVE_SREG_T SRVE_CORE_DOINSTR(SRVE_CORE_T* core);