312 lines
5.8 KiB
C
312 lines
5.8 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("Output enabled?: %d\n", cpu->output_enable);
|
|
|
|
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 , 158 };
|
|
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;
|
|
}
|
|
|