Initial release of CAR

This commit is contained in:
2026-07-16 13:46:13 -05:00
commit 89fa043caa
11 changed files with 942 additions and 0 deletions

33
helper.py Normal file
View File

@ -0,0 +1,33 @@
try:
from colorama import Fore, Style
HAS_COLORAMA = True
except ImportError:
HAS_COLORAMA = False
if not HAS_COLORAMA:
print("Warning: colorama is not installed.")
print("Install it with: pip install colorama or sudo apt install python3-colorama or sudo pacman -S python-colorama")
exit(-1);
def is_number(s):
try:
if s.lower().startswith(("0x", "0b", "0o")):
int(s, 0)
else:
int(s)
return True
except ValueError:
return False
REG_OPCODE_MASK = 0x3f800000
REG_DEST_MASK = 0x001f0000
REG_SRC2_MASK = 0x0000f800
REG_SRC1_MASK = 0x000007f0
LS_OPCODE_MASK = 0x3c000000
LS_IMM_MASK = 0x03ffffff
print("this helper function is not ready yet!")

58
helpers.c Normal file
View File

@ -0,0 +1,58 @@
/*
* Source file for helper functions.
*
* CAR (Cool ARM Ripoff) copyright (c) 2026 David J Goeke. All rights reserved.
* Unauthorized (re)distribution is prohibited.
*/
#include <stdio.h>
#include "include/defs.h"
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("r4: 0x%08x r5: 0x%08x r6: 0x%08x, r7: 0x%08x\n", s->gprs[4], s->gprs[5], s->gprs[6], s->gprs[7]);
printf("r8: 0x%08x r9: 0x%08x r10: 0x%08x, r11: 0x%08x\n", s->gprs[8], s->gprs[9], s->gprs[10], s->gprs[11]);
printf("r12: 0x%08x r13: 0x%08x r14: 0x%08x, r15: 0x%08x\n", s->gprs[12], s->gprs[13], s->gprs[14], s->gprs[15]);
printf("sp: 0x%04x pc: 0x%04x\n", s->sp, s->pc);
printf("\n");
}
misc_instruction_t convert_raw2misc(raw_instruction_t* r)
{
misc_instruction_t i;
uint32_t inst = (uint32_t) *r;
inst = __builtin_bswap32(inst);
i.opcode = (inst >> 23) & 0x3f;
i.imm = 0xffffff;
return i;
}
register_instruction_t convert_raw2register(raw_instruction_t* r)
{
register_instruction_t i;
uint32_t inst = (uint32_t) *r;
i.opcode = (inst >> 23) & 0x7f;
i.dest = (inst >> 18) & 0x1f;
i.src1 = (inst >> 13) & 0x1f;
i.src2 = (inst >> 8) & 0x1f;
#ifdef _DEBUG
printf("convert_raw2register: opcode: 0b%04b, dest: 0b%05b, src1: 0b%021b, src2: 0b%021b\n", i.opcode, i.dest, i.src1, i.src2);
#endif
return i;
}
ls_instruction_t convert_raw2ls(raw_instruction_t* r)
{
ls_instruction_t i;
uint32_t inst = (uint32_t) *r;
i.opcode = (inst >> 26) & 0xf;
i.reg = (inst >> 21) & 0x1f;
i.imm = inst & 0x1FFFFF;
#ifdef _DEBUG
printf("convert_raw2ls: opcode: 0b%04b, reg: 0b%05b, imm: 0b%021b\n", i.opcode, i.reg, i.imm);
#endif
return i;
}

209
include/defs.h Normal file
View File

@ -0,0 +1,209 @@
#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

69
instruction_format.txt Normal file
View File

