Skip to content

Instantly share code, notes, and snippets.

@DCubix
Created July 3, 2018 20:38
Show Gist options
  • Save DCubix/006799b6767bbd04f5657fafa9b194c2 to your computer and use it in GitHub Desktop.
Save DCubix/006799b6767bbd04f5657fafa9b194c2 to your computer and use it in GitHub Desktop.
RIP
#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;
}
#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