osiris-process 0.3.1

A processor implementation.
Documentation
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::communication::MessageQueue;

use crate::operation;
use crate::operation::{Instruction, Operation, OperationSet};
use crate::operation::error::{OperationError, OperationResult};
use crate::register::{RegisterBank, RegisterId, RegisterRange};
use crate::register::floating_point::{Number, VectorApplication};
use crate::register::integral::BankApplication;
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 {
    /// See : [CpuConfiguration::DEFAULT_FREQUENCY]
    fn default() -> Self {
        CpuConfiguration {
            frequency: Self::DEFAULT_FREQUENCY,
        }
    }
}

/// Cpu is a facade to a virtual processor : register control and instructions_sets, and memory.
#[derive(Clone, Debug, Default)]
pub struct Cpu {
    pub parent: Option<Rc<Cpu>>,
    pub config: CpuConfiguration,
    pub state: CpuState,
    pub output: MessageQueue,
    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(),
            output: MessageQueue::default(),
            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,
            output: MessageQueue::default(),
            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);
        }
    }

    // ///////////////////////////////////////////////////////////////////////////////////////////// Memory references

    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() }

    // ///////////////////////////////////////////////////////////////////////////////////////////// Operations

    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: BankApplication) {
        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;
    }

    // ///////////////////////////////////////////////////////////////////////////////////////////// Operation execution utilities

    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 {
        // `::from_nanos` is used for precision. Maximum frequency of the Cpu should be far inferior.
        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;
            }
        }
    }

}