use std::cell::{Ref, RefCell, RefMut};
use std::ops::Add;
use std::rc::Rc;
use std::time::{Duration, Instant};
use osiris_data::data::atomic::Word;
use osiris_data::data::composite::ProduceConsume;
use osiris_data::data::identification::{Address, Identifier};
use osiris_data::memory::{Memory, MemoryError, MemoryResult};
use crate::operation;
use crate::operation::{Instruction, Operation, OperationSet};
use crate::operation::error::{OperationError, OperationResult};
use crate::register::{RegisterId, RegisterRange};
use crate::register::floating_point::{Number, VectorApplication};
use crate::register::integral::RangeApplication;
use crate::register::state::{CpuState, TickState};
#[derive(Copy, Clone, Debug)]
pub struct CpuConfiguration {
pub frequency: usize,
}
impl CpuConfiguration {
pub const DEFAULT_FREQUENCY: usize = 64;
}
impl Default for CpuConfiguration {
fn default() -> Self {
CpuConfiguration {
frequency: Self::DEFAULT_FREQUENCY,
}
}
}
#[derive(Clone, Debug, Default)]
pub struct Cpu {
pub parent: Option<Rc<Cpu>>,
pub config: CpuConfiguration,
pub state: CpuState,
operations: Rc<OperationSet>,
ram: RefCell<Memory>,
}
impl Cpu {
pub fn new(memory: RefCell<Memory>, operation_set: Rc<OperationSet>) -> Self {
Self {
parent: None,
config: CpuConfiguration::default(),
state: CpuState::new(),
operations: operation_set,
ram: memory,
}
}
pub fn fork(self, fork_target: Address) -> (Self, Rc<Self>) {
let config = self.config;
let mut state = self.state.clone();
state.current = fork_target;
let operations = self.operations.clone();
let ram = self.memory();
let rc = Rc::from(self);
(Self {
parent: Some(rc.clone()),
config,
state,
operations,
ram,
}, rc)
}
pub fn debug(&self, label: &str, value: String, symbol: String) {
if self.state.flag_debug {
println!("\u{2ba1} {:15} {:} \x1b[1;38m{}\x1b[0m", label, symbol, value);
}
}
pub fn memory(&self) -> RefCell<Memory> { self.ram.clone() }
pub fn ram(&self) -> Ref<Memory> { self.ram.borrow() }
pub fn ram_mut(&self) -> RefMut<Memory> { self.ram.borrow_mut() }
pub fn stack_push(&mut self, word: Word) {
self.debug("push", format!("{:016x}", word.to_u64()), "🔽".to_string());
self.state.stack.produce(word);
}
pub fn stack_pop(&mut self) -> Option<Word> {
let pop = self.state.stack.consume();
self.debug("pop", match &pop {
None => "".to_string(),
Some(w) => format!("{:016x}", w.to_u64()),
}, "🔼".to_string());
pop
}
pub fn bank_get(&self, register_id: RegisterId) -> Word {
let v = self.state.bank.get(register_id);
self.debug(format!("get r{:04x}", register_id.to_u16()).as_str(), format!("{:016x}", v.to_u64()), "▶️".to_string());
v
}
pub fn bank_set(&mut self, register_id: RegisterId, word: Word) {
self.state.bank.set(register_id, word);
self.debug(format!("set r{:04x}", register_id.to_u16()).as_str(), format!("{:016x}", self.state.bank.get(register_id).to_u64()), "◀️".to_string());
}
pub fn bank_store(&mut self, register_id: RegisterId, address: Address) -> MemoryResult<()> {
let word = self.state.bank.get(register_id);
self.ram_mut().store(address, word)?;
self.debug("store", format!("{:016x} {:016x}", address.to_u64(), word.to_u64()), "⏬".to_string());
Ok(())
}
pub fn bank_load(&mut self, register_id: RegisterId, address: Address) -> MemoryResult<()> {
let word = self.ram().load(address)?;
self.state.bank.set(register_id, word);
self.debug("load", format!("{:016x} {:016x}", address.to_u64(), word.to_u64()), "⏫".to_string());
Ok(())
}
pub fn bank_apply(&mut self, target: RegisterId, range: RegisterRange, application: RangeApplication) {
self.debug("apply unsigned", format!("{:04x}:{:04x}", range.start.to_u16(), range.end.to_u16()), "⚙️".to_string());
self.state.operation.result = self.state.bank.apply(range, application);
self.bank_set(target, self.state.operation.result);
}
pub fn bank_push(&mut self, register_id: RegisterId) {
self.stack_push(self.bank_get(register_id));
}
pub fn bank_pop(&mut self, register_id: RegisterId) {
if self.state.stack.is_empty() { return; }
let popped = self.stack_pop().unwrap_or(self.state.bank.get(register_id));
self.bank_set(register_id, popped);
}
pub fn vector_get(&self, register_id: RegisterId) -> Number {
let v = self.state.vector.get(register_id);
self.debug(format!("get f{:04x}", register_id.to_u16()).as_str(), format!("{}", v.to_f64()), "▶️".to_string());
v
}
pub fn vector_set(&mut self, register_id: RegisterId, number: Number) {
self.state.vector.set(register_id, number);
self.debug(format!("set f{:04x}", register_id.to_u16()).as_str(), format!("{}", self.state.vector.get(register_id).to_f64()), "◀️".to_string());
}
pub fn vector_store(&mut self, register_id: RegisterId, address: Address) -> MemoryResult<()> {
let number = self.state.vector.get(register_id);
self.ram_mut().store(address, Word::new(number.to_u64()))?;
self.debug("store", format!("{:016x} {}", address.to_u64(), number.to_f64()), "⏬".to_string());
Ok(())
}
pub fn vector_load(&mut self, register_id: RegisterId, address: Address) -> MemoryResult<()> {
let number = self.ram().load(address)?;
let number = Number::from_u64(number.to_u64());
self.state.vector.set(register_id, number);
self.debug("load", format!("{:016x} {}", address.to_u64(), number.to_f64()), "⏬".to_string());
Ok(())
}
pub fn vector_apply(&mut self, target: RegisterId, range: RegisterRange, application: VectorApplication) {
self.debug("apply float", format!("{:04x}:{:04x}", range.start.to_u16(), range.end.to_u16()), "⚙️".to_string());
self.state.vector.set(target, self.state.vector.apply(range, application));
}
pub fn vector_push(&mut self, register_id: RegisterId) { self.stack_push(Word::new(self.vector_get(register_id).to_u64())); }
pub fn vector_pop(&mut self, register_id: RegisterId) {
if self.state.stack.is_empty() { return; }
let value = self.stack_pop()
.unwrap_or(Word::new(self.vector_get(register_id).to_u64())).to_u64();
self.vector_set(register_id, Number::from_u64(value))
}
pub fn next_instruction(&mut self) {
self.state.current.increment();
}
pub fn stack_size(&self) -> usize { self.state.stack.len() }
pub fn memory_size(&self) -> usize { self.ram().len() }
pub fn current_instruction(&self) -> Instruction { Instruction::new(self.ram().load(self.state.current).unwrap_or_default().to_u64()) }
pub fn point_instruction(&mut self, new_address: Address) -> MemoryResult<()> {
if new_address.to_usize() > self.memory_size() {
return Err(MemoryError::OutOfBounds { requested: new_address.to_usize(), memory_len: self.memory_size() });
}
self.state.current = new_address;
self.debug("point", format!("{:016x}", self.state.current.to_u64()), "📌".to_string());
Ok(())
}
pub fn decrease_loop_counter(&mut self) {
let counter = self.state.operation.counter.to_u64();
if counter > 0 {
self.state.operation.counter = Word::new(counter - 1);
self.debug("loop--", format!("{}", counter), "♾️".to_string());
} else {
self.debug("no loop", format!("{}", counter), "♾️".to_string());
}
}
pub fn halt(&mut self) {
self.debug("halt cpu", "".to_string(), "🛑".to_string());
self.state.flag_halt = true;
}
pub fn tick(&mut self) -> OperationResult<TickState> {
let instruction = self.current_instruction();
match operation::match_operation(&self.operations, instruction) {
None => Err(OperationError::MismatchedInstruction(instruction)),
Some(operation) => self.execute_or_skip(instruction, operation)
}
}
fn execute_or_skip(&mut self, instruction: Instruction, operation: Operation<()>) -> OperationResult<TickState> {
let scheme = instruction.operation_to_instruction(&operation);
if self.state.flag_skip {
self.state.flag_skip = false;
Ok(TickState::Skipped)
} else {
let old_current = self.state.current;
if self.state.flag_debug {
let [addr_top, addr_bottom] = Word::new(self.state.current.to_u64()).split();
print!("\x1b[37m{:08x}\x1b[0m{:08x}: ", addr_top.to_u32(), addr_bottom.to_u32());
operation.call_debug(self, scheme)?;
} else {
operation.call(self, scheme)?;
}
if self.state.current != old_current {
Ok(TickState::Jumped)
} else {
Ok(TickState::Executed)
}
}
}
pub fn next_instant(&self) -> Instant {
Instant::now().add(Duration::from_nanos(((1024 * 1024 * 1024) as f64 / self.config.frequency as f64) as u64))
}
pub fn advance(&mut self) {
let state = match self.tick() {
Ok(s) => s,
Err(err) => panic!("⚠️ \x1b[31mOperation error\x1b[0m : {:#?}", err)
};
if state != TickState::Jumped {
self.next_instruction();
}
}
pub fn until_halt(&mut self) {
loop {
self.advance();
if self.state.flag_halt {
break;
}
}
}
}