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
|
||||
30
README.md
30
README.md
@ -1,22 +1,19 @@
|
||||
#Cool ARM Ripoff
|
||||
# Cool ARM Ripoff
|
||||
|
||||
*A simple (and ridiculous) virtual machine/CPU made for no real reason/purpose.*
|
||||
|
||||
***Written in C, made by David Goeke.***
|
||||
|
||||
|
||||
###Current features:
|
||||
### Current features:
|
||||
- few to none.
|
||||
- 32 general purpose registers
|
||||
- 32-bit addresses
|
||||
|
||||
###Needed features:
|
||||
- push/pop
|
||||
- call/ret
|
||||
- jmp/conditional jmps
|
||||
- store high 11 bits of an immediate in memory
|
||||
### Needed features:
|
||||
- conditional jmps
|
||||
|
||||
###instuctions (arithmetic):
|
||||
### Instuctions (arithmetic):
|
||||
- add
|
||||
- sub (subtract)
|
||||
- mul (multiply)
|
||||
@ -31,8 +28,13 @@
|
||||
- xor (logical XOR)
|
||||
- not (logical NOT/invertion)
|
||||
- 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)
|
||||
- lds (load register with value from memory, using the stack pointer as the base)
|
||||
- ldb (load register with value from memory, using a specified register as the base)
|
||||
@ -43,6 +45,14 @@
|
||||
- ldh (load high 11 bits of register with immediate)
|
||||
- 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)
|
||||
- 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)
|
||||
- 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.
|
||||
* Unauthorized (re)distribution is prohibited.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdio.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)
|
||||
{
|
||||
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 <stdbool.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
//#define _DEBUG
|
||||
|
||||
@ -27,6 +28,22 @@ 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)
|
||||
@ -116,21 +133,31 @@ typedef struct
|
||||
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_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*);
|
||||
|
||||
static DEFINE_OP(nop)
|
||||
{
|
||||
OP_RETURN_NORMAL
|
||||
}
|
||||
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]);
|
||||
|
||||
@ -152,6 +179,12 @@ 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,
|
||||
@ -171,6 +204,12 @@ static const op reg_ops[] =
|
||||
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]);
|
||||
|
||||
@ -188,6 +227,13 @@ 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,
|
||||
@ -203,6 +249,15 @@ static const op ls_ops[] =
|
||||
|
||||
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]);
|
||||
|
||||
|
||||
55
load_store.c
55
load_store.c
@ -160,3 +160,58 @@ DEFINE_OP(stj)
|
||||
|
||||
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"
|
||||
|
||||
|
||||
|
||||
|
||||
DEFINE_OP(add)
|
||||
{
|
||||
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.
|
||||
# Unauthorized (re)distribution is prohibited.
|
||||
|
||||
FILES="processor.c load_store.c operations.c helpers.c main.c"
|
||||
CFLAGS="" #"-g -O0 -fsanitize=address"
|
||||
FILES="processor.c fpu.c misc.c load_store.c operations.c helpers.c main.c"
|
||||
CFLAGS="-O2 -Wall" #"-g -O0 -fsanitize=address"
|
||||
TARGET="vm"
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user