CAR: added stack operations, call, ret, jmp and some other random stuff
This commit is contained in:
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
*.o
|
||||||
|
|
||||||
|
*.helper
|
||||||
|
|
||||||
|
!.gitignore
|
||||||
20
README.md
20
README.md
@ -11,12 +11,9 @@
|
|||||||
- 32-bit addresses
|
- 32-bit addresses
|
||||||
|
|
||||||
### Needed features:
|
### Needed features:
|
||||||
- push/pop
|
- conditional jmps
|
||||||
- call/ret
|
|
||||||
- jmp/conditional jmps
|
|
||||||
- store high 11 bits of an immediate in memory
|
|
||||||
|
|
||||||
###instuctions (arithmetic):
|
### Instuctions (arithmetic):
|
||||||
- add
|
- add
|
||||||
- sub (subtract)
|
- sub (subtract)
|
||||||
- mul (multiply)
|
- mul (multiply)
|
||||||
@ -31,6 +28,11 @@
|
|||||||
- xor (logical XOR)
|
- xor (logical XOR)
|
||||||
- not (logical NOT/invertion)
|
- not (logical NOT/invertion)
|
||||||
- xchg (exchange registers)
|
- xchg (exchange registers)
|
||||||
|
- fp_add (add floating point values in registers)
|
||||||
|
- fp_sub (subtract floating point values in registers)
|
||||||
|
- fp_mul (multiply floating point values in registers)
|
||||||
|
- fp_div (divide floating point values in registers)
|
||||||
|
- fp_mod (modulus (division remainder) floating point values in registers)
|
||||||
|
|
||||||
### Insutrctions (load/store):
|
### Insutrctions (load/store):
|
||||||
- ldr (load register with value from memory, using the program counter as the base)
|
- ldr (load register with value from memory, using the program counter as the base)
|
||||||
@ -43,6 +45,14 @@
|
|||||||
- ldh (load high 11 bits of register with immediate)
|
- ldh (load high 11 bits of register with immediate)
|
||||||
- sti (store a 21-bit immediate at memory, using the program counter as the base)
|
- sti (store a 21-bit immediate at memory, using the program counter as the base)
|
||||||
- stj (store a 21-bit immediate at memory, using the stack pointer as the base)
|
- stj (store a 21-bit immediate at memory, using the stack pointer as the base)
|
||||||
|
- push (push register onto stack)
|
||||||
|
- pushi (push 21-bit immediate onto stack)
|
||||||
|
- pop (pop value from stack into register)
|
||||||
|
- sth (stroe high 11 bits of register to memory, using pc as the base)
|
||||||
|
- stk (stroe high 11 bits of register to memory, using sp as the base)
|
||||||
|
|
||||||
### Instructions (misc):
|
### Instructions (misc):
|
||||||
- nop (do nothing)
|
- nop (do nothing)
|
||||||
|
- call (call subroutine/function)
|
||||||
|
- ret (return from subroutine/function)
|
||||||
|
- jmp (jump to memory address)
|
||||||
|
|||||||
88
fpu.c
Normal file
88
fpu.c
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Source file for floating point operations.
|
||||||
|
*
|
||||||
|
* CAR (Cool ARM Ripoff) copyright (c) 2026 David J Goeke. All rights reserved.
|
||||||
|
* Unauthorized (re)distribution is prohibited.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// This is mostly just wrappers around the hardware/system FPU.
|
||||||
|
// We don't do any calculations ourselves.
|
||||||
|
|
||||||
|
#include "include/defs.h"
|
||||||
|
|
||||||
|
DEFINE_OP(fp_add)
|
||||||
|
{
|
||||||
|
register_instruction_t i = convert_raw2register(ri);
|
||||||
|
|
||||||
|
uint8_t dest = i.dest;
|
||||||
|
uint8_t src1 = i.src1;
|
||||||
|
uint8_t src2 = i.src2;
|
||||||
|
|
||||||
|
state->gprs[dest] = (uint32_t) ((float) state->gprs[src1] + (float) state->gprs[src2]);
|
||||||
|
|
||||||
|
OP_RETURN_NORMAL
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_OP(fp_sub)
|
||||||
|
{
|
||||||
|
register_instruction_t i = convert_raw2register(ri);
|
||||||
|
|
||||||
|
uint8_t dest = i.dest;
|
||||||
|
uint8_t src1 = i.src1;
|
||||||
|
uint8_t src2 = i.src2;
|
||||||
|
|
||||||
|
state->gprs[dest] = (uint32_t) ((float) state->gprs[src1] - (float) state->gprs[src2]);
|
||||||
|
|
||||||
|
OP_RETURN_NORMAL
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_OP(fp_mul)
|
||||||
|
{
|
||||||
|
register_instruction_t i = convert_raw2register(ri);
|
||||||
|
|
||||||
|
uint8_t dest = i.dest;
|
||||||
|
uint8_t src1 = i.src1;
|
||||||
|
uint8_t src2 = i.src2;
|
||||||
|
|
||||||
|
state->gprs[dest] = (uint32_t) ((float) state->gprs[src1] * (float) state->gprs[src2]);
|
||||||
|
|
||||||
|
OP_RETURN_NORMAL
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_OP(fp_div)
|
||||||
|
{
|
||||||
|
register_instruction_t i = convert_raw2register(ri);
|
||||||
|
|
||||||
|
uint8_t dest = i.dest;
|
||||||
|
uint32_t src1 = state->gprs[i.src1];
|
||||||
|
uint32_t src2 = state->gprs[i.src2];
|
||||||
|
|
||||||
|
if (src1 != 0 && src2 != 0)
|
||||||
|
{
|
||||||
|
state->gprs[dest] = (uint32_t) ((float) src1 / (float) src2);
|
||||||
|
OP_RETURN_NORMAL
|
||||||
|
}
|
||||||
|
|
||||||
|
state->gprs[dest] = 0xffffffff;
|
||||||
|
|
||||||
|
OP_RETURN_NORMAL
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_OP(fp_mod)
|
||||||
|
{
|
||||||
|
register_instruction_t i = convert_raw2register(ri);
|
||||||
|
|
||||||
|
uint8_t dest = i.dest;
|
||||||
|
uint32_t src1 = state->gprs[i.src1];
|
||||||
|
uint32_t src2 = state->gprs[i.src2];
|
||||||
|
|
||||||
|
if (src1 != 0 && src2 != 0)
|
||||||
|
{
|
||||||
|
state->gprs[dest] = (uint32_t) ((float) src1 / (float) src2);
|
||||||
|
OP_RETURN_NORMAL
|
||||||
|
}
|
||||||
|
|
||||||
|
state->gprs[dest] = 0xffffffff;
|
||||||
|
|
||||||
|
OP_RETURN_NORMAL
|
||||||
|
}
|
||||||
13
helpers.c
13
helpers.c
@ -4,10 +4,23 @@
|
|||||||
* CAR (Cool ARM Ripoff) copyright (c) 2026 David J Goeke. All rights reserved.
|
* CAR (Cool ARM Ripoff) copyright (c) 2026 David J Goeke. All rights reserved.
|
||||||
* Unauthorized (re)distribution is prohibited.
|
* Unauthorized (re)distribution is prohibited.
|
||||||
*/
|
*/
|
||||||
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "include/defs.h"
|
#include "include/defs.h"
|
||||||
|
|
||||||
|
void _push(uint32_t v, pstate_t* state)
|
||||||
|
{
|
||||||
|
state->sp--;
|
||||||
|
memcpy(state->memory + state->sp, &v, sizeof(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
void _pop(uint32_t* a, pstate_t* state)
|
||||||
|
{
|
||||||
|
memcpy(a, state->memory + state->sp, sizeof(*a));
|
||||||
|
state->sp++;
|
||||||
|
}
|
||||||
|
|
||||||
void dump_regs(pstate_t* s)
|
void dump_regs(pstate_t* s)
|
||||||
{
|
{
|
||||||
printf("r0: 0x%08x r1: 0x%08x r2: 0x%08x, r3: 0x%08x\n", s->gprs[0], s->gprs[1], s->gprs[2], s->gprs[3]);
|
printf("r0: 0x%08x r1: 0x%08x r2: 0x%08x, r3: 0x%08x\n", s->gprs[0], s->gprs[1], s->gprs[2], s->gprs[3]);
|
||||||
|
|||||||
@ -5,7 +5,8 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
//#define _DEBUG
|
//#define _DEBUG
|
||||||
|
|
||||||
@ -27,6 +28,22 @@ int processor_start(pstate_t* state);
|
|||||||
|
|
||||||
void dump_regs(pstate_t* s);
|
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_CARRY (1 << 0)
|
||||||
#define FLAG_SIGN (1 << 1)
|
#define FLAG_SIGN (1 << 1)
|
||||||
#define FLAG_OVERFLOW (1 << 2)
|
#define FLAG_OVERFLOW (1 << 2)
|
||||||
@ -117,20 +134,30 @@ typedef struct
|
|||||||
|
|
||||||
static const op_return_t _OP_RETV_NORMAL = { .do_inc_pc = true, .exiting_error = false };
|
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_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_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;
|
#define OP_RETURN_EXITING_ERROR return _OP_RETV_EXITING_ERROR;
|
||||||
|
|
||||||
typedef op_return_t (*op)(raw_instruction_t*, pstate_t*);
|
typedef op_return_t (*op)(raw_instruction_t*, pstate_t*);
|
||||||
|
|
||||||
static DEFINE_OP(nop)
|
DEFINE_OP(nop);
|
||||||
{
|
|
||||||
OP_RETURN_NORMAL
|
DEFINE_OP(call);
|
||||||
}
|
DEFINE_OP(ret);
|
||||||
|
|
||||||
|
DEFINE_OP(jmp);
|
||||||
|
|
||||||
static const op misc_ops[] =
|
static const op misc_ops[] =
|
||||||
{
|
{
|
||||||
op_nop,
|
op_nop,
|
||||||
|
|
||||||
|
op_call,
|
||||||
|
op_ret,
|
||||||
|
|
||||||
|
op_jmp,
|
||||||
|
op_jb,
|
||||||
};
|
};
|
||||||
static const size_t NUM_MISC_OPCODES = sizeof(misc_ops) / sizeof(misc_ops[0]);
|
static const size_t NUM_MISC_OPCODES = sizeof(misc_ops) / sizeof(misc_ops[0]);
|
||||||
|
|
||||||
@ -152,6 +179,12 @@ DEFINE_OP(bnot);
|
|||||||
|
|
||||||
DEFINE_OP(xchg);
|
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[] =
|
static const op reg_ops[] =
|
||||||
{
|
{
|
||||||
op_add,
|
op_add,
|
||||||
@ -171,6 +204,12 @@ static const op reg_ops[] =
|
|||||||
op_bnot,
|
op_bnot,
|
||||||
|
|
||||||
op_xchg,
|
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]);
|
static const size_t NUM_REG_OPCODES = sizeof(reg_ops) / sizeof(reg_ops[0]);
|
||||||
|
|
||||||
@ -188,6 +227,13 @@ DEFINE_OP(ldh);
|
|||||||
DEFINE_OP(sti);
|
DEFINE_OP(sti);
|
||||||
DEFINE_OP(stj);
|
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[] =
|
static const op ls_ops[] =
|
||||||
{
|
{
|
||||||
op_ldr,
|
op_ldr,
|
||||||
@ -203,6 +249,15 @@ static const op ls_ops[] =
|
|||||||
|
|
||||||
op_sti,
|
op_sti,
|
||||||
op_stj,
|
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]);
|
static const size_t NUM_LS_OPCODES = sizeof(ls_ops) / sizeof(ls_ops[0]);
|
||||||
|
|
||||||
|
|||||||
55
load_store.c
55
load_store.c
@ -160,3 +160,58 @@ DEFINE_OP(stj)
|
|||||||
|
|
||||||
OP_RETURN_NORMAL
|
OP_RETURN_NORMAL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_OP(push)
|
||||||
|
{
|
||||||
|
ls_instruction_t i = convert_raw2ls(ri);
|
||||||
|
|
||||||
|
_push(state->gprs[i.reg], state);
|
||||||
|
|
||||||
|
OP_RETURN_NORMAL
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_OP(pushi)
|
||||||
|
{
|
||||||
|
ls_instruction_t i = convert_raw2ls(ri);
|
||||||
|
|
||||||
|
_push(i.imm, state);
|
||||||
|
|
||||||
|
OP_RETURN_NORMAL
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_OP(pop)
|
||||||
|
{
|
||||||
|
ls_instruction_t i = convert_raw2ls(ri);
|
||||||
|
|
||||||
|
uint32_t v;
|
||||||
|
|
||||||
|
_pop(&v, state);
|
||||||
|
|
||||||
|
state->gprs[i.reg] = v;
|
||||||
|
|
||||||
|
OP_RETURN_NORMAL
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_OP(sth)
|
||||||
|
{
|
||||||
|
ls_instruction_t i = convert_raw2ls(ri);
|
||||||
|
|
||||||
|
uint32_t addr = state->pc + state->gprs[i.reg];
|
||||||
|
uint32_t v = (i.imm >> 21) & 0x7ff;
|
||||||
|
|
||||||
|
memcpy(state->memory + addr, &v, sizeof(v));
|
||||||
|
|
||||||
|
OP_RETURN_NORMAL
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_OP(stk)
|
||||||
|
{
|
||||||
|
ls_instruction_t i = convert_raw2ls(ri);
|
||||||
|
|
||||||
|
uint32_t addr = state->sp + state->gprs[i.reg];
|
||||||
|
uint32_t v = (i.imm >> 21) & 0x7ff;
|
||||||
|
|
||||||
|
memcpy(state->memory + addr, &v, sizeof(v));
|
||||||
|
|
||||||
|
OP_RETURN_NORMAL
|
||||||
|
}
|
||||||
|
|||||||
49
misc.c
Normal file
49
misc.c
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Source file for miscellaneous operations.
|
||||||
|
*
|
||||||
|
* CAR (Cool ARM Ripoff) copyright (c) 2026 David J Goeke. All rights reserved.
|
||||||
|
* Unauthorized (re)distribution is prohibited.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "include/defs.h"
|
||||||
|
|
||||||
|
|
||||||
|
DEFINE_OP(nop)
|
||||||
|
{
|
||||||
|
OP_RETURN_NORMAL
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_OP(call)
|
||||||
|
{
|
||||||
|
misc_instruction_t i = convert_raw2misc(ri);
|
||||||
|
|
||||||
|
_push(state->pc + 1, state);
|
||||||
|
|
||||||
|
uint32_t addr = (uint32_t) (state->pc + (int32_t) i.imm);
|
||||||
|
|
||||||
|
state->pc = addr;
|
||||||
|
|
||||||
|
OP_RETURN_NO_INC_PC
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_OP(ret)
|
||||||
|
{
|
||||||
|
uint32_t r_addr;
|
||||||
|
|
||||||
|
_pop(&r_addr, state);
|
||||||
|
|
||||||
|
state->pc = r_addr;
|
||||||
|
|
||||||
|
OP_RETURN_NO_INC_PC
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_OP(jmp)
|
||||||
|
{
|
||||||
|
misc_instruction_t i = convert_raw2misc(ri);
|
||||||
|
|
||||||
|
uint32_t addr = (uint32_t) (state->pc + (int32_t) i.imm);
|
||||||
|
|
||||||
|
state->pc = addr;
|
||||||
|
|
||||||
|
OP_RETURN_NO_INC_PC
|
||||||
|
}
|
||||||
@ -9,8 +9,6 @@
|
|||||||
#include "include/defs.h"
|
#include "include/defs.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
DEFINE_OP(add)
|
DEFINE_OP(add)
|
||||||
{
|
{
|
||||||
register_instruction_t i = convert_raw2register(ri);
|
register_instruction_t i = convert_raw2register(ri);
|
||||||
|
|||||||
4
run
4
run
@ -4,8 +4,8 @@
|
|||||||
# CAR (Cool ARM Ripoff) copyright (c) 2026 David J Goeke. All rights reserved.
|
# CAR (Cool ARM Ripoff) copyright (c) 2026 David J Goeke. All rights reserved.
|
||||||
# Unauthorized (re)distribution is prohibited.
|
# Unauthorized (re)distribution is prohibited.
|
||||||
|
|
||||||
FILES="processor.c load_store.c operations.c helpers.c main.c"
|
FILES="processor.c fpu.c misc.c load_store.c operations.c helpers.c main.c"
|
||||||
CFLAGS="" #"-g -O0 -fsanitize=address"
|
CFLAGS="-O2 -Wall" #"-g -O0 -fsanitize=address"
|
||||||
TARGET="vm"
|
TARGET="vm"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user