osiris_set_std/
unsigned_arithmetic.rs

1//! 0x10 Integral arithmetic (+, -, /, *, rnd(), <=>)
2//! * `0x1001` [sum_unsigned]:`target` `[start:end]`
3//! * `0x1002` [product_unsigned]:`target` `[start:end]`
4//! * `0x1003` [difference_unsigned]:`target` `[start:end]`
5//! * `0x1004` [quotient_unsigned]:`target` `[start:end]`
6//! * TODO ... RANDOM
7//! * `0x100F` [compare_unsigned] `r1:r2`
8
9use std::collections::HashMap;
10
11use osiris_process::compare::Compare;
12use osiris_process::operation::error::{OperationError, OperationResult};
13use osiris_process::operation::{Operation, OperationSet};
14use osiris_process::operation::scheme::{ArgumentType, InstructionScheme, OperationId};
15use osiris_process::processor::Cpu;
16use osiris_process::register::{RegisterBank, RegisterId};
17
18use crate::range_applications::unsigned;
19
20pub const SET_MASK: u16 = 0x1000;
21
22pub const SUM_UNSIGNED: OperationId = OperationId::new(SET_MASK | 0x01);
23pub const PRODUCT_UNSIGNED: OperationId = OperationId::new(SET_MASK | 0x02);
24pub const DIFFERENCE_UNSIGNED: OperationId = OperationId::new(SET_MASK | 0x03);
25pub const QUOTIENT_UNSIGNED: OperationId = OperationId::new(SET_MASK | 0x04);
26pub const COMPARE_UNSIGNED: OperationId = OperationId::new(SET_MASK | 0x0F);
27
28/// # `0x1001` [sum_unsigned]:`target` `[start:end]`
29///
30/// ## Target
31///  - The register to store the result into
32///
33/// ## Arguments
34///  - Range : the range to sum
35///
36/// ## Operation
37///  - `REG[$target] = sum(REG[$start..=$end])`
38///
39/// ## Errors
40///  - [OperationError::InvalidArgumentType] if the provided argument is not an [ArgumentType::Range]
41pub fn sum_unsigned(cpu: &mut Cpu, scheme: InstructionScheme) -> OperationResult<()> {
42    cpu.bank_apply(scheme.target, scheme.argument.get_range()?, unsigned::sum);
43    Ok(())
44}
45
46/// # `0x1002` [product_unsigned]:`target` `[start:end]`
47///
48/// ## Target
49///  - The register to store the result into
50///
51/// ## Arguments
52///  - Range : the range to product
53///
54/// ## Operation
55///  - `REG[$target] = product(REG[$start..=$end])`
56///
57/// ## Errors
58///  - [OperationError::InvalidArgumentType] if the provided argument is not an [ArgumentType::Range]
59pub fn product_unsigned(cpu: &mut Cpu, scheme: InstructionScheme) -> OperationResult<()> {
60    cpu.bank_apply(scheme.target, scheme.argument.get_range()?, unsigned::product);
61    Ok(())
62}
63
64/// # `0x1003` [difference_unsigned]:`target` `[start:end]`
65///
66/// ## Target
67///  - The register to store the result into
68///
69/// ## Arguments
70///  - Range : the range to sum
71///
72/// ## Operation
73///  - `REG[$target] = difference(REG[$start..=$end])`
74///
75/// ## Errors
76///  - [OperationError::InvalidArgumentType] if the provided argument is not an [ArgumentType::Range]
77pub fn difference_unsigned(cpu: &mut Cpu, scheme: InstructionScheme) -> OperationResult<()> {
78    cpu.bank_apply(scheme.target, scheme.argument.get_range()?, unsigned::difference);
79    Ok(())
80}
81
82/// # `0x1004` [quotient_unsigned]:`target` `[start:end]`
83///
84/// ## Target
85///  - The register to store the result into
86///
87/// ## Arguments
88///  - Range : the range to product
89///
90/// ## Operation
91///  - `REG[$target] = quotient(REG[$start..=$end])`
92///
93/// ## Errors
94///  - [OperationError::InvalidArgumentType] if the provided argument is not an [ArgumentType::Range]
95pub fn quotient_unsigned(cpu: &mut Cpu, scheme: InstructionScheme) -> OperationResult<()> {
96    cpu.bank_apply(scheme.target, scheme.argument.get_range()?, unsigned::quotient);
97    Ok(())
98}
99
100/// # `0x100F` [compare_unsigned] `r1:r2`
101/// 
102/// ## Target
103///  - None
104///
105/// ## Arguments
106///  - Two registers ids.
107///
108/// ## Operation
109///  - `REG[r1] <=> REG[r2]`
110///
111/// ## Errors
112///  - [OperationError::InvalidArgumentType] if the provided argument is not an [ArgumentType::TwoU16]
113pub fn compare_unsigned(cpu: &mut Cpu, scheme: InstructionScheme) -> OperationResult<()> {
114    let (a, b) = scheme.argument.get_two_u16()?;
115    let a_val = cpu.state.bank.get(RegisterId::new(a));
116    let b_val = cpu.state.bank.get(RegisterId::new(b));
117    cpu.state.operation.compare = Compare::cmp(a_val, b_val);
118    cpu.debug("compare", cpu.state.operation.compare.to_string(), "=".to_string());
119    Ok(())
120}
121
122/// Returns integral arithmetic operations.
123///
124/// ## Operations
125/// 
126/// * `0x1001` [sum_unsigned]:`target` `[start:end]`
127/// * `0x1002` [product_unsigned]:`target` `[start:end]`
128/// * `0x1003` [difference_unsigned]:`target` `[start:end]`
129/// * `0x1004` [quotient_unsigned]:`target` `[start:end]`
130/// * `0x100F` [compare_unsigned] `r1:r2`
131pub fn operation_set() -> OperationSet {
132    let mut set: OperationSet = HashMap::new();
133    set.insert(
134        SUM_UNSIGNED,
135        Operation::new(SUM_UNSIGNED, "sum-unsigned".to_string(), true, ArgumentType::Range, sum_unsigned),
136    );
137    set.insert(
138        PRODUCT_UNSIGNED,
139        Operation::new(PRODUCT_UNSIGNED, "product-unsigned".to_string(), true, ArgumentType::Range, product_unsigned),
140    );
141    set.insert(
142        DIFFERENCE_UNSIGNED,
143        Operation::new(DIFFERENCE_UNSIGNED, "difference-unsigned".to_string(), true, ArgumentType::Range, difference_unsigned),
144    );
145    set.insert(
146        QUOTIENT_UNSIGNED,
147        Operation::new(QUOTIENT_UNSIGNED, "quotient-unsigned".to_string(), true, ArgumentType::Range, quotient_unsigned),
148    );
149    set.insert(
150        COMPARE_UNSIGNED,
151        Operation::new(COMPARE_UNSIGNED, "compare-unsigned".to_string(), false, ArgumentType::TwoU16, compare_unsigned),
152    );
153    set
154}