Skip to content

Instantly share code, notes, and snippets.

@harubaru
Last active May 24, 2024 09:53
Show Gist options
  • Save harubaru/dd750fb53380fa96afa01a5a01c75a19 to your computer and use it in GitHub Desktop.
Save harubaru/dd750fb53380fa96afa01a5a01c75a19 to your computer and use it in GitHub Desktop.
some random shit
/*
hello, i got bored while trying to sleep again so here is this.
it's a dumb little CPU emulator thing just to get back into the C grind.
anyways, don't mind its sillyness, it's not that much of a serious
project. have a good day!
~ haru */
// 0 : blit <val> <addr> : plaps a value to an address
// 1 : blop <addr> : prints an address's contents to console
// 2 : store <register> <addr> : stores a register's contents to an address
// 3 : fetch <register <addr> : fetches an address's contents into a register
// 4 : astore <register> : stores a register's contents into an alu accumulator
// 5 : afetch <register> : stores an alu accumulator's contents into a register
// 6 : aswap : swaps the accumulators around. theres two lol.
// 7 : jmp <addr> : set instruction pointer to address
// 8 : gtj <addr> : Acc0 > Acc1 -> ip = addr
// 9 : etj <addr> : Acc0 == Acc1 -> ip = addr
// 10 : iadd : Acc0 = Acc0 + Acc1
// 11 : isub : Acc0 = Acc0 - Acc1
// 12 : imul : Acc0 = Acc0 * Acc1
// 13 : idiv : Acc0 = Acc0 / Acc1
// 14 : vstore <register> <addr> : V(register)[0..8] = Heap[Addr..Addr+8]
// 15 : vfetch <register> <addr> : Heap[Addr..Addr+8] = V(register)[0..8]
// 16 : vadd <vreg> <vreg> : V(register a)[0..8] = V(register a)[0..8] + V(register b)[0..8]
// 17 : vsub <vreg> <vreg> : V(register a)[0..8] = V(register a)[0..8] - V(register b)[0..8]
// 18 : vmul <vreg> <vreg> : V(register a)[0..8] = V(register a)[0..8] * V(register b)[0..8]
// 19 : vdiv <vreg> <vreg> : V(register a)[0..8] = V(register a)[0..8] / V(register b)[0..8]
// 20 : hlt : Ip = DS - 1
// 21 : rtsc <register> : Stores the internal timestamp counter into a register.
// 22 : mov <register> <value> : Stores a value into a register.
// 23 : mstore <register> <addr> : M(register)[0..M_X][0..M_Y] = Heap[Addr..M_X][Addr..M_Y]
// 24 : madd <mreg> <mreg> : M(register a)[0..M_X][0..M_Y] = M(register a)[0..M_X][0..M_Y] + M(register b)[0..M_X][0..M_Y]
// 25 : msub <mreg> <mreg> : M(register a)[0..M_X][0..M_Y] = M(register a)[0..M_X][0..M_Y] - M(register b)[0..M_X][0..M_Y]
// 26 : mmul <mreg> <mreg> : M(register a)[0..M_X][0..M_Y] = M(register a)[0..M_X][0..M_Y] * M(register b)[0..M_X][0..M_Y]
// 27 : mdiv <mreg> <mreg> : M(register a)[0..M_X][0..M_Y] = M(register a)[0..M_X][0..M_Y] / M(register b)[0..M_X][0..M_Y]
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#define CPU_REGISTER_COUNT 4
#define CPU_HEAP_SIZE 0xFFF
#define CPU_DEFAULT_IP 0
#define CPU_DATA_TYPE uint64_t
#define CPU_ADDR_TYPE uint64_t
// parallel extension
#define CPU_VECTOR_REGISTER_COUNT 4
#define CPU_VECTOR_REGISTER_BYTES 4
#define CPU_MATRIX_REGISTER_COUNT 4
#define CPU_MATRIX_REGISTER_X 4
#define CPU_MATRIX_REGISTER_Y 4
#define DS (CPU_HEAP_SIZE)/2
typedef struct cpu {
// extensions
CPU_DATA_TYPE vector_registers[CPU_VECTOR_REGISTER_COUNT][CPU_VECTOR_REGISTER_BYTES];
CPU_DATA_TYPE matrix_registers[CPU_MATRIX_REGISTER_COUNT][CPU_MATRIX_REGISTER_X][CPU_MATRIX_REGISTER_Y];
CPU_DATA_TYPE registers[CPU_REGISTER_COUNT];
CPU_DATA_TYPE accumulators[2];
CPU_DATA_TYPE heap[CPU_HEAP_SIZE]; // for decoding, instruction takes up 1 byte, arguments take the next bytes
CPU_ADDR_TYPE instruction_pointer;
uint64_t tsc;
CPU_ADDR_TYPE dsp; // data segment pointer. any addresses to any instruction is translated to the ds pointer. jmp <addr> == jmp <addr + ds>
CPU_DATA_TYPE instruction_cache[3]; // 0 = instruction id, 1 = arg 1, 2 = arg 2
} cpu_t;
// Blits a value onto heap.
void blit(CPU_DATA_TYPE val, CPU_ADDR_TYPE addr, cpu_t *cpu)
{
cpu->heap[addr] = val;
}
// Blops a value from heap onto console.
void blop(CPU_ADDR_TYPE addr, cpu_t *cpu)
{
printf("%d\n", cpu->heap[addr]);
}
// Store a register onto the heap.
void store(CPU_DATA_TYPE reg_idx, CPU_ADDR_TYPE addr, cpu_t *cpu)
{
cpu->heap[addr] = cpu->registers[reg_idx];
}
// Fetch a register from the heap.
void fetch(CPU_DATA_TYPE reg_idx, CPU_ADDR_TYPE addr, cpu_t * cpu)
{
cpu->registers[reg_idx] = cpu->heap[addr];
}
// Load first accumulator with the value from a register.
void astore(CPU_DATA_TYPE reg_idx, cpu_t *cpu)
{
cpu->accumulators[0] = cpu->registers[reg_idx];
}
// Load first accumulator into register.
void afetch(CPU_DATA_TYPE reg_idx, cpu_t *cpu)
{
cpu->registers[reg_idx] = cpu->accumulators[0];
}
// Swap the contents of the accumulator register.
void aswap(cpu_t *cpu)
{
cpu->accumulators[0] = cpu->accumulators[0] ^ cpu->accumulators[1];
cpu->accumulators[1] = cpu->accumulators[0] ^ cpu->accumulators[1];
cpu->accumulators[0] = cpu->accumulators[0] ^ cpu->accumulators[1];
}
void jump(CPU_ADDR_TYPE jump_pointer, cpu_t *cpu)
{
cpu->instruction_pointer = jump_pointer;
}
// If Acc0 > Acc1, jump to jump_pointer, else do not jump.
void greater_than_jump(CPU_ADDR_TYPE jump_pointer, cpu_t *cpu)
{
if (cpu->accumulators[0] > cpu->accumulators[1]) {
jump(jump_pointer, cpu);
}
}
// If Acc0 == Acc1, jump to jump_pointer, else do not jump.
void equal_jump(CPU_ADDR_TYPE jump_pointer, cpu_t *cpu)
{
if (cpu->accumulators[0] == cpu->accumulators[1]) {
jump(jump_pointer, cpu);
}
}
// Acc0 = Acc0 + Acc1
void iadd(cpu_t *cpu)
{
cpu->accumulators[0] = cpu->accumulators[0] + cpu->accumulators[1];
}
// Acc0 = Acc0 - Acc1
void isub(cpu_t *cpu)
{
cpu->accumulators[0] = cpu->accumulators[0] - cpu->accumulators[1];
}
// Acc0 = Acc0 * Acc1
void imul(cpu_t *cpu)
{
cpu->accumulators[0] = cpu->accumulators[0] * cpu->accumulators[1];
}
// Acc0 = Acc0 / Acc1
void idiv(cpu_t *cpu)
{
cpu->accumulators[0] = cpu->accumulators[0] / cpu->accumulators[1];
}
// Va[0..8] = H[BaseAddr...BaseAddr+8]
void vstore(cpu_t *cpu)
{
for (size_t i = 0; i < CPU_VECTOR_REGISTER_BYTES; i++) {
cpu->vector_registers[cpu->instruction_cache[1]][i] = cpu->heap[cpu->instruction_cache[2] + i];
}
}
// H[BaseAddr...BaseAddr+8] = Va[0..8]
void vfetch(cpu_t *cpu)
{
for (size_t i = 0; i < CPU_VECTOR_REGISTER_BYTES; i++) {
cpu->heap[cpu->instruction_cache[2] + i] = cpu->vector_registers[cpu->instruction_cache[1]][i];
}
}
// Va = Va + Vb
void vadd(cpu_t *cpu)
{
for (size_t i = 0; i < CPU_VECTOR_REGISTER_BYTES; i++) {
cpu->vector_registers[cpu->instruction_cache[1]][i] = cpu->vector_registers[cpu->instruction_cache[1]][i] + cpu->vector_registers[cpu->instruction_cache[2]][i];
}
}
// Va = Va - Vb
void vsub(cpu_t *cpu)
{
for (size_t i = 0; i < CPU_VECTOR_REGISTER_BYTES; i++) {
cpu->vector_registers[cpu->instruction_cache[1]][i] = cpu->vector_registers[cpu->instruction_cache[1]][i] - cpu->vector_registers[cpu->instruction_cache[2]][i];
}
}
// Va = Va * Vb
void vmul(cpu_t *cpu)
{
for (size_t i = 0; i < CPU_VECTOR_REGISTER_BYTES; i++) {
cpu->vector_registers[cpu->instruction_cache[1]][i] = cpu->vector_registers[cpu->instruction_cache[1]][i] * cpu->vector_registers[cpu->instruction_cache[2]][i];
}
}
// Va = Va / Vb
void vdiv(cpu_t *cpu)
{
for (size_t i = 0; i < CPU_VECTOR_REGISTER_BYTES; i++) {
cpu->vector_registers[cpu->instruction_cache[1]][i] = cpu->vector_registers[cpu->instruction_cache[1]][i] * cpu->vector_registers[cpu->instruction_cache[2]][i];
}
}
// Load Time Stamp Counter into Register.
void rtsc(CPU_DATA_TYPE reg_idx, cpu_t *cpu)
{
cpu->registers[reg_idx] = cpu->tsc;
}
// Load an integer into a Register.
void mov(CPU_DATA_TYPE reg_idx, CPU_DATA_TYPE val, cpu_t *cpu)
{
cpu->registers[reg_idx] = val;
}
// M(register)[0..M_X][0..M_Y] = Heap[Addr..M_X][Addr..M_Y]
void mstore(cpu_t *cpu)
{
for (size_t y = 0; y < CPU_MATRIX_REGISTER_Y; y++) {
for (size_t x = 0; x < CPU_MATRIX_REGISTER_X; x++) {
cpu->matrix_registers[cpu->instruction_cache[1]][x][y] = cpu->heap[cpu->instruction_cache[2] + (y + (x * CPU_MATRIX_REGISTER_X))];
}
}
}
// Ma = Ma + Mb
void madd(cpu_t *cpu)
{
for (size_t x = 0; x < CPU_MATRIX_REGISTER_X; x++) {
for (size_t y = 0; y < CPU_MATRIX_REGISTER_Y; y++) {
cpu->matrix_registers[cpu->instruction_cache[1]][x][y] = cpu->matrix_registers[cpu->instruction_cache[1]][x][y] + cpu->matrix_registers[cpu->instruction_cache[2]][x][y];
}
}
}
// Ma = Ma - Mb
void msub(cpu_t *cpu)
{
for (size_t x = 0; x < CPU_MATRIX_REGISTER_X; x++) {
for (size_t y = 0; y < CPU_MATRIX_REGISTER_Y; y++) {
cpu->matrix_registers[cpu->instruction_cache[1]][x][y] = cpu->matrix_registers[cpu->instruction_cache[1]][x][y] - cpu->matrix_registers[cpu->instruction_cache[2]][x][y];
}
}
}
// Ma = Ma * Mb
void mmul(cpu_t *cpu)
{
for (size_t x = 0; x < CPU_MATRIX_REGISTER_X; x++) {
for (size_t y = 0; y < CPU_MATRIX_REGISTER_Y; y++) {
cpu->matrix_registers[cpu->instruction_cache[1]][x][y] = cpu->matrix_registers[cpu->instruction_cache[1]][x][y] * cpu->matrix_registers[cpu->instruction_cache[2]][x][y];
}
}
}
// Ma = Ma / Mb
void mdiv(cpu_t *cpu)
{
for (size_t x = 0; x < CPU_MATRIX_REGISTER_X; x++) {
for (size_t y = 0; y < CPU_MATRIX_REGISTER_Y; y++) {
cpu->matrix_registers[cpu->instruction_cache[1]][x][y] = cpu->matrix_registers[cpu->instruction_cache[1]][x][y] / cpu->matrix_registers[cpu->instruction_cache[2]][x][y];
}
}
}
// IP == 0 represents halt.
int control_step(cpu_t *cpu)
{
uint8_t different_ip = 0;
for (size_t i = 0; i < 3; i++)
cpu->instruction_cache[i] = cpu->heap[cpu->instruction_pointer+i];
switch (cpu->instruction_cache[0]) {
case 20: // hlt
return 1;
case 0: // blit <val> <addr>
blit(cpu->instruction_cache[1], cpu->instruction_cache[2], cpu);
break;
case 1: // blop <addr>
blop(cpu->instruction_cache[1], cpu);
break;
case 2: // store <reg_idx> <addr>
store(cpu->instruction_cache[1], cpu->instruction_cache[2], cpu);
break;
case 3: // fetch <reg_idx> <addr>
fetch(cpu->instruction_cache[1], cpu->instruction_cache[2], cpu);
break;
case 4: // astore <reg_idx>
astore(cpu->instruction_cache[1], cpu);
break;
case 5: // afetch <reg_idx>
afetch(cpu->instruction_cache[1], cpu);
break;
case 6: // aswap
aswap(cpu);
break;
case 7: // jump <addr>
jump(cpu->instruction_cache[1], cpu);
different_ip = 1;
break;
case 8: // greater than jump <addr> (acc0 > acc1 -> addr)
greater_than_jump(cpu->instruction_cache[1], cpu);
different_ip = 1;
break;
case 9: // equal to jump <addr> (acc0 == acc1 -> addr)
equal_jump(cpu->instruction_cache[1], cpu);
different_ip = 1;
break;
case 10: // add
iadd(cpu);
break;
case 11: // sub
isub(cpu);
break;
case 12: // mul
imul(cpu);
break;
case 13: // div
idiv(cpu);
break;
case 14:
vstore(cpu);
break;
case 15:
vfetch(cpu);
break;
case 16:
vadd(cpu);
break;
case 17:
vsub(cpu);
break;
case 18:
vmul(cpu);
break;
case 19:
vdiv(cpu);
break;
case 21:
rtsc(cpu->instruction_cache[1], cpu);
break;
case 22:
mov(cpu->instruction_cache[1], cpu->instruction_cache[2], cpu);
break;
case 23:
mstore(cpu);
break;
case 24:
madd(cpu);
break;
case 25:
msub(cpu);
break;
case 26:
mmul(cpu);
break;
case 27:
mdiv(cpu);
break;
}
if (!different_ip)
cpu->instruction_pointer = cpu->instruction_pointer + 3;
cpu->tsc++;
return 0;
}
void execute(cpu_t *cpu)
{
int status = 0;
while (!status) {
status = control_step(cpu);
//dbg_print_registers(cpu);
}
}
void dbg_print_registers(cpu_t *cpu)
{
printf("===Registers==\n");
for (size_t i = 0; i < CPU_REGISTER_COUNT; i++)
printf("R%d - %d\n", i, cpu->registers[i]);
printf("==Accumulators==\n");
for (size_t i = 0; i < 2; i++)
printf("A%d - %d\n", i, cpu->accumulators[i]);
printf("==Vectors==\n");
for (size_t i = 0; i < CPU_VECTOR_REGISTER_COUNT; i++) {
printf("V%d - ", i);
for(size_t j = 0; j < CPU_VECTOR_REGISTER_BYTES; j++)
printf("%d ", cpu->vector_registers[i][j]);
printf("\n");
}
printf("==Matrices==\n");
for (size_t m_i = 0; m_i < CPU_MATRIX_REGISTER_COUNT; m_i++) {
printf(" M%d\n", m_i);
for (size_t i = 0; i < CPU_MATRIX_REGISTER_X; i++) {
printf("[[");
for (size_t j = 0; j < CPU_MATRIX_REGISTER_Y; j++) {
printf("%d ", cpu->matrix_registers[m_i][i][j]);
}
printf("]]\n");
}
}
printf("==Miscellanea==\n");
printf("Ip - %d\nTSC - %d\n", cpu->instruction_pointer, cpu->tsc);
}
void blit_instructions(CPU_DATA_TYPE *instructions, CPU_DATA_TYPE instruction_count, CPU_ADDR_TYPE base_addr, cpu_t *cpu)
{
// op = instruction + arg 1 + arg 2
for (size_t i = base_addr; i < base_addr + instruction_count; i++)
cpu->heap[i] = instructions[i];
}
int main()
{
printf("%u\n", sizeof(cpu_t));
cpu_t *cpu = malloc(sizeof(cpu_t));
cpu->instruction_pointer = CPU_DEFAULT_IP;
CPU_DATA_TYPE instructions[] = {
0, 1, DS+0, // blit 1 [0]
0, 0, DS+1, // blit 0 [1]
0, 0, DS+2, // blit 0 [2]
0, -1, DS+3,// blit -1 [3]
14, 0, DS+0, // vstore v0 [0]
15, 0, DS+0, // vfetch v0 [0]
15, 0, DS+4, // vfetch v0 [4]
15, 0, DS+8, // vfetch v0 [8]
15, 0, DS+12,// vfetch v0 [12]
23, 0, DS+0, // mstore m0 [0..15]
0, 3, DS+0, // blit 3 [0]
0, 2, DS+1, // blit 2 [1]
0, 6, DS+2, // blit 6 [2]
0, 2, DS+3, // blit 2 [3]
14, 0, DS+0,// vstore v0 [0]
15, 0, DS+0, // vfetch v0 [0]
15, 0, DS+4, // vfetch v0 [4]
15, 0, DS+8, // vfetch v0 [8]
15, 0, DS+12,// vfetch v0 [12]
23, 1, DS+0, // mstore m1 [0..15]
21, 0, 0, // rtsc r0
2, 0, DS+24, // store r0 [24]
1, DS+24, 0, // blop [24]
26, 0, 1, // mmul m0 m1
24, 0, 1, // madd m0 m1
21, 0, 0, // rtsc r0
2, 0, DS+24, // store r0 [24]
1, DS+24, 0, // blop [24]
20, 0, 0, // hlt
};
blit_instructions(instructions, sizeof(instructions)/sizeof(CPU_DATA_TYPE), CPU_DEFAULT_IP, cpu);
execute(cpu);
dbg_print_registers(cpu);
free(cpu);
return 0;
}
/*
2, 0, DS + 51, // fetch r0 51
4, 0, 0, // astore r0
6, 0, 0, // aswap
0, 1, DS + 0,
0, 2, DS + 1,
0, 3, DS + 2,
0, 4, DS + 3,
0, 5, DS + 4,
0, 6, DS + 5,
0, 7, DS + 6,
0, 8, DS + 7,
14, 0, DS + 0,
14, 1, DS + 0,
16, 0, 1,
// end - jmp to beginning conditional after 4 steps
0, 4, DS + 50, // blit 50 4
3, 0, DS + 50, // fetch r0 50
4, 0, 0, // astore r0
6, 0, 0, // swp
3, 0, DS + 51, // fetch r0 51
4, 0, 0, // astore r0
8, 0, 0, // gtj 0
7, 0, 0, // jmp 0
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment