Last active
May 24, 2024 09:53
-
-
Save harubaru/dd750fb53380fa96afa01a5a01c75a19 to your computer and use it in GitHub Desktop.
some random shit
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
/* | |
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