Files
CAR/include/defs.h

265 lines
5.4 KiB
C

#ifndef _CAR_INCLUDE_DEFS_H
#define _CAR_INCLUDE_DEFS_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdio.h>
//#define _DEBUG
typedef struct
{
uint32_t gprs[32]; // register 31 is the control register (change maybe?)
uint32_t flags;
uint32_t pc;
uint32_t sp;
uint32_t* memory;
size_t memory_size; // Never let addresses go past this, or we wil get a segsev
} pstate_t;
int processor_start(pstate_t* state);
void dump_regs(pstate_t* s);
void _push(uint32_t v, pstate_t* state);
void _pop(uint32_t* a, pstate_t* state);
// returns !error (true on no error, false on error) { true on safe address, false on invalid address }
static inline bool check_addr(uint32_t addr, pstate_t* state)
{
if (addr < state->memory_size)
{
return true;
}
fprintf(stderr, "[ERROR]: memory address out of range: address 0x%x with memory size 0x%x\n", addr, (uint32_t) state->memory_size);
return false;
}
#define FLAG_CARRY (1 << 0)
#define FLAG_SIGN (1 << 1)
#define FLAG_OVERFLOW (1 << 2)
#define FLAG_ZERO (1 << 3)
#define FLAG_INTERRUPTS (1 << 4)
#define FLAG_ERROR (1 << 5)
#define FLAG_DIRECTION_ERROR (1 << 6)
#define FLAG_DIVISION_ERROR (1 << 7)
typedef uint32_t raw_instruction_t;
/*
Instruction encoding for misc operations:
instruction group: bits 0 to 1 (2 bits) {NOTE: for misc operations, should be set to 0b00}
opcode: bits 2 to 7 (6 bits)
imm: bits 8 to 31 {NOTE: depending on the opcode, could be an address, or a register indirection}
Instruction encoding for register operations:
instruction group: bits 0 to 1 (2 bits) {NOTE: for register operations, should be set to 0b01}
opcode: bits 2 to 8 (7 bits)
dest: bits 9 to 14 (5 bits)
src1 bits 15 to 20 (5 bits)
src2 bits 21 to 26 (5 bits)
all other bits unused, however should be set to zero
Instruction encoding for load/store operations:
instruction group: bits 0 to 1 (2 bits) {NOTE: for load/store operations, should be set to 0b10}
opcode: bits 2 to 5 (4 bits)
register: bits 6 to 10 (5 bits)
imm: bits 11 to 31 {NOTE: depending on the opcode, could be an address, or register indirect, or an immediate}
is be one of:
A) signed 21-bit offset from PC
B) signed 21-bit offset from SP
C) base register (5 bits) and a 16-bit signed offset from PC
D) signed 21 bit immediate
*/
typedef struct
{
uint8_t opcode;
uint32_t imm;
} misc_instruction_t;
typedef struct
{
uint8_t opcode;
uint8_t dest;
uint8_t src1;
uint8_t src2;
} register_instruction_t;
typedef struct
{
uint8_t opcode;
uint8_t reg;
uint32_t imm;
} ls_instruction_t;
misc_instruction_t convert_raw2misc(raw_instruction_t* r);
register_instruction_t convert_raw2register(raw_instruction_t* r);
ls_instruction_t convert_raw2ls(raw_instruction_t* r);
static inline uint8_t get_instruction_group(raw_instruction_t* r)
{
return ((uint32_t) (*r)) >> 30;
}
#define get_reg_from_imm(x) ((x & 0x1F0000) >> 16)
#define get_imm_from_imm(x) (x & ~0x1F0000)
typedef struct
{
bool do_inc_pc;
bool exiting_error;
} op_return_t;
#define DEFINE_OP(name) \
op_return_t op_##name(raw_instruction_t* ri, \
pstate_t* state)
static const op_return_t _OP_RETV_NORMAL = { .do_inc_pc = true, .exiting_error = false };
static const op_return_t _OP_RETV_EXITING_ERROR = { .do_inc_pc = true, .exiting_error = true };
static const op_return_t _OP_RETV_NO_INC_PC = { .do_inc_pc = false, .exiting_error = false };
#define OP_RETURN_NORMAL return _OP_RETV_NORMAL;
#define OP_RETURN_NO_INC_PC return _OP_RETV_NO_INC_PC;
#define OP_RETURN_EXITING_ERROR return _OP_RETV_EXITING_ERROR;
typedef op_return_t (*op)(raw_instruction_t*, pstate_t*);
DEFINE_OP(nop);
DEFINE_OP(call);
DEFINE_OP(ret);
DEFINE_OP(jmp);
static const op misc_ops[] =
{
op_nop,
op_call,
op_ret,
op_jmp,
op_jb,
};
static const size_t NUM_MISC_OPCODES = sizeof(misc_ops) / sizeof(misc_ops[0]);
DEFINE_OP(add);
DEFINE_OP(sub);
DEFINE_OP(mul);
DEFINE_OP(divide);
DEFINE_OP(modulus);
DEFINE_OP(shl);
DEFINE_OP(shr);
DEFINE_OP(ahr);
DEFINE_OP(ror);
DEFINE_OP(band);
DEFINE_OP(bor);
DEFINE_OP(bxor);
DEFINE_OP(bnot);
DEFINE_OP(xchg);
DEFINE_OP(fp_add);
DEFINE_OP(fp_sub);
DEFINE_OP(fp_mul);
DEFINE_OP(fp_div);
DEFINE_OP(fp_mod);
static const op reg_ops[] =
{
op_add,
op_sub,
op_mul,
op_divide,
op_modulus,
op_shl,
op_shr,
op_ahr, // Arithmetic sHift Right
op_ror,
op_band,
op_bor,
op_bxor,
op_bnot,
op_xchg,
op_fp_add,
op_fp_sub,
op_fp_mul,
op_fp_div,
op_fp_mod,
};
static const size_t NUM_REG_OPCODES = sizeof(reg_ops) / sizeof(reg_ops[0]);
DEFINE_OP(ldr);
DEFINE_OP(lds);
DEFINE_OP(ldb);
DEFINE_OP(ldi);
DEFINE_OP(str);
DEFINE_OP(sts);
DEFINE_OP(stb);
DEFINE_OP(ldh);
DEFINE_OP(sti);
DEFINE_OP(stj);
DEFINE_OP(push);
DEFINE_OP(pushi); // push immediate
DEFINE_OP(pop);
DEFINE_OP(sth);
DEFINE_OP(stk);
static const op ls_ops[] =
{
op_ldr,
op_lds,
op_ldb,
op_ldi,
op_str,
op_sts,
op_stb,
op_ldh,
op_sti,
op_stj,
op_push,
op_pushi,
op_pop,
op_sth, // store high 11 bits of immediate at address with base of pc
op_stk, // store high 11 bits of immediate at address with base of sp
// 1 more
};
static const size_t NUM_LS_OPCODES = sizeof(ls_ops) / sizeof(ls_ops[0]);
#endif // _CAR_INCLUDE_DEFS_H