Git add src
This commit is contained in:
parent
f84ee341a4
commit
520561dade
|
|
@ -0,0 +1 @@
|
||||||
|
/target
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "2.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "overture_cpu_emulator"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
[package]
|
||||||
|
name = "overture_cpu_emulator"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bitflags = "2.10.0"
|
||||||
|
|
@ -0,0 +1,310 @@
|
||||||
|
use std::{thread, time, io, io::Read};
|
||||||
|
use bitflags::bitflags;
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
struct Instruction: u8 {
|
||||||
|
const immediate = 0b00111111;
|
||||||
|
const left_args = 0b00111000;
|
||||||
|
const right_args = 0b00000111;
|
||||||
|
const mode = 0b11000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Register {
|
||||||
|
R0,
|
||||||
|
R1,
|
||||||
|
R2,
|
||||||
|
R3,
|
||||||
|
R4,
|
||||||
|
R5,
|
||||||
|
IO,
|
||||||
|
}
|
||||||
|
impl From<u8> for Register {
|
||||||
|
fn from(value: u8) -> Self {
|
||||||
|
match value {
|
||||||
|
0 => Self::R0,
|
||||||
|
1 => Self::R1,
|
||||||
|
2 => Self::R2,
|
||||||
|
3 => Self::R3,
|
||||||
|
4 => Self::R4,
|
||||||
|
5 => Self::R5,
|
||||||
|
6 => Self::IO,
|
||||||
|
_ => Self::R0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CalculateOperation {
|
||||||
|
OR,
|
||||||
|
NAND,
|
||||||
|
NOR,
|
||||||
|
AND,
|
||||||
|
ADD,
|
||||||
|
SUB,
|
||||||
|
}
|
||||||
|
impl From<u8> for CalculateOperation {
|
||||||
|
fn from(value: u8) -> Self {
|
||||||
|
match value {
|
||||||
|
0 => Self::OR,
|
||||||
|
1 => Self::NAND,
|
||||||
|
2 => Self::NOR,
|
||||||
|
3 => Self::AND,
|
||||||
|
4 => Self::ADD,
|
||||||
|
5 => Self::SUB,
|
||||||
|
_ => Self::OR,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ConditionOperation {
|
||||||
|
NEVER,
|
||||||
|
EQZ,
|
||||||
|
LTZ,
|
||||||
|
LTEQZ,
|
||||||
|
ALWAYS,
|
||||||
|
NEQZ,
|
||||||
|
GTEQZ,
|
||||||
|
GTZ,
|
||||||
|
}
|
||||||
|
impl From<u8> for ConditionOperation {
|
||||||
|
fn from(value: u8) -> Self {
|
||||||
|
match value {
|
||||||
|
0 => Self::NEVER,
|
||||||
|
1 => Self::EQZ,
|
||||||
|
2 => Self::LTZ,
|
||||||
|
3 => Self::LTEQZ,
|
||||||
|
4 => Self::ALWAYS,
|
||||||
|
5 => Self::NEQZ,
|
||||||
|
6 => Self::GTEQZ,
|
||||||
|
7 => Self::GTZ,
|
||||||
|
_ => Self::NEVER,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum DecodedInstruction {
|
||||||
|
Immediate (u8),
|
||||||
|
Calculate (CalculateOperation),
|
||||||
|
Copy (Register, Register),
|
||||||
|
Condition (ConditionOperation),
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Overture<'a> {
|
||||||
|
rom: &'a [u8],
|
||||||
|
current_instruction: &'a u8,
|
||||||
|
program_counter: u8,
|
||||||
|
clock_rate_duration: time::Duration,
|
||||||
|
step_mode: bool,
|
||||||
|
|
||||||
|
r0: u8,
|
||||||
|
r1: u8,
|
||||||
|
r2: u8,
|
||||||
|
r3: u8,
|
||||||
|
r4: u8,
|
||||||
|
r5: u8,
|
||||||
|
|
||||||
|
io: u8,
|
||||||
|
input_enable: bool,
|
||||||
|
output_enable: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Overture<'a> {
|
||||||
|
pub fn new(rom: &'a [u8], clock_rate_hertz: u32, step_mode: bool) -> Self {
|
||||||
|
Overture {
|
||||||
|
rom: rom,
|
||||||
|
current_instruction: &rom[0],
|
||||||
|
program_counter: 0x00,
|
||||||
|
clock_rate_duration: Overture::from_hertz(clock_rate_hertz),
|
||||||
|
step_mode: step_mode,
|
||||||
|
|
||||||
|
r0: 0x00,
|
||||||
|
r1: 0x00,
|
||||||
|
r2: 0x00,
|
||||||
|
r3: 0x00,
|
||||||
|
r4: 0x00,
|
||||||
|
r5: 0x00,
|
||||||
|
io: 0x00,
|
||||||
|
|
||||||
|
input_enable: false,
|
||||||
|
output_enable: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start(&mut self) {
|
||||||
|
let mut io_stdin = io::stdin();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
self.program_counter = match self.program_counter.checked_add(1) {
|
||||||
|
Some(new) => new,
|
||||||
|
None => break
|
||||||
|
};
|
||||||
|
self.current_instruction = match self.rom.get(usize::from(self.program_counter - 1)) {
|
||||||
|
Some(instruction) => instruction,
|
||||||
|
None => break
|
||||||
|
};
|
||||||
|
self.input_enable = false;
|
||||||
|
self.output_enable = false;
|
||||||
|
|
||||||
|
// Decode Instruction
|
||||||
|
let decoded_instruction: DecodedInstruction = match self.get_instruction_operand(Instruction::mode) {
|
||||||
|
0b0000_0000 => DecodedInstruction::Immediate(
|
||||||
|
self.get_instruction_operand(Instruction::immediate)
|
||||||
|
),
|
||||||
|
0b0100_0000 => DecodedInstruction::Calculate(
|
||||||
|
self.get_instruction_operand(Instruction::right_args).into()
|
||||||
|
),
|
||||||
|
0b1000_0000 => DecodedInstruction::Copy(
|
||||||
|
(self.get_instruction_operand(Instruction::left_args) >> 3).into(),
|
||||||
|
self.get_instruction_operand(Instruction::right_args).into()
|
||||||
|
),
|
||||||
|
0b1100_0000 => DecodedInstruction::Condition(
|
||||||
|
self.get_instruction_operand(Instruction::right_args).into()
|
||||||
|
),
|
||||||
|
_ => DecodedInstruction::Immediate(
|
||||||
|
self.get_instruction_operand(Instruction::immediate)
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Execute Instruction
|
||||||
|
match decoded_instruction {
|
||||||
|
DecodedInstruction::Immediate(value) => {
|
||||||
|
self.r0 = value;
|
||||||
|
}
|
||||||
|
DecodedInstruction::Calculate(operation) => {
|
||||||
|
match operation {
|
||||||
|
CalculateOperation::OR => self.r3 = self.r1 | self.r2,
|
||||||
|
CalculateOperation::NAND => self.r3 = !(self.r1 & self.r2),
|
||||||
|
CalculateOperation::NOR => self.r3 = !(self.r1 | self.r2),
|
||||||
|
CalculateOperation::AND => self.r3 = self.r1 & self.r2,
|
||||||
|
CalculateOperation::ADD => self.r3 = self.r1 + self.r2,
|
||||||
|
CalculateOperation::SUB => self.r3 = self.r1 - self.r2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DecodedInstruction::Copy(source, destination) => {
|
||||||
|
let multiplexed_source = match source {
|
||||||
|
Register::R0 => self.r0,
|
||||||
|
Register::R1 => self.r1,
|
||||||
|
Register::R2 => self.r2,
|
||||||
|
Register::R3 => self.r3,
|
||||||
|
Register::R4 => self.r4,
|
||||||
|
Register::R5 => self.r5,
|
||||||
|
Register::IO => {
|
||||||
|
self.input_enable = true;
|
||||||
|
|
||||||
|
self.io
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match destination {
|
||||||
|
Register::R0 => self.r0 = multiplexed_source,
|
||||||
|
Register::R1 => self.r1 = multiplexed_source,
|
||||||
|
Register::R2 => self.r2 = multiplexed_source,
|
||||||
|
Register::R3 => self.r3 = multiplexed_source,
|
||||||
|
Register::R4 => self.r4 = multiplexed_source,
|
||||||
|
Register::R5 => self.r5 = multiplexed_source,
|
||||||
|
Register::IO => self.io = {
|
||||||
|
self.output_enable = true;
|
||||||
|
|
||||||
|
multiplexed_source
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
DecodedInstruction::Condition(operation) => {
|
||||||
|
match operation {
|
||||||
|
ConditionOperation::NEVER => {}
|
||||||
|
ConditionOperation::EQZ => {
|
||||||
|
if self.r3 == 0 {
|
||||||
|
self.program_counter = self.r0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ConditionOperation::LTZ => {
|
||||||
|
if self.r3 < 0 {
|
||||||
|
self.program_counter = self.r0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ConditionOperation::LTEQZ => {
|
||||||
|
if self.r3 <= 0 {
|
||||||
|
self.program_counter = self.r0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ConditionOperation::ALWAYS => {
|
||||||
|
self.program_counter = self.r0
|
||||||
|
}
|
||||||
|
ConditionOperation::NEQZ => {
|
||||||
|
if self.r3 != 0 {
|
||||||
|
self.program_counter = self.r0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ConditionOperation::GTEQZ => {
|
||||||
|
if self.r3 >= 0 {
|
||||||
|
self.program_counter = self.r0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ConditionOperation::GTZ => {
|
||||||
|
if self.r3 > 0 {
|
||||||
|
self.program_counter = self.r0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.print_diagnostics();
|
||||||
|
|
||||||
|
if self.step_mode {
|
||||||
|
match io_stdin.read(&mut [0]) {
|
||||||
|
Ok(_) => continue,
|
||||||
|
Err(_) => break
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread::sleep(self.clock_rate_duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_diagnostics(&self) {
|
||||||
|
println!("");
|
||||||
|
println!("Program counter: {:x} ({})", self.program_counter, self.program_counter);
|
||||||
|
println!("Current instruction: {:x} ({})", self.current_instruction, self.current_instruction);
|
||||||
|
println!("r0: {:x} ({})", self.r0, self.r0);
|
||||||
|
println!("r1: {:x} ({})", self.r1, self.r1);
|
||||||
|
println!("r2: {:x} ({})", self.r2, self.r2);
|
||||||
|
println!("r3: {:x} ({})", self.r3, self.r3);
|
||||||
|
println!("r4: {:x} ({})", self.r4, self.r4);
|
||||||
|
println!("r5: {:x} ({})", self.r5, self.r5);
|
||||||
|
println!("io: {:x} ({})", self.io, self.io);
|
||||||
|
println!("input: {}", self.input_enable);
|
||||||
|
println!("output: {}", self.output_enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_hertz(hertz: u32) -> time::Duration {
|
||||||
|
let second = time::Duration::from_secs(1);
|
||||||
|
|
||||||
|
match second.checked_div(hertz) {
|
||||||
|
Some(hertz) => hertz,
|
||||||
|
None => second
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_instruction_operand(&self, operand_type: Instruction) -> u8 {
|
||||||
|
self.current_instruction & operand_type.bits()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let rom: [u8; _] = [
|
||||||
|
0x3f, // immediate 63
|
||||||
|
0x81, // mov r0 r1
|
||||||
|
0x07, // immediate 7
|
||||||
|
0x82, // mov r0 r2
|
||||||
|
0x44, // add
|
||||||
|
0x9e, // mov r3 out
|
||||||
|
];
|
||||||
|
let mut cpu = Overture::new(
|
||||||
|
&rom,
|
||||||
|
4,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
cpu.start();
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue