commit 1028ca734042f5ee64de2698c1e649a3fde08969 Author: David Goeke Date: Thu Jul 16 13:46:13 2026 -0500 Initial release of CAR diff --git a/helper.py b/helper.py new file mode 100644 index 0000000..3bf271c --- /dev/null +++ b/helper.py @@ -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!") diff --git a/helpers.c b/helpers.c new file mode 100644 index 0000000..1160a2d --- /dev/null +++ b/helpers.c @@ -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 + +#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; +} diff --git a/include/defs.h b/include/defs.h new file mode 100644 index 0000000..3b7d8ea --- /dev/null +++ b/include/defs.h @@ -0,0 +1,209 @@ +#ifndef _CAR_INCLUDE_DEFS_H +#define _CAR_INCLUDE_DEFS_H + +#include +#include +#include + +#include + +//#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 diff --git a/instruction_format.txt b/instruction_format.txt new file mode 100644 index 0000000..57ee893 --- /dev/null +++ b/instruction_format.txt @@ -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 diff --git a/load_store.c b/load_store.c new file mode 100644 index 0000000..b0376bf --- /dev/null +++ b/load_store.c @@ -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 +#include +#include + +#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 +} diff --git a/main.c b/main.c new file mode 100644 index 0000000..41ed2fd --- /dev/null +++ b/main.c @@ -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 +#include + +#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; +} diff --git a/operations.c b/operations.c new file mode 100644 index 0000000..4a3308e --- /dev/null +++ b/operations.c @@ -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 +} diff --git a/processor.c b/processor.c new file mode 100644 index 0000000..600285c --- /dev/null +++ b/processor.c @@ -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 +#include +#include +#include + +#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; +} diff --git a/program.bin b/program.bin new file mode 100644 index 0000000..73d3bcd Binary files /dev/null and b/program.bin differ diff --git a/program.txt b/program.txt new file mode 100644 index 0000000..2daf05c --- /dev/null +++ b/program.txt @@ -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 diff --git a/run b/run new file mode 100755 index 0000000..d6bb6ad --- /dev/null +++ b/run @@ -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