osiris-set-std 0.1.17

A standard operation set.
Documentation
//! This crate defines a **standard set** for a future **osiris-machine**.
//!
//! Each module has its own **operation prefix** which is one byte long.
//!
//! ## Operations
//! * `0x0000` noop
//!
//! ### Control
//! * `0x0101` [control::jump]:`address`
//! * `0x0102` [control::call]:`address`
//! * `0x0103` [control::call_return]
//! * `0x0104` [control::goto] `direct:32`
//! * `0x0105` [control::gosub] `direct:32`
//! * `0x0108` [control::loop_init]:`counter_init`
//! * `0x0109` [control::next] `direct:32`
//! * `0x010A` [control::goto_if]:`CMP` `direct:32`
//! * `0x010B` [control::gosub_if]:`CMP` `direct:32`
//! * `0x010C` [control::goto_check]:`checked` `direct:32`
//! * `0x010D` [control::gosub_check]:`checked` `direct:32`
//! * `0x010E` [control::skip_if]:`CMP`
//! * `0x010F` [control::skip_check]:`checked`
//! * `0x01FF` [control::halt]
//!
//! ### Registers control
//! * `0x0201` [registers::set_top]:target top:**32**
//! * `0x0202` [registers::set_bottom]:target bottom:**32**
//! * `0x0203` [registers::clear_range]
//! * `0x0204` [registers::move_to_float]:float unsigned:**16**
//! * `0x0205` [registers::move_from_float]:unsigned float:**16**
//! * `0x0210` [registers::push]:unsigned
//! * `0x0211` [registers::pop]:unsigned
//! * `0x0220` [registers::get_compare]:target
//!
//! ### Memory management
//! * `0x0301` [memory::store_words]:`target` `[start:end]`
//! * `0x0302` [memory::load_words]:`target` `[start:end]`
//! * `0x0303` [memory::get_memory_size]:`target`
//! * `0x0304` [memory::store_floats]:`target` `[start:end]`
//! * `0x0305` [memory::load_floats]:`target` `[start:end]`
//!
//! ### Logic operations
//! * `0x0400` [logic::is]:`CMP` `target:16`:`compare:16`
//! * `0x0401` [logic::not]:`target` 0:`origin:16`
//! * `0x0402` [logic::or]:`target` `[start:end]`
//! * `0x0403` [logic::and]:`target` `[start:end]`
//! * `0x0404` [logic::xor]:`target` `[start:end]`
//! * `0x0405` [logic::nor]:`target` `[start:end]`
//! * `0x0406` [logic::nand]:`target` `[start:end]`
//! * `0x0407` [logic::nxor]:`target` `[start:end]`
//!
//! ### Integral arithmetic
//! * `0x1001` [unsigned_arithmetic::sum_unsigned]:`target` `[start:end]`
//! * `0x1002` [unsigned_arithmetic::product_unsigned]:`target` `[start:end]`
//! * `0x1003` [unsigned_arithmetic::difference_unsigned]:`target` `[start:end]`
//! * `0x1004` [unsigned_arithmetic::quotient_unsigned]:`target` `[start:end]`
//! * `0x100F` [unsigned_arithmetic::compare_unsigned] `r1:r2`

use osiris_process::operation::{merge, Operation, OperationSet};
use osiris_process::operation::scheme::{ArgumentType, OperationId};

#[cfg(feature = "control")]
pub mod control;

#[cfg(feature = "registers")]
pub mod registers;

#[cfg(feature = "memory")]
pub mod memory;

#[cfg(feature = "logic")]
/// 0x04
pub mod logic;

pub mod range_applications;
#[cfg(feature = "unsigned")]
pub mod unsigned_arithmetic;

/// 0x11 Floating point arithmetic (+, -, /, *, rnd(), <=>)
#[cfg(feature = "floating-point")]
pub mod float_arithmetic {}

