Overture-CPU-Emulator/main.c

311 lines
5.7 KiB
C

#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <stdbool.h>
enum overture_mode {
IMMEDIATE,
CALCULATE,
COPY,
CONDITION
};
enum overture_calculate_mode {
OR,
NAND,
NOR,
AND,
ADD,
SUB
};
enum overture_condition_mode {
NEVER,
EQZ,
LTZ,
LTEQZ,
ALWAYS,
NEQZ,
GTEQZ,
GTZ
};
enum overture_registers {
R0,
R1,
R2,
R3,
R4,
R5,
INPUT_OUTPUT
};
void overture_immediate(uint8_t immediate, uint8_t* r0) {
*r0 = immediate;
}
void overture_alu_calculate(enum overture_calculate_mode mode, uint8_t r1, uint8_t r2, uint8_t* r3) {
switch (mode) {
case OR:
*r3 = r1 | r2;
break;
case NAND:
*r3 = ~(r1 & r2);
break;
case NOR:
*r3 = ~(r1 | r2);
break;
case AND:
*r3 = r1 & r2;
break;
case ADD:
*r3 = r1 + r2;
break;
case SUB:
*r3 = r1 - r2;
break;
}
};
void overture_register_copy(uint8_t* source, uint8_t* destination) {
*destination = *source;
};
void overture_condition_jump(enum overture_condition_mode mode, uint8_t r0, uint8_t r3, uint8_t* program_counter) {
switch (mode) {
case NEVER:
return;
case EQZ:
if (r3 == 0)
*program_counter = r0;
break;
case LTZ:
if (r3 < 0)
*program_counter = r0;
break;
case LTEQZ:
if (r3 <= 0)
*program_counter = r0;
break;
case ALWAYS:
*program_counter = r0;
break;
case NEQZ:
if (r3 != 0)
*program_counter = r0;
break;
case GTEQZ:
if (r3 >= 0)
*program_counter = r0;
break;
case GTZ:
if (r3 > 0)
*program_counter = r0;
break;
};
}
typedef struct overture_decoded_instruction {
uint8_t overture_mode : 2;
uint8_t left_operand : 3;
uint8_t right_operand : 3;
uint8_t combined_immediate : 6;
} overture_decoded_instruction;
overture_decoded_instruction overture_decode_instruction(uint8_t current_instruction) {
overture_decoded_instruction instruction = {
.overture_mode = current_instruction >> 6,
.left_operand = (current_instruction << 2) >> 5,
.right_operand = (current_instruction << 5) >> 5,
.combined_immediate = (current_instruction << 2) >> 2,
};
return instruction;
};
void overture_fetch_instruction(uint8_t program_counter, uint8_t* current_instruction, uint8_t rom[256]) {
*current_instruction = rom[program_counter - 1];
}
typedef struct overture {
bool step_mode;
int clock_speed_hz;
uint8_t program_counter;
uint8_t r0;
uint8_t r1;
uint8_t r2;
uint8_t r3;
uint8_t r4;
uint8_t r5;
uint8_t input;
uint8_t output;
bool output_enable;
uint8_t current_instruction;
} overture;
void sleep_hz(int hz) {
usleep(1000000 / hz);
};
uint8_t* multiplex_source(uint8_t operand, overture* cpu) {
uint8_t* source;
switch (operand) {
case R0:
source = &(cpu->r0);
break;
case R1:
source = &(cpu->r1);
break;
case R2:
source = &(cpu->r2);
break;
case R3:
source = &(cpu->r3);
break;
case R4:
source = &(cpu->r4);
break;
case R5:
source = &(cpu->r5);
break;
case INPUT_OUTPUT:
source = &(cpu->input);
break;
}
return source;
}
uint8_t* multiplex_destination(uint8_t operand, overture* cpu) {
uint8_t* destination;
switch (operand) {
case R0:
destination = &(cpu->r0);
break;
case R1:
destination = &(cpu->r1);
break;
case R2:
destination = &(cpu->r2);
break;
case R3:
destination = &(cpu->r3);
break;
case R4:
destination = &(cpu->r4);
break;
case R5:
destination = &(cpu->r5);
break;
case INPUT_OUTPUT:
destination = &(cpu->output);
break;
}
return destination;
}
void overture_execute_instruction(overture_decoded_instruction instruction, overture* cpu) {
uint8_t* source_register = multiplex_source(instruction.left_operand, cpu);
uint8_t* destination_register = multiplex_destination(instruction.right_operand, cpu);
switch (instruction.overture_mode) {
case IMMEDIATE:
overture_immediate(instruction.combined_immediate, &(cpu->r0));
break;
case CALCULATE:
overture_alu_calculate(instruction.right_operand, cpu->r1, cpu->r2, &(cpu->r3));
break;
case COPY:
overture_register_copy(source_register, destination_register);
if (instruction.right_operand == INPUT_OUTPUT) {
cpu->output_enable = true;
}
break;
case CONDITION:
overture_condition_jump(instruction.right_operand, cpu->r0, cpu->r3, &(cpu->program_counter));
break;
};
}
void cpu_diagnostics(overture* cpu) {
if (cpu->step_mode) {
printf("Step mode\n");
} else {
printf("Clock speed: %dhz\n", cpu->clock_speed_hz);
}
printf("Program counter: %d\n\n", cpu->program_counter);
printf("r0: %d\n", cpu->r0);
printf("r1: %d\n", cpu->r1);
printf("r2: %d\n", cpu->r2);
printf("r3: %d\n", cpu->r3);
printf("r4: %d\n", cpu->r4);
printf("r5: %d\n\n", cpu->r5);
printf("input: %d\n", cpu->input);
printf("output: %d\n", cpu->output);
printf("Current instruction: %d\n\n", cpu->current_instruction);
}
void overture_cycle(overture* cpu, uint8_t rom[256]) {
if (cpu->program_counter == 255) {
cpu->program_counter = 0;
};
cpu->program_counter += 1;
cpu->output_enable = false;
overture_fetch_instruction(cpu->program_counter, &(cpu->current_instruction), rom);
overture_decoded_instruction instruction = overture_decode_instruction(cpu->current_instruction);
overture_execute_instruction(instruction, cpu);
cpu_diagnostics(cpu);
}
void overture_start_clock(overture* cpu, uint8_t rom[256]) {
while (true) {
if (cpu->step_mode) {
getchar();
} else {
sleep_hz(cpu->clock_speed_hz);
}
overture_cycle(cpu, rom);
};
}
int main() {
uint8_t rom[256] = { 63, 129, 7, 130, 68 };
overture cpu = {
.step_mode = true,
.clock_speed_hz = 1,
.program_counter = 0,
.r0 = 0,
.r1 = 0,
.r2 = 0,
.r3 = 0,
.r4 = 0,
.r5 = 0,
.input = 0,
.output = 0,
.output_enable = true,
.current_instruction = 0
};
overture_start_clock(&cpu, rom);
return 0;
}