/* * Unnamed 8-bit processing unit * Made by github.com/xamidev * * This is free and unencumbered software released into the public domain. * For more information, please refer to */ #include #include #include #include #include #define MEM_SIZE 256 #define NUM_REGISTERS 4 /* * Instruction set * Here, we're making a RISC (reduced instruction set computer) * so we're staying minimalistic. */ typedef enum { // 0x00 -> No operation NOP = 0, // 0xA? -> Memory operations MOV = 0xA0, // 0xB? -> Arithmetic operations ADD = 0xB0, SUB = 0xB1, // 0xC? -> Bitwise operations OR = 0xC0, AND = 0xC1, XOR = 0xC2, // 0xE? -> Jump and comparisons JMP = 0xE0, JEQ = 0xE1, CMP = 0xE2, // 0xF? -> Misc operations HLT = 0xFF } instruction_set_t; /* * CPU structure definition * Contains 4 8-bit registers, memory, a program counter, a halt switch, and flags. */ typedef struct { uint8_t reg[NUM_REGISTERS]; uint8_t memory[MEM_SIZE]; uint16_t pc; bool halted; bool equal_flag; int flag_clear_delay; } CPU_t; CPU_t cpu; /* * Initializing the CPU: program counter and registers to zero, halted flag to false. */ void cpu_init() { cpu.pc = 0; cpu.halted = false; cpu.equal_flag = false; cpu.flag_clear_delay = 0; for (size_t i=0; i 0) { cpu.flag_clear_delay--; if (cpu.flag_clear_delay == 0) { cpu.equal_flag = false; } } switch (opcode) { // Some lines are repeating.. Should make this a better way.. case NOP: break; case MOV: reg1 = cpu.memory[cpu.pc++]; reg2 = cpu.memory[cpu.pc++]; cpu.reg[reg1] = cpu.reg[reg2]; break; case ADD: reg1 = cpu.memory[cpu.pc++]; reg2 = cpu.memory[cpu.pc++]; cpu.reg[reg1] += cpu.reg[reg2]; break; case SUB: reg1 = cpu.memory[cpu.pc++]; reg2 = cpu.memory[cpu.pc++]; cpu.reg[reg1] -= cpu.reg[reg2]; break; case OR: reg1 = cpu.memory[cpu.pc++]; reg2 = cpu.memory[cpu.pc++]; cpu.reg[reg1] |= cpu.reg[reg2]; break; case AND: reg1 = cpu.memory[cpu.pc++]; reg2 = cpu.memory[cpu.pc++]; cpu.reg[reg1] &= cpu.reg[reg2]; break; case XOR: reg1 = cpu.memory[cpu.pc++]; reg2 = cpu.memory[cpu.pc++]; cpu.reg[reg1] ^= cpu.reg[reg2]; break; case HLT: cpu.halted = true; break; case JMP: addr = cpu.memory[cpu.pc++]; cpu.pc = addr; break; case JEQ: reg1 = cpu.memory[cpu.pc++]; addr = cpu.memory[cpu.pc++]; if (cpu.equal_flag) { cpu.pc = addr; } break; case CMP: reg1 = cpu.memory[cpu.pc++]; reg2 = cpu.memory[cpu.pc++]; cpu.equal_flag = (cpu.reg[reg1] == cpu.reg[reg2]); cpu.flag_clear_delay = 2; break; // TODO: complete instruction set default: printf("Unknown instruction: 0x%02X\n", opcode); cpu.halted = true; break; } } /* * Loading the program in memory */ void cpu_load(const uint8_t* program, size_t size) { for (size_t i=0; i\n", argv[0]); return -1; } assemble(argv[1]); // Dumping our program mem_dump(); reg_write(1, 0x12); reg_write(2, 0x10); cpu_run(); // Post-mortem analysis cpu_dump(); return 0; }