/// Returns the standard operation set.
///
/// ## Operations
/// * `0x0000` noop
/// * `0x0101` [control::jump]:`address`
/// * `0x0102` [control::call]:`address`
/// * `0x0103` return ([control::call_return])
/// * `0x0104` [control::goto] `direct:32`
/// * `0x0105` [control::gosub] `direct:32`
/// * `0x0108` loop:`counter_init` ([control::loop_init])
/// * `0x0109` [control::next] `direct:32`
/// * `0x010A` [control::goto_if]:`CMP` `direct:32`
/// * `0x010B` [control::gosub_if]:`CMP` `direct:32`
/// * `0x010C` [control::goto_check]:`checked` `direct:32`
/// * `0x010D` [control::gosub_check]:`checked` `direct:32`
/// * `0x010E` [control::skip_if]:`CMP`
/// * `0x010F` [control::skip_check]:`checked`
/// * `0x01FF` [control::halt]
///
///
/// * `0x0201` [registers::set_top]:target top:**32**
/// * `0x0202` [registers::set_bottom]:target bottom:**32**
/// * `0x0203` [registers::clear_range]
/// * `0x0204` [registers::move_to_float]:float unsigned:**16**
/// * `0x0205` [registers::move_from_float]:unsigned float:**16**
/// * `0x0210` [registers::push]:unsigned
/// * `0x0211` [registers::pop]:unsigned
/// * `0x0220` [registers::get_compare]:target
///
///
/// * `0x0301` [memory::store_words]:`target` `[start:end]`
/// * `0x0302` [memory::load_words]:`target` `[start:end]`
/// * `0x0303` [memory::get_memory_size]:`target`
/// * `0x0304` [memory::store_floats]:`target` `[start:end]`
/// * `0x0305` [memory::load_floats]:`target` `[start:end]`
///
///
/// * `0x0400` [logic::is]:`CMP` `target:16`:`compare:16`
/// * `0x0401` [logic::not]:`target` 0:`origin:16`
/// * `0x0402` [logic::or]:`target` `[start:end]`
/// * `0x0403` [logic::and]:`target` `[start:end]`
/// * `0x0404` [logic::xor]:`target` `[start:end]`
/// * `0x0405` [logic::nor]:`target` `[start:end]`
/// * `0x0406` [logic::nand]:`target` `[start:end]`
/// * `0x0407` [logic::nxor]:`target` `[start:end]`
///
///
/// * `0x1001` [unsigned_arithmetic::sum_unsigned]:`target` `[start:end]`
/// * `0x1002` [unsigned_arithmetic::product_unsigned]:`target` `[start:end]`
/// * `0x1003` [unsigned_arithmetic::difference_unsigned]:`target` `[start:end]`
/// * `0x1004` [unsigned_arithmetic::quotient_unsigned]:`target` `[start:end]`
/// * `0x100F` [unsigned_arithmetic::compare_unsigned] `r1:r2`
pub fn get_standard_set() -> OperationSet {
    merge(&[
        #[cfg(feature = "control")]
        control::operation_set(),
        #[cfg(feature = "registers")]
        registers::operation_set(),
        #[cfg(feature = "memory")]
        memory::operation_set(),
        #[cfg(feature = "logic")]
        logic::operation_set(),
        #[cfg(feature = "unsigned")]
        unsigned_arithmetic::operation_set(),
        OperationSet::from([
            (OperationId::new(0x0000), Operation::new(
                OperationId::new(0x0000),
                "noop".to_string(),
                false,
                ArgumentType::NoArgument,
                |_, _| Ok(()),
            ))
        ])
    ])
}

#[cfg(test)]
#[cfg(feature = "control")]
#[cfg(feature = "registers")]
#[cfg(feature = "unsigned")]
mod tests {
    use std::cell::RefCell;
    use std::rc::Rc;
    use osiris_data::data::atomic::Word;
    use osiris_data::data::composite::Array;
    use osiris_data::data::identification::Address;
    use osiris_data::memory::Memory;
    use osiris_process::processor::Cpu;
    use osiris_process::register::{RegisterBank, RegisterId};
    use crate::get_standard_set;

    mod instructions_tests;

    #[test]
    pub fn test_std() {
        let mut memory = Memory::with_size(1024);
        memory.copy(Address::new(0), Array::from(&[
            //                OPID TRGT ARG1 ARG2
            // 0x0000
            Word::new(0x0105_0000_0000_0003), // gosub 3
            // 0x0001
            Word::new(0x0211_0000_0000_0000), // pop:0
            // 0x0002
            Word::new(0x01FF_0000_0000_0000), // halt
            // 0x0003
            Word::new(0x0202_0000_0000_0000), // set-bottom:0 0
            // 0x0004
            Word::new(0x0202_0001_0000_0001), // set-bottom:1 1
            // 0x0005
            Word::new(0x0202_0002_0000_000A), // set-bottom:2 10
            // 0x0006
            Word::new(0x0108_0002_0000_0000), // for:2
            // 0x0007
            Word::new(0x1001_0000_0000_0001), // sum-unsigned:0 [0:1]
            // 0x0008
            Word::new(0x0109_0000_0000_0007), // next 7
            // 0x0009
            Word::new(0x0211_0004_0000_0000), // pop:4
            // 0x000A
            Word::new(0x0210_0000_0000_0000), // push:0
            // 0x000B
            Word::new(0x0210_0004_0000_0000), // push:4
            // 0x000C
            Word::new(0x0103_0000_0000_0000), // return
        ])).expect("");
        let mut cpu = Cpu::new(RefCell::new(memory), Rc::new(get_standard_set()));
        cpu.state.flag_debug = true;
        cpu.until_halt();
        assert_eq!(cpu.state.bank.get(RegisterId::new(0)).to_u64(), 10);
    }

}