Created
July 3, 2018 20:38
-
-
Save DCubix/006799b6767bbd04f5657fafa9b194c2 to your computer and use it in GitHub Desktop.
RIP
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "sgm_cpu.h" | |
#include <stdio.h> | |
#include <assert.h> | |
#include <memory.h> | |
#include <math.h> | |
static sgmByte sgm_cpu_next_byte(sgmCPU* cpu) { | |
return cpu->ram[SGM_LOC_PROGRAM + (cpu->pc++)] & 0xFF; | |
} | |
static sgmWord cpu_fetch(sgmCPU* cpu, sgmOperand* out) { | |
bool prevIsOp = ((cpu->ram[cpu->pc-1] & 0b10000000) >> 7) == 0x1; | |
sgmByte b = sgm_cpu_next_byte(cpu); | |
bool isword = ((b & 0b10000000) >> 7) == 0b1; | |
sgmByte r = (b & 0b00011111); | |
sgmByte addr = (b & 0b01100000) >> 5; | |
if (out) { | |
out->isWord = isword; | |
out->addressing = addr; | |
out->reg = r; | |
} | |
sgmWord value = 0; | |
if (isword) { | |
switch (addr) { | |
case 0: | |
case SGM_IMM: | |
assert(!prevIsOp && "Cannot use an IMMEDIATE as DESTINATION."); | |
value = (b << 8 | sgm_cpu_next_byte(cpu)); | |
break; | |
case SGM_REG: | |
value = cpu->wordRegisters[r]; | |
break; | |
case SGM_PTR: | |
value = cpu->ram[cpu->wordRegisters[r]]; | |
break; | |
} | |
} else { | |
switch (addr) { | |
case 0: | |
case SGM_IMM: | |
value = (sgm_cpu_next_byte(cpu) << 8 | b); | |
break; | |
case SGM_REG: | |
value = cpu->byteRegisters[r]; | |
break; | |
case SGM_PTR: | |
value = cpu->ram[cpu->byteRegisters[r]]; | |
break; | |
} | |
} | |
return value; | |
} | |
static void cpu_write(sgmCPU* cpu, sgmOperand dest, sgmWord value) { | |
if (dest.isWord) { | |
switch (dest.addressing) { | |
case SGM_IMM: | |
assert(false && "Cannot use IMMEDIATE here."); | |
break; | |
case SGM_REG: | |
cpu->wordRegisters[dest.reg] = value; | |
break; | |
case SGM_PTR: { | |
sgmWord* dst = (sgmWord*)(&cpu->ram[cpu->wordRegisters[dest.reg]]); | |
*dst = value; | |
} break; | |
} | |
} else { | |
switch (dest.addressing) { | |
case SGM_IMM: | |
assert(false && "Cannot use IMMEDIATE here."); | |
break; | |
case SGM_REG: | |
cpu->byteRegisters[dest.reg] = value & 0xFF; | |
break; | |
case SGM_PTR: | |
cpu->ram[cpu->wordRegisters[dest.reg]] = value; | |
break; | |
} | |
} | |
} | |
SGM_DEF_INSTR(end) { | |
cpu->ram[SGM_LOC_SYSCALL] = SGM_SYSCALL_STOP; | |
} | |
SGM_DEF_INSTR(mov) { // mov dest, src | |
sgmOperand dst; cpu_fetch(cpu, &dst); | |
sgmWord srcVal = cpu_fetch(cpu, NULL); | |
cpu_write(cpu, dst, srcVal); | |
} | |
static const sgmInstruction SGM_INSTRUCTIONS[] = { | |
//// General purpose instructions | |
{ "end", sgm_instr_end }, | |
{ "mov", sgm_instr_mov }, | |
{ "", NULL } | |
}; | |
sgmCPU* sgm_cpu_new() { | |
sgmCPU* cpu = (sgmCPU*) malloc(sizeof(sgmCPU)); | |
memset(cpu->byteRegisters, 0, sizeof(sgmByte) * RCount); | |
memset(cpu->ram, 0, sizeof(sgmByte) * SGM_RAM_SIZE); | |
cpu->pc = cpu->sp = 0; | |
cpu->flag = 0; | |
return cpu; | |
} | |
void sgm_cpu_free(sgmCPU* cpu) { | |
} | |
void sgm_cpu_tick(sgmCPU* cpu) { | |
sgmByte opcode = sgm_cpu_next_byte(cpu) & 0b01111111; | |
// printf("EXEC. INSTR: %s\n", SGM_INSTRUCTIONS[opcode].name); | |
SGM_INSTRUCTIONS[opcode].exec(cpu); | |
} | |
void sgm_cpu_load(sgmCPU* cpu, sgmByte* program, sgmWord n) { | |
memcpy(cpu->ram + SGM_LOC_PROGRAM, program, sizeof(sgmByte) * n); | |
memset(cpu->byteRegisters, 0, sizeof(sgmByte) * RCount); | |
cpu->pc = 0; | |
cpu->sp = 0; | |
cpu->flag = 0; | |
} | |
void sgm_cpu_run(sgmCPU* cpu) { | |
while (cpu->ram[SGM_LOC_SYSCALL] != SGM_SYSCALL_STOP) { | |
cpu->ram[SGM_LOC_SYSCALL] = 0; | |
sgm_cpu_tick(cpu); | |
if (cpu->ram[SGM_LOC_SYSCALL] == SGM_SYSCALL_RESET) { | |
memset(cpu->byteRegisters, 0, sizeof(sgmByte) * RCount); | |
cpu->pc = cpu->sp = 0; | |
cpu->flag = 0; | |
} | |
printf("[ "); | |
for (sgmInt i = 0; i < RCount; i++) { | |
printf("%02xh, ", cpu->byteRegisters[i]); | |
} | |
printf("]\n"); | |
} | |
} | |
sgmByte sgm_get_op(const char* name) { | |
sgmInt isz = sizeof(SGM_INSTRUCTIONS) / sizeof(sgmInstruction); | |
for (sgmInt i = 0; i < isz; i++) { | |
if (strcmp(SGM_INSTRUCTIONS[i].name, name) == 0) | |
return i; | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef SGM_CPU_H | |
#define SGM_CPU_H | |
#include <stdlib.h> | |
#include <stdbool.h> | |
#include <stdint.h> | |
#include "sgm_mem.h" | |
#define SGM_PROGRAM_MAX_SIZE 0xC00 // 3KB | |
#define SGM_GENERAL_PURPOSE_SIZE 0x400 // 1KB | |
#define SGM_VIDEO_SIZE (128 * 96) // 12 KB | |
#define SGM_STACK_SIZE 32 | |
#define SGM_RAM_SIZE (SGM_PROGRAM_MAX_SIZE + SGM_GENERAL_PURPOSE_SIZE + SGM_VIDEO_SIZE + SGM_STACK_SIZE + 2) | |
#define SGM_LOC_PROGRAM 0 | |
#define SGM_LOC_GENERAL_PURPOSE SGM_PROGRAM_MAX_SIZE | |
#define SGM_LOC_VIDEO (SGM_PROGRAM_MAX_SIZE + SGM_GENERAL_PURPOSE_SIZE) | |
#define SGM_LOC_STACK (SGM_LOC_VIDEO + SGM_VIDEO_SIZE) | |
#define SGM_LOC_SYSCALL (SGM_LOC_STACK + SGM_STACK_SIZE) | |
#define SGM_LOC_SYSCALL_PARAM (SGM_LOC_SYSCALL+1) | |
#define SGM_SYSCALL_STOP 0x1 | |
#define SGM_SYSCALL_RESET 0x2 | |
#define SGM_SYSCALL_VIDEO_CLEAR 0x3 | |
#define SGM_SYSCALL_DRAW_SPRITE 0x4 | |
#define SGM_FLAG_EQUAL 0x1 | |
#define SGM_FLAG_GREATER 0x2 | |
#define SGM_FLAG_LESS 0x3 | |
#define SGM_LINE(x) (x * sizeof(sgmInt)) | |
#define SGM_DEF_INSTR(name) static void sgm_instr_##name(sgmCPU* cpu) | |
// INSTRUCTION ENCODING | |
// =========================================== | |
// 1byte 1byte 1byte 2bytes | |
// [ OPCODE ][ OPERAND ][ OPERAND ][ OPTIONAL IMMEDIATE ] | |
// | |
// | |
// OPCODE | |
// =========================================== | |
// [ FLAG ][ CODE ] | |
// 1bit 7bit | |
// | |
// OPERAND | |
// =========================================== | |
// [ WORD ][ ADDR ][ REGISTER ] | |
// 1bit 2bit 5bit | |
// | |
#define SGM_IMM 0b01 | |
#define SGM_REG 0b10 | |
#define SGM_PTR 0b11 | |
sgmByte sgm_get_op(const char* name); | |
#define OC(name) ((0b1 << 7) | (sgm_get_op(name) & 0b111111)) | |
#define OP(w, addr, reg) ((w & 0b1) << 7 | (addr & 0b11) << 5 | (reg & 0b11111)) | |
#define IM(v) (v & 0x0F), (v & 0xF0) >> 4 | |
#define BR(r) OP(0, SGM_REG, r) | |
#define WR(r) OP(1, SGM_REG, r) | |
#define BM(r) OP(0, SGM_PTR, r) | |
#define WM(r) OP(1, SGM_PTR, r) | |
typedef struct sgm_operand_t { | |
bool isWord; | |
sgmByte reg, addressing; | |
} sgmOperand; | |
enum sgmRegisters { | |
R0 = 0, | |
R1, | |
R2, | |
R3, | |
R4, | |
R5, | |
R6, | |
R7, | |
RCount | |
}; | |
typedef struct sgm_cpu_t { | |
sgmByte ram[SGM_RAM_SIZE]; | |
union { | |
sgmByte byteRegisters[RCount]; | |
sgmWord wordRegisters[RCount / 2]; | |
}; | |
sgmWord pc, sp; | |
sgmByte flag; | |
} sgmCPU; | |
typedef struct sgm_instruction_t { | |
char name[6]; | |
void (*exec)(sgmCPU*); | |
} sgmInstruction; | |
sgmCPU* sgm_cpu_new(); | |
void sgm_cpu_free(sgmCPU* cpu); | |
void sgm_cpu_load(sgmCPU* cpu, sgmByte* program, sgmWord n); | |
void sgm_cpu_tick(sgmCPU* cpu); | |
void sgm_cpu_run(sgmCPU* cpu); | |
#endif // SGM_CPU_H |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment