210 lines
4.3 KiB
C
210 lines
4.3 KiB
C
|
|
#ifndef _CAR_INCLUDE_DEFS_H
|
||
|
|
#define _CAR_INCLUDE_DEFS_H
|
||
|
|
|
||
|
|
#include <stdint.h>
|
||
|
|
#include <stddef.h>
|
||
|
|
#include <stdbool.h>
|
||
|
|
|
||
|
|
#include <stdlib.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);
|
||
|
|
|
||
|
|
#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 };
|
||
|
|
|
||
|
|
#define OP_RETURN_NORMAL return _OP_RETV_NORMAL;
|
||
|
|
#define OP_RETURN_EXITING_ERROR return _OP_RETV_EXITING_ERROR;
|
||
|
|
|
||
|
|
typedef op_return_t (*op)(raw_instruction_t*, pstate_t*);
|
||
|
|
|
||
|
|
static DEFINE_OP(nop)
|
||
|
|
{
|
||
|
|
OP_RETURN_NORMAL
|
||
|
|
}
|
||
|
|
|
||
|
|
static const op misc_ops[] =
|
||
|
|
{
|
||
|
|
op_nop,
|
||
|
|
};
|
||
|
|
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);
|
||
|
|
|
||
|
|
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,
|
||
|
|
};
|
||
|
|
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);
|
||
|
|
|
||
|
|
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,
|
||
|
|
};
|
||
|
|
static const size_t NUM_LS_OPCODES = sizeof(ls_ops) / sizeof(ls_ops[0]);
|
||
|
|
|
||
|
|
#endif // _CAR_INCLUDE_DEFS_H
|