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