osiris_set_std/
registers.rs

1//! 0x02 Register operations (set, move, stack)
2//! * `0x0201` [set_top]:target top:**32**
3//! * `0x0202` [set_bottom]:target bottom:**32**
4//! * `0x0203` [clear_range]
5//! * `0x0204` [move_to_float]:float unsigned:**16** 
6//! * `0x0205` [move_from_float]:unsigned float:**16**
7//! * `0x0210` [push]:unsigned
8//! * `0x0211` [pop]:unsigned
9//! * TODO 0x0212 PUSH RANGE
10//! * TODO 0x0213 POP RANGE
11//! * TODO 0x0220 REVERSE RANGE
12//! * TODO 0x0221 SWAP3 $start <$target> $end
13
14use std::collections::HashMap;
15use osiris_data::converters::Words;
16
17use osiris_data::data::atomic::{HalfWord, Word};
18use osiris_process::operation::error::{OperationError, OperationResult};
19use osiris_process::operation::{Operation, OperationSet};
20use osiris_process::operation::scheme::{ArgumentType, InstructionScheme, OperationId};
21use osiris_process::processor::Cpu;
22use osiris_process::register::floating_point::Number;
23use osiris_process::register::RegisterId;
24
25pub const SET_MASK: u16 = 0x0200;
26pub const SET_TOP: OperationId = OperationId::new(SET_MASK | 0x01);
27pub const SET_BOTTOM: OperationId = OperationId::new(SET_MASK | 0x02);
28pub const CLEAR_RANGE: OperationId = OperationId::new(SET_MASK | 0x03);
29pub const MOVE_TO_FLOAT: OperationId = OperationId::new(SET_MASK | 0x04);
30pub const MOVE_FROM_FLOAT: OperationId = OperationId::new(SET_MASK | 0x05);
31pub const PUSH: OperationId = OperationId::new(SET_MASK | 0x10);
32pub const POP: OperationId = OperationId::new(SET_MASK | 0x11);
33pub const GET_COMPARE: OperationId = OperationId::new(SET_MASK | 0x20);
34
35/// # `0x0201` [set_top]:target top:**32**
36///
37/// ## Target
38///  - The register to set
39///
40/// ## Arguments
41///  - top
42///
43/// ## Operation
44///  - `r:target.top = top`
45///
46/// ## Errors
47///  - [OperationError::InvalidArgumentType] if the provided argument is not an [ArgumentType::OneU32],
48pub fn set_top(cpu: &mut Cpu, scheme: InstructionScheme) -> OperationResult<()> {
49    let value = scheme.argument.get_one_u32()?;
50    let bottom = cpu.bank_get(scheme.target).bottom();
51    cpu.debug("merge", format!("{:08x}:{:08x}", value, bottom.to_u32()), "⚙️".to_string());
52    cpu.bank_set(scheme.target, Word::merge(HalfWord::new(value), bottom));
53    Ok(())
54}
55
56/// # `0x0202` [set_bottom]:target bottom:**32**
57///
58/// ## Target
59///  - The register to set
60///
61/// ## Arguments
62///  - 32 bits : the bottom of the 64 bits value
63///
64/// ## Operation
65///  - sets `REG[$target].bottom = $argument`
66///
67/// ## Errors
68///  - [OperationError::InvalidArgumentType] if the provided argument is not an [ArgumentType::OneU32],
69pub fn set_bottom(cpu: &mut Cpu, scheme: InstructionScheme) -> OperationResult<()> {
70    let value = scheme.argument.get_one_u32()?;
71    let top = cpu.bank_get(scheme.target).top();
72    cpu.debug("merge", format!("{:08x}:{:08x}", top.to_u32(), value), "⚙️".to_string());
73    cpu.bank_set(scheme.target, Word::merge(top, HalfWord::new(value)));
74    Ok(())
75}
76
77/// `0x0203` [clear_range]
78///
79/// ## Target
80///  - No target
81///
82/// ## Arguments
83///  - Range($start, $end)
84///
85/// ## Operation
86///  - sets `REG[$start..=$end] = 0`
87///
88/// ## Errors
89///  - [OperationError::InvalidArgumentType] if the provided argument is not an [ArgumentType::Range],
90pub fn clear_range(cpu: &mut Cpu, scheme: InstructionScheme) -> OperationResult<()> {
91    for id in scheme.argument.get_range()?.to_usize_range() {
92        let rid = RegisterId::new(id as u16);
93        cpu.bank_set(rid, Word::default());
94    }
95    Ok(())
96}
97
98/// # `0x0204` [move_to_float]:float unsigned:**16** 
99///
100/// ## Target
101///  - The vector RegisterId to write to.
102///
103/// ## Arguments
104///  - 16 bits : nothing,
105///  - 16 bits : the bank RegisterId to read from.
106///
107/// ## Operation
108///  - sets `FLOAT[$target] = REG[$argument]`
109///
110/// ## Errors
111///  - [OperationError::InvalidArgumentType] if the provided argument is not an [ArgumentType::TwoU16],
112pub fn move_to_float(cpu: &mut Cpu, scheme: InstructionScheme) -> OperationResult<()> {
113    let (_, bank_id) = scheme.argument.get_two_u16()?;
114    let word = cpu.bank_get(RegisterId::new(bank_id));
115    cpu.vector_set(scheme.target, Number::from_word(word));
116    Ok(())
117}
118
119/// # `0x0205` [move_from_float]:unsigned float:**16**
120///
121/// ## Target
122///  - The bank RegisterId to write to.
123///
124/// ## Arguments
125///  - 16 bits : nothing,
126///  - 16 bits : the vector RegisterId to read from.
127///
128/// ## Operation
129///  - sets `REG[$target] = FLOAT[$argument]`
130///
131/// ## Errors
132///  - [OperationError::InvalidArgumentType] if the provided argument is not an [ArgumentType::TwoU16],
133pub fn move_from_float(cpu: &mut Cpu, scheme: InstructionScheme) -> OperationResult<()> {
134    let (_, bank_id) = scheme.argument.get_two_u16()?;
135    let number = cpu.vector_get(RegisterId::new(bank_id));
136    cpu.bank_set(scheme.target, number.to_word());
137    Ok(())
138}
139
140/// # `0x0210` [push]:unsigned
141///
142/// ## Target
143///  - The bank register to read the value to push into the stack.
144///
145/// ## Arguments
146/// - None
147///
148/// ## Operation
149///  - push `REG[$target]` into the stack
150///
151/// ## Errors
152///  - [OperationError::InvalidArgumentType] if the provided argument is not an [ArgumentType::NoArgument],
153pub fn push(cpu: &mut Cpu, scheme: InstructionScheme) -> OperationResult<()> {
154    scheme.argument.get_no_argument()?;
155    cpu.bank_push(scheme.target);
156    Ok(())
157}
158
159/// # `0x0211` [pop]:unsigned
160///
161/// ## Target
162///  - The bank register to write the value to pop from the stack.
163///
164/// ## Arguments
165/// - None
166///
167/// ## Operation
168///  - pop a value from the stack and put it into `REG[$target]`.
169///
170/// ## Errors
171///  - [OperationError::InvalidArgumentType] if the provided argument is not an [ArgumentType::NoArgument],
172pub fn pop(cpu: &mut Cpu, scheme: InstructionScheme) -> OperationResult<()> {
173    scheme.argument.get_no_argument()?;
174    cpu.bank_pop(scheme.target);
175    Ok(())
176}
177
178/// # `0x0220` [get_compare]:target
179///
180/// ## Target
181///  - The bank register to write the value of the compare register.
182///
183/// ## Arguments
184/// - None
185///
186/// ## Operation
187///  - `REG[$target] = CMP`
188///
189/// ## Errors
190///  - [OperationError::InvalidArgumentType] if the provided argument is not an [ArgumentType::NoArgument],
191pub fn get_compare(cpu: &mut Cpu, scheme: InstructionScheme) -> OperationResult<()> {
192    scheme.argument.get_no_argument()?;
193    cpu.bank_set(scheme.target, Words::from_i64(cpu.state.operation.compare));
194    Ok(())
195}
196
197/// Returns register operations.
198///
199/// ## Operations
200///
201/// * `0x0201` [set_top]:target top:**32**
202/// * `0x0202` [set_bottom]:target bottom:**32**
203/// * `0x0203` [clear_range]
204/// * `0x0204` [move_to_float]:float unsigned:**16** 
205/// * `0x0205` [move_from_float]:unsigned float:**16**
206/// * `0x0210` [push]:unsigned
207/// * `0x0211` [pop]:unsigned
208/// * `0x0220` [get_compare]:target
209pub fn operation_set() -> OperationSet {
210    let mut set: OperationSet = HashMap::new();
211    set.insert(SET_TOP, Operation::new(SET_TOP, "set-top".to_string(), true, ArgumentType::OneU32, set_top));
212    set.insert(SET_BOTTOM, Operation::new(SET_BOTTOM, "set-bottom".to_string(), true, ArgumentType::OneU32, set_bottom));
213    set.insert(CLEAR_RANGE, Operation::new(CLEAR_RANGE, "clear-range".to_string(), false, ArgumentType::Range, clear_range));
214    set.insert(MOVE_TO_FLOAT, Operation::new(MOVE_TO_FLOAT, "move-to-float".to_string(), true, ArgumentType::TwoU16, move_to_float));
215    set.insert(MOVE_FROM_FLOAT, Operation::new(MOVE_FROM_FLOAT, "move-from-float".to_string(), true, ArgumentType::TwoU16, move_from_float));
216    set.insert(PUSH, Operation::new(PUSH, "push".to_string(), true, ArgumentType::NoArgument, push));
217    set.insert(POP, Operation::new(POP, "pop".to_string(), true, ArgumentType::NoArgument, pop));
218    set.insert(GET_COMPARE, Operation::new(GET_COMPARE, "get-compare".to_string(), true, ArgumentType::NoArgument, get_compare));
219    set
220}