use std::collections::HashMap;
use osiris_data::converters::Words;
use osiris_data::data::atomic::{HalfWord, Word};
use osiris_process::operation::error::{OperationError, OperationResult};
use osiris_process::operation::{Operation, OperationSet};
use osiris_process::operation::scheme::{ArgumentType, InstructionScheme, OperationId};
use osiris_process::processor::Cpu;
use osiris_process::register::floating_point::Number;
use osiris_process::register::RegisterId;
pub const SET_MASK: u16 = 0x0200;
pub const SET_TOP: OperationId = OperationId::new(SET_MASK | 0x01);
pub const SET_BOTTOM: OperationId = OperationId::new(SET_MASK | 0x02);
pub const CLEAR_RANGE: OperationId = OperationId::new(SET_MASK | 0x03);
pub const MOVE_TO_FLOAT: OperationId = OperationId::new(SET_MASK | 0x04);
pub const MOVE_FROM_FLOAT: OperationId = OperationId::new(SET_MASK | 0x05);
pub const PUSH: OperationId = OperationId::new(SET_MASK | 0x10);
pub const POP: OperationId = OperationId::new(SET_MASK | 0x11);
pub const GET_COMPARE: OperationId = OperationId::new(SET_MASK | 0x20);
pub fn set_top(cpu: &mut Cpu, scheme: InstructionScheme) -> OperationResult<()> {
let value = scheme.argument.get_one_u32()?;
let bottom = cpu.bank_get(scheme.target).bottom();
cpu.debug("merge", format!("{:08x}:{:08x}", value, bottom.to_u32()), "⚙️".to_string());
cpu.bank_set(scheme.target, Word::merge(HalfWord::new(value), bottom));
Ok(())
}
pub fn set_bottom(cpu: &mut Cpu, scheme: InstructionScheme) -> OperationResult<()> {
let value = scheme.argument.get_one_u32()?;
let top = cpu.bank_get(scheme.target).top();
cpu.debug("merge", format!("{:08x}:{:08x}", top.to_u32(), value), "⚙️".to_string());
cpu.bank_set(scheme.target, Word::merge(top, HalfWord::new(value)));
Ok(())
}
pub fn clear_range(cpu: &mut Cpu, scheme: InstructionScheme) -> OperationResult<()> {
for id in scheme.argument.get_range()?.to_usize_range() {
let rid = RegisterId::new(id as u16);
cpu.bank_set(rid, Word::default());
}
Ok(())
}
pub fn move_to_float(cpu: &mut Cpu, scheme: InstructionScheme) -> OperationResult<()> {
let (_, bank_id) = scheme.argument.get_two_u16()?;
let word = cpu.bank_get(RegisterId::new(bank_id));
cpu.vector_set(scheme.target, Number::from_word(word));
Ok(())
}
pub fn move_from_float(cpu: &mut Cpu, scheme: InstructionScheme) -> OperationResult<()> {
let (_, bank_id) = scheme.argument.get_two_u16()?;
let number = cpu.vector_get(RegisterId::new(bank_id));
cpu.bank_set(scheme.target, number.to_word());
Ok(())
}
pub fn push(cpu: &mut Cpu, scheme: InstructionScheme) -> OperationResult<()> {
scheme.argument.get_no_argument()?;
cpu.bank_push(scheme.target);
Ok(())
}
pub fn pop(cpu: &mut Cpu, scheme: InstructionScheme) -> OperationResult<()> {
scheme.argument.get_no_argument()?;
cpu.bank_pop(scheme.target);
Ok(())
}
pub fn get_compare(cpu: &mut Cpu, scheme: InstructionScheme) -> OperationResult<()> {
scheme.argument.get_no_argument()?;
cpu.bank_set(scheme.target, Words::from_i64(cpu.state.operation.compare));
Ok(())
}
pub fn operation_set() -> OperationSet {
let mut set: OperationSet = HashMap::new();
set.insert(SET_TOP, Operation::new(SET_TOP, "set-top".to_string(), true, ArgumentType::OneU32, set_top));
set.insert(SET_BOTTOM, Operation::new(SET_BOTTOM, "set-bottom".to_string(), true, ArgumentType::OneU32, set_bottom));
set.insert(CLEAR_RANGE, Operation::new(CLEAR_RANGE, "clear-range".to_string(), false, ArgumentType::Range, clear_range));
set.insert(MOVE_TO_FLOAT, Operation::new(MOVE_TO_FLOAT, "move-to-float".to_string(), true, ArgumentType::TwoU16, move_to_float));
set.insert(MOVE_FROM_FLOAT, Operation::new(MOVE_FROM_FLOAT, "move-from-float".to_string(), true, ArgumentType::TwoU16, move_from_float));
set.insert(PUSH, Operation::new(PUSH, "push".to_string(), true, ArgumentType::NoArgument, push));
set.insert(POP, Operation::new(POP, "pop".to_string(), true, ArgumentType::NoArgument, pop));
set.insert(GET_COMPARE, Operation::new(GET_COMPARE, "get-compare".to_string(), true, ArgumentType::NoArgument, get_compare));
set
}