@ -0,0 +1,69 @@
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 13 (5 bits)
src1 bits 14 to 18 (5 bits)
src2 bits 19 to 23 (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
The difference between 'arithmetic' and 'logical' shifts/rotates is that in arithmetic shifts/rotates
the sign bit is untouched, while logical shifts/rotates don't care about the sign bit.
Also, we only need arithmetic shift right because arithmetic shift left is typically the same as a logical shift left.
Another instruction we really don't 'need' is a rotate left instrction, because you can do the same thing with a rotate right
instruction, and rotate right instructions are more common than rotate left instructions.
opcodes for register operations (in order of opcode numbers):
add; add src1 and src2 and store the result in dest.
sub; subtract src1 and src2 and store the result in dest.
mul; multiply src1 and src2 and store the result in dest.
div; divide src1 and src2 and store the result in dest. If src1 or src2 is zero, dest is untouched and a exception is raised.
mod; divide src1 and src2 and store the remainder in dest. If src1 or src2 is zero, dest is untouched and a exception is raised.
shl; logically shift src1 left by src2 and store the result in dest.
shr; logically shift src1 right by src2 and store the result in dest.
ahr; arithmetic shift src1 right by src2 and store the result in dest.
ror; logically rotate src1 right by src2 and store the result in dest.
and; AND src1 by src2 and store the result in dest.
or; OR src1 by src2 and store the result in dest.
xor; XOR src1 by src2 and store the result in dest.
not; NOT src1 and store the result in dest, ignore src2.
xchg; exchange src1 and src2, ingore dest.
opcodes for load/store operations: (in order of opcode numbers)
ldr; load register from value at PC + imm
lds; load register from value at SP + imm
ldb; load register from value base_reg + imm
ldi; load low 21 bits of register with value imm
str; store register at address PC + imm
sts; store register at address SP + imm
stb; store register at address base_reg + imm
ldh; load high 11 bits of register with value imm
sti; store immediate at address PC + register
stj; store immediate at address SP + register

162
load_store.c Normal file
View File

@ -0,0 +1,162 @@
/*
* Source file for load/store operations.
*
* CAR (Cool ARM Ripoff) copyright (c) 2026 David J Goeke. All rights reserved.
* Unauthorized (re)distribution is prohibited.
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "include/defs.h"
DEFINE_OP(ldr)
{
ls_instruction_t i = convert_raw2ls(ri);
uint8_t reg = i.reg;
uint32_t dest;
uint32_t addr = state->pc + i.imm;
//assert(addr < state->memory_size);
if (addr >= state->memory_size)
{
printf("addr >= state->memory_size!\n");
//OP_RETURN_EXITING_ERROR
}
printf("loading register %i with value from address 0x%04x, imm: 0x%04x\n", reg, addr, i.imm);
memcpy(&dest, state->memory + addr, sizeof(dest));
state->gprs[reg] = dest;
OP_RETURN_NORMAL
}
DEFINE_OP(lds)
{
ls_instruction_t i = convert_raw2ls(ri);
uint8_t reg = i.reg;
uint32_t dest;
uint32_t addr = state->sp + i.imm;
memcpy(&dest, state->memory + addr, sizeof(dest));
state->gprs[reg] = dest;
OP_RETURN_NORMAL
}
DEFINE_OP(ldb)
{
ls_instruction_t i = convert_raw2ls(ri);
uint8_t reg = i.reg;
uint32_t dest;
uint32_t base_value = state->gprs[get_reg_from_imm(i.imm)];
uint32_t addr = base_value + (uint32_t) get_imm_from_imm(i.imm);
memcpy(&dest, state->memory + addr, sizeof(dest));
state->gprs[reg] = dest;
OP_RETURN_NORMAL
}
DEFINE_OP(ldi)
{
ls_instruction_t i = convert_raw2ls(ri);
uint8_t reg = i.reg;
//uint32_t value = (i.imm) & 0b111111111111111111111; // should convert this to hex
uint32_t value = i.imm;
#ifdef _DEBUG
printf("In ldi, reg: 0b%05b, imm: 0x%x\n", reg, value);
#endif
state->gprs[reg] |= value;
OP_RETURN_NORMAL
}
DEFINE_OP(str)
{
ls_instruction_t i = convert_raw2ls(ri);
uint32_t value = state->gprs[i.reg];
uint32_t addr = state->pc + i.imm;
memcpy(state->memory + addr, &value, sizeof(value));
OP_RETURN_NORMAL
}
DEFINE_OP(sts)
{
ls_instruction_t i = convert_raw2ls(ri);
uint32_t value = state->gprs[i.reg];
uint32_t addr = state->sp + i.imm;
memcpy(state->memory + addr, &value, sizeof(value));
OP_RETURN_NORMAL
}
DEFINE_OP(stb)
{
ls_instruction_t i = convert_raw2ls(ri);
uint32_t value = state->gprs[i.reg];
uint32_t base_value = state->gprs[get_reg_from_imm(i.imm)];
uint32_t addr = base_value + (uint32_t) get_imm_from_imm(i.imm);
memcpy(state->memory + addr, &value, sizeof(value));
OP_RETURN_NORMAL
}
DEFINE_OP(ldh)
{
ls_instruction_t i = convert_raw2ls(ri);
uint8_t reg = i.reg;
uint32_t value = (i.imm) & 0b11111111111; // should convert this to hex
state->gprs[reg] = (state->gprs[reg] & 0x001FFFFF) | ((value & 0x7FF) << 21);
OP_RETURN_NORMAL
}
DEFINE_OP(sti)
{
ls_instruction_t i = convert_raw2ls(ri);
uint32_t addr = state->pc + state->gprs[i.reg];
uint32_t value = i.imm;
memcpy(state->memory + addr, &value, sizeof(value));
OP_RETURN_NORMAL
}
DEFINE_OP(stj)
{
ls_instruction_t i = convert_raw2ls(ri);
uint32_t addr = state->sp + state->gprs[i.reg];
uint32_t value = i.imm;
memcpy(state->memory + addr, &value, sizeof(value));
OP_RETURN_NORMAL
}

97
main.c Normal file
View File

@ -0,0 +1,97 @@
/*
* Source file for entry point and initialization.
*
* CAR (Cool ARM Ripoff) copyright (c) 2026 David J Goeke. All rights reserved.
* Unauthorized (re)distribution is prohibited.
*/
#include <stdio.h>
#include <stdlib.h>
#include "include/defs.h"
static long get_file_size(FILE *fp)
{
long current = ftell(fp);
fseek(fp, 0, SEEK_END);
long size = ftell(fp);
fseek(fp, current, SEEK_SET);
return size;
}
int main(int argc, char** argv)
{
printf("CAR (Cool ARM Ripoff) copyright (c) 2026 David J Goeke. All rights reserved.\n\n");
pstate_t* state = malloc(sizeof(pstate_t));
if (!state)
{
printf("Error: malloc failed.\n");
return -1;
}
if (argc < 1)
{
printf("Error: no input file specified.\n");
return -1;
}
FILE* f = fopen(argv[1], "rb");
if (!f)
{
printf("Error: failed to open file %s.\n", argv[1]);
return -1;
}
uint8_t* data = malloc(get_file_size(f));
if (!data)
{
printf("Error: malloc failed.\n");
free(state);
return -1;
}
size_t read = fread(data, 1, get_file_size(f), f);
size_t words = read / sizeof(uint32_t);
if (read % sizeof(uint32_t) != 0)
{
fprintf(stderr, "Error: file size (%zu bytes) is not a multiple of 4.\n", read);
free(data);
free(state);
fclose(f);
return -1;
}
state->memory_size = words; // Just to be safe, use the number of bytes read instead of what get_file_size told us
state->memory = (uint32_t*) data;
state->flags = 0;
state->pc = 0; // TODO: we should load ELF files or some other format so we can start somewhere other than address 0 (and so we can have bss)
// We could set sp, but let's let software do that
for (int k = 0; k < words; k++)
{
state->memory[k] = __builtin_bswap32(state->memory[k]);
}
int j = processor_start(state);
if (j != 0)
{
// An error occured, though a message already has been printed, so for now do nothing.
}
free(data); // or would could do free(state->memory), shouldn't matter
free(state);
return 0;
}

216
operations.c Normal file
View File

@ -0,0 +1,216 @@
/*
* Source file for register 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(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] = state->gprs[src1] + state->gprs[src2];
OP_RETURN_NORMAL
}
DEFINE_OP(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] = state->gprs[src1] - state->gprs[src2];
OP_RETURN_NORMAL
}
DEFINE_OP(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] = state->gprs[src1] * state->gprs[src2];
OP_RETURN_NORMAL
}
DEFINE_OP(divide)
{
register_instruction_t i = convert_raw2register(ri);
uint8_t dest = i.dest;
uint8_t src1 = i.src1;
uint8_t src2 = i.src2;
if (src1 == 0 || src2 == 0)
{
state->flags |= FLAG_DIVISION_ERROR;
OP_RETURN_NORMAL
}
state->gprs[dest] = state->gprs[src1] / state->gprs[src2];
OP_RETURN_NORMAL
}
DEFINE_OP(modulus)
{
register_instruction_t i = convert_raw2register(ri);
uint8_t dest = i.dest;
uint8_t src1 = i.src1;
uint8_t src2 = i.src2;
if (src1 == 0 || src2 == 0)
{
state->flags |= FLAG_DIVISION_ERROR;
OP_RETURN_NORMAL
}
state->gprs[dest] = state->gprs[src1] % state->gprs[src2];
OP_RETURN_NORMAL
}
DEFINE_OP(shl)
{
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] = state->gprs[src1] << state->gprs[src2];
OP_RETURN_NORMAL
}
DEFINE_OP(shr)
{
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] = state->gprs[src1] >> state->gprs[src2];
OP_RETURN_NORMAL
}
DEFINE_OP(ahr)
{
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) ((int32_t) state->gprs[src1]) >> state->gprs[src2];
OP_RETURN_NORMAL
}
static uint32_t rotr32(uint32_t x, uint32_t n)
{
n &= 31; // Ensure 0 <= n < 32
return (x >> n) | (x << ((32 - n) & 31));
}
DEFINE_OP(ror)
{
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] = rotr32(state->gprs[src1], state->gprs[src2]);
OP_RETURN_NORMAL
}
DEFINE_OP(band)
{
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] = state->gprs[src1] & state->gprs[src2];
OP_RETURN_NORMAL
}
DEFINE_OP(bor)
{
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] = state->gprs[src1] | state->gprs[src2];
OP_RETURN_NORMAL
}
DEFINE_OP(bxor)
{
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] = state->gprs[src1] ^ state->gprs[src2];
OP_RETURN_NORMAL
}
DEFINE_OP(bnot)
{
register_instruction_t i = convert_raw2register(ri);
uint8_t dest = i.dest;
uint8_t src1 = i.src1;
state->gprs[dest] = ~(state->gprs[src1]);
OP_RETURN_NORMAL
}
DEFINE_OP(xchg)
{
register_instruction_t i = convert_raw2register(ri);
uint8_t src1 = i.src1;
uint8_t src2 = i.src2;
// Truthfully we could use XORs here, but it's not really faster, so there is no real point,
// along with the fact that if both values are the same the result is zeroed out.
uint8_t temp = src1;
state->gprs[src1] = state->gprs[src2];
state->gprs[src2] = state->gprs[temp];
OP_RETURN_NORMAL
}

67
processor.c Normal file
View File

@ -0,0 +1,67 @@
/*
* Source file for core processor functions.
*
* CAR (Cool ARM Ripoff) copyright (c) 2026 David J Goeke. All rights reserved.
* Unauthorized (re)distribution is prohibited.
*/
#include <time.h>
#include <unistd.h>
#include <stdio.h>
#include <assert.h>
#include "include/defs.h"
op_return_t dispatch(raw_instruction_t* r, pstate_t* state)
{
uint8_t instruction_group = get_instruction_group(r);
uint8_t opcode;
switch (instruction_group)
{
case 0:
opcode = convert_raw2misc(r).opcode;
//assert(opcode < NUM_MISC_OPCODES);
return misc_ops[opcode](r, state);
case 1:
opcode = convert_raw2register(r).opcode;
return reg_ops[opcode](r, state);
case 2:
opcode = convert_raw2ls(r).opcode;
return ls_ops[opcode](r, state);
default:
printf("\n[ERROR] instruction group is invalid\n");
OP_RETURN_EXITING_ERROR
}
OP_RETURN_EXITING_ERROR
}
int processor_start(pstate_t* state)
{
while (state->pc < state->memory_size)
{
#ifdef _DEBUG
printf("state->memory[pc] -> 0x%x, 0b%032b\n", state->memory[state->pc], state->memory[state->pc]);
#endif
op_return_t rv = dispatch((raw_instruction_t*) (state->memory + state->pc), state);
if (rv.do_inc_pc)
{
state->pc++;
}
else if (rv.exiting_error)
{
printf("An error was occured\n");
return -1;
}
dump_regs(state);
usleep(300000);
}
return 0;
}

BIN
program.bin Normal file

Binary file not shown.

12
program.txt Normal file
View File

@ -0,0 +1,12 @@
What program.bin does is this:
; Move the value 8 into r0 and r1
mov r0, #0x8
mov r1, #0x8
; multiply r0 by r1 and store the result in r2
mul r2, r0, r1
; do nothing
nop

19
run Executable file
View File

@ -0,0 +1,19 @@
#!/bin/sh
# Run script.
# 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"
TARGET="vm"
gcc $CFLAGS $FILES -o $TARGET
if [ $? -eq 0 ]; then
echo
./$TARGET $@
else
echo "Error: gcc failed with error code" $?
fi