Browse Source

basic float arith, wip float trig, abs

Ondřej Hruška 11 months ago
parent
commit
68c9b33637
Signed by: Ondřej Hruška <ondra@ondrovo.com> GPG key ID: 2C5FD5035250423D

+ 1 - 1
crsn/src/asm/data/literal.rs View File

@@ -9,7 +9,7 @@ pub type Value = u64;
9 9
 
10 10
 #[inline(always)]
11 11
 pub const fn is_positive(val: Value) -> bool {
12
-    0 == (val & 0x8000_0000_0000_0000)
12
+    0 == (val & 0x8000_0000_0000_0000) && val != 0
13 13
 }
14 14
 
15 15
 #[inline(always)]

+ 19 - 2
crsn/src/asm/data/rd.rs View File

@@ -14,11 +14,28 @@ impl Rd {
14 14
     pub const fn new(src: RdData) -> Self {
15 15
         Rd(src)
16 16
     }
17
-    pub const fn immediate(val: Value) -> Rd {
17
+
18
+    pub const fn new_imm(val: Value) -> Rd {
18 19
         Rd(RdData::Immediate(val))
19 20
     }
20 21
 
21
-    pub fn is_immediate_equal(self, other: Value) -> bool {
22
+    /// Construct new from float
23
+    pub fn new_float(val: f64) -> Rd { // TODO const when stabilized
24
+        Rd(RdData::Immediate(val.to_bits()))
25
+    }
26
+
27
+    /// Convert immediate read to float
28
+    pub fn imm_to_float(self) -> Rd {
29
+        match self {
30
+            Rd(RdData::Immediate(v)) => {
31
+                let signed : i64 = unsafe { std::mem::transmute(v) };
32
+                Rd::new_float(signed as f64)
33
+            }
34
+            other => other
35
+        }
36
+    }
37
+
38
+    pub fn is_imm_equal(self, other: Value) -> bool {
22 39
         match self.0 {
23 40
             RdData::Immediate(val) => {
24 41
                 val == other

+ 1 - 1
crsn/src/asm/parse/arg_parser.rs View File

@@ -291,7 +291,7 @@ impl<'a> TokenParser<'a> {
291 291
     pub fn parse_wr_rd_rd_or_n(&mut self, n : Value) -> Result<(Wr, Rd, Rd), CrsnError> {
292 292
         if self.len() == 1 {
293 293
             let rw = self.next_rdwr()?;
294
-            Ok((rw.wr(), rw.rd(), Rd::immediate(n)))
294
+            Ok((rw.wr(), rw.rd(), Rd::new_imm(n)))
295 295
         } else if self.len() == 2 {
296 296
             let rw = self.next_rdwr()?;
297 297
             let rd = self.next_rd()?;

+ 7 - 0
crsn/src/runtime/frame/status.rs View File

@@ -79,6 +79,13 @@ impl StatusFlags {
79 79
     }
80 80
 
81 81
     #[inline(always)]
82
+    pub fn update_float(&mut self, val: f64) {
83
+        self.zero = val == 0.0;
84
+        self.positive = val > 0.0;
85
+        self.negative = val < 0.0;
86
+    }
87
+
88
+    #[inline(always)]
82 89
     pub fn test(&self, cond: Cond) -> bool {
83 90
         match cond {
84 91
             Cond::Equal => self.equal,

+ 7 - 0
crsn/src/runtime/run_thread/state.rs View File

@@ -102,6 +102,13 @@ impl RunState {
102 102
         self.frame.status.update(val);
103 103
     }
104 104
 
105
+    /// Update status flags using a variable.
106
+    /// The update is additive - call `clear_status()` first if desired!
107
+    #[inline(always)]
108
+    pub fn update_status_float(&mut self, val: f64) {
109
+        self.frame.status.update_float(val);
110
+    }
111
+
105 112
     /// Read object handle value
106 113
     pub fn read_obj(&mut self, rdo: impl Into<RdObj>) -> Result<Value, Fault> {
107 114
         rdo.into().read(self)

+ 40 - 14
crsn_arith/src/defs.rs View File

@@ -27,8 +27,10 @@ pub enum ArithOp {
27 27
     SignExtend { dst: Wr, src: Rd, mask: BitMask },
28 28
 
29 29
     Add { dst: Wr, a: Rd, b: Rd },
30
+    Abs { dst: Wr, a: Rd },
30 31
     Sub { dst: Wr, a: Rd, b: Rd },
31 32
     Mul { dst: Wr, a: Rd, b: Rd },
33
+    Pow { dst: Wr, a: Rd, pow: Rd },
32 34
     Div { dst: Wr, rem: Wr, a: Rd, div: Rd },
33 35
     // "Mod" is functionally equivalent to "Div" with the result discarded,
34 36
     // but status flags are updated by the remainder
@@ -46,18 +48,42 @@ pub enum ArithOp {
46 48
     Lsr { dst: Wr, a: Rd, n: Rd },
47 49
     Asr { dst: Wr, a: Rd, n: Rd },
48 50
 
49
-    // IntToFloat { dst: Wr, a: Rd },
50
-    // FloatToInt { dst: Wr, a: Rd },
51
-    // FloatTest { a: Rd },
52
-    // FloatCompare { a: Rd, b: Rd },
53
-    // FloatRangeTest { val: Rd, a: Rd, b: Rd },
54
-    // FloatRng { dst: Wr, min: Rd, max: Rd },
55
-    // FloatRound { dst: Wr, a: Rd, b: Rd },
56
-    // FloatCeil { dst: Wr, a: Rd, b: Rd },
57
-    // FloatFloor { dst: Wr, a: Rd, b: Rd },
58
-    // FloatAdd { dst: Wr, a: Rd, b: Rd },
59
-    // FloatSub { dst: Wr, a: Rd, b: Rd },
60
-    // FloatMul { dst: Wr, a: Rd, b: Rd },
61
-    // FloatDiv { dst: Wr, rem: Wr, a: Rd, div: Rd },
62
-    // FloatMod { dst: Wr, a: Rd, div: Rd },
51
+    IntToFloat { dst: Wr, a: Rd },
52
+    FloatToInt { dst: Wr, a: Rd, mode: FloatToIntMode },
53
+    FloatTest { a: Rd },
54
+    FloatCompare { a: Rd, b: Rd },
55
+    FloatRangeTest { val: Rd, a: Rd, b: Rd },
56
+    FloatRng { dst: Wr, min: Rd, max: Rd },
57
+    FloatAdd { dst: Wr, a: Rd, b: Rd },
58
+    FloatSub { dst: Wr, a: Rd, b: Rd },
59
+    FloatMul { dst: Wr, a: Rd, b: Rd },
60
+    FloatPow { dst: Wr, a: Rd, pow: Rd },
61
+    FloatRoot { dst: Wr, a: Rd, root: Rd },
62
+    FloatHyp { dst: Wr, a: Rd, b: Rd },
63
+    FloatDiv { dst: Wr, rem: Wr, a: Rd, div: Rd },
64
+    FloatMod { dst: Wr, a: Rd, div: Rd },
65
+    FloatAbs { dst: Wr, a: Rd },
66
+
67
+    FloatSin { dst: Wr, f: Rd },
68
+    FloatAsin { dst: Wr, a: Rd },
69
+    FloatCos { dst: Wr, f: Rd },
70
+    FloatAcos { dst: Wr, a: Rd },
71
+    FloatTan { dst: Wr, f: Rd },
72
+    FloatAtan { dst: Wr, a: Rd },
73
+    FloatAtan2 { dst: Wr, y: Rd, x: Rd },
74
+    FloatCot { dst: Wr, f: Rd },
75
+    FloatAcot { dst: Wr, a: Rd },
76
+}
77
+
78
+#[derive(Debug, Clone, Copy, Eq, PartialEq)]
79
+pub enum FloatToIntMode {
80
+    Floor,
81
+    Ceil,
82
+    Round,
83
+}
84
+
85
+impl Default for FloatToIntMode {
86
+    fn default() -> Self {
87
+        Self::Round
88
+    }
63 89
 }

+ 180 - 5
crsn_arith/src/exec.rs View File

@@ -10,14 +10,35 @@ use crsn::sexp;
10 10
 use crsn::sexp::Sexp;
11 11
 use crsn::utils::A;
12 12
 
13
-use crate::defs::ArithOp;
13
+use crate::defs::{ArithOp, FloatToIntMode};
14 14
 use crsn::asm::instr::cond::Flag;
15 15
 use rand::Rng;
16 16
 
17
+#[inline]
18
+fn f2u(f: f64) -> u64 {
19
+    unsafe { std::mem::transmute(f) }
20
+}
21
+
22
+#[inline]
23
+fn u2f(f: u64) -> f64 {
24
+    unsafe { std::mem::transmute(f) }
25
+}
26
+
27
+#[inline]
28
+fn i2u(f: i64) -> u64 {
29
+    unsafe { std::mem::transmute(f) }
30
+}
31
+
32
+#[inline]
33
+fn u2i(f: u64) -> i64 {
34
+    unsafe { std::mem::transmute(f) }
35
+}
36
+
17 37
 impl OpTrait for ArithOp {
18 38
     fn execute(&self, _ti: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault> {
19 39
         let eres = EvalRes::default();
20 40
         match self {
41
+            // Integers
21 42
             ArithOp::Test { a } => {
22 43
                 state.clear_status();
23 44
                 let res = state.read(a)?;
@@ -142,6 +163,122 @@ impl OpTrait for ArithOp {
142 163
                     state.write(dst, remainder)?;
143 164
                 }
144 165
             }
166
+
167
+            // Floating point
168
+
169
+            ArithOp::FloatToInt { dst, a, mode } => {
170
+                state.clear_status();
171
+                let val : f64 = u2f(state.read(a)?);
172
+                let res = i2u(match mode {
173
+                    FloatToIntMode::Floor => val.floor(),
174
+                    FloatToIntMode::Ceil => val.ceil(),
175
+                    FloatToIntMode::Round => val.round(),
176
+                } as i64);
177
+                state.update_status(res);
178
+                state.write(dst, res)?;
179
+            }
180
+            ArithOp::IntToFloat { dst, a } => {
181
+                state.clear_status();
182
+                let val : f64 = u2i(state.read(a)?) as f64;
183
+                state.update_status_float(val);
184
+                state.write(dst, f2u(val))?;
185
+            }
186
+            ArithOp::FloatTest { a } => {
187
+                state.clear_status();
188
+                let res = u2f(state.read(a)?);
189
+                state.update_status_float(res);
190
+            }
191
+            ArithOp::FloatCompare { a, b } => {
192
+                state.clear_status();
193
+                let x = u2f(state.read(a)?);
194
+                let y = u2f(state.read(b)?);
195
+                state.set_flag(Flag::Equal, x == y);
196
+                state.set_flag(Flag::Lower, x < y);
197
+                state.set_flag(Flag::Greater, x > y);
198
+                // Test flags are set when both arguments have the property
199
+                if x == y {
200
+                    state.update_status_float(x);
201
+                }
202
+            }
203
+            ArithOp::FloatRangeTest { val, a, b } => {
204
+                state.clear_status();
205
+                let val = u2f(state.read(val)?);
206
+                let a = u2f(state.read(a)?);
207
+                let b = u2f(state.read(b)?);
208
+                state.set_flag(Flag::Equal, val >= a && val <= b);
209
+                state.set_flag(Flag::Lower, val < a);
210
+                state.set_flag(Flag::Greater, val > b);
211
+                state.update_status_float(val);
212
+            }
213
+            ArithOp::FloatRng { dst, min, max } => {
214
+                state.clear_status();
215
+                let min = u2f(state.read(min)?);
216
+                let max = u2f(state.read(max)?);
217
+
218
+                let val = if min == max {
219
+                    min
220
+                } else if min > max {
221
+                    state.set_flag(Flag::Invalid, true);
222
+                    min
223
+                } else {
224
+                    rand::thread_rng()
225
+                        .gen_range(min, max)
226
+                };
227
+                state.write(dst, f2u(val))?;
228
+                state.update_status_float(val);
229
+            }
230
+            ArithOp::FloatAdd { dst, a, b } => {
231
+                state.clear_status();
232
+                let x = u2f(state.read(a)?);
233
+                let y = u2f(state.read(b)?);
234
+                let res = x + y;
235
+                state.update_status_float(res);
236
+                state.write(dst, f2u(res))?;
237
+            }
238
+            ArithOp::FloatSub { dst, a, b } => {
239
+                state.clear_status();
240
+                let x = u2f(state.read(a)?);
241
+                let y = u2f(state.read(b)?);
242
+                let res = x - y;
243
+                state.update_status_float(res);
244
+                state.write(dst, f2u(res))?;
245
+            }
246
+            ArithOp::FloatMul { dst, a, b } => {
247
+                state.clear_status();
248
+                let x = u2f(state.read(a)?);
249
+                let y = u2f(state.read(b)?);
250
+                let res = x * y;
251
+                state.update_status_float(res);
252
+                state.write(dst, f2u(res))?;
253
+            }
254
+            ArithOp::FloatDiv { dst, rem, a, div } => {
255
+                state.clear_status();
256
+                let x = u2f(state.read(a)?);
257
+                let d = u2f(state.read(div)?);
258
+                if d == 0.0 {
259
+                    state.set_flag(Flag::Invalid, true);
260
+                } else {
261
+                    let res = x / d;
262
+                    let remainder = x % d;
263
+                    state.update_status_float(res);
264
+                    state.write(dst, f2u(res))?;
265
+                    state.write(rem, f2u(remainder))?;
266
+                }
267
+            }
268
+            ArithOp::FloatMod { dst, a, div } => {
269
+                state.clear_status();
270
+                let x = u2f(state.read(a)?);
271
+                let d = u2f(state.read(div)?);
272
+                if d == 0.0 {
273
+                    state.set_flag(Flag::Invalid, true);
274
+                } else {
275
+                    let rem = x % d;
276
+                    state.update_status_float(rem);
277
+                    state.write(dst, f2u(rem))?;
278
+                }
279
+            }
280
+
281
+            // Bitwise
145 282
             ArithOp::And { dst, a, b } => {
146 283
                 state.clear_status();
147 284
                 let x = state.read(a)?;
@@ -282,6 +419,8 @@ impl OpTrait for ArithOp {
282 419
                 state.update_status(res);
283 420
                 state.write(dst, res)?;
284 421
             }
422
+
423
+            _ => unimplemented!() // TODO implement float trig etc
285 424
         }
286 425
 
287 426
         Ok(eres)
@@ -289,19 +428,19 @@ impl OpTrait for ArithOp {
289 428
 
290 429
     fn to_sexp(&self) -> Sexp {
291 430
         match self {
292
-            ArithOp::Add { dst, a, b } => to_sexp_2_or_3("add", dst, a, b),
293
-            ArithOp::Test { a } => sexp::list(&[A("test"), A(a)]),
431
+            ArithOp::Test { a } => sexp::list(&[A("tst"), A(a)]),
294 432
             ArithOp::Compare { a, b } => sexp::list(&[A("cmp"), A(a), A(b)]),
295 433
             ArithOp::RangeTest { val, a: start, b: end } => sexp::list(&[A("rcmp"), A(val), A(start), A(end)]),
296 434
             ArithOp::Rng { dst, min, max } => {
297
-                if min.is_immediate_equal(0) && max.is_immediate_equal(u64::MAX) {
435
+                if min.is_imm_equal(0) && max.is_imm_equal(u64::MAX) {
298 436
                     sexp::list(&[A("rng"), A(dst)])
299
-                } else if min.is_immediate_equal(0) {
437
+                } else if min.is_imm_equal(0) {
300 438
                     sexp::list(&[A("rng"), A(dst), A(max)])
301 439
                 } else {
302 440
                     sexp::list(&[A("rng"), A(dst), A(min), A(max)])
303 441
                 }
304 442
             }
443
+            ArithOp::Add { dst, a, b } => to_sexp_2_or_3("add", dst, a, b),
305 444
             ArithOp::Sub { dst, a, b } => to_sexp_2_or_3("sub", dst, a, b),
306 445
             ArithOp::Mul { dst, a, b } => to_sexp_2_or_3("mul", dst, a, b),
307 446
             ArithOp::Div { dst, rem, a, div } => {
@@ -316,6 +455,40 @@ impl OpTrait for ArithOp {
316 455
                 }
317 456
             }
318 457
             ArithOp::Mod { dst, a, div } => to_sexp_2_or_3("mod", dst, a, div),
458
+
459
+            // TODO render as float
460
+            ArithOp::FloatTest { a } => sexp::list(&[A("tstf"), A(a)]),
461
+            ArithOp::FloatCompare { a, b } => sexp::list(&[A("cmpf"), A(a), A(b)]),
462
+            ArithOp::FloatRangeTest { val, a: start, b: end } => sexp::list(&[A("rcmpf"), A(val), A(start), A(end)]),
463
+            ArithOp::FloatRng { dst, min, max } => {
464
+                if min.is_imm_equal(0f64.to_bits()) && max.is_imm_equal(f64::MAX.to_bits()) {
465
+                    sexp::list(&[A("rngf"), A(dst)])
466
+                } else if min.is_imm_equal(0) {
467
+                    sexp::list(&[A("rngf"), A(dst), A(max)])
468
+                } else {
469
+                    sexp::list(&[A("rngf"), A(dst), A(min), A(max)])
470
+                }
471
+            }
472
+            ArithOp::FloatAdd { dst, a, b } => to_sexp_2_or_3("addf", dst, a, b),
473
+            ArithOp::FloatSub { dst, a, b } => to_sexp_2_or_3("subf", dst, a, b),
474
+            ArithOp::FloatMul { dst, a, b } => to_sexp_2_or_3("mulf", dst, a, b),
475
+            ArithOp::FloatDiv { dst, rem, a, div } => {
476
+                if rem.is_discard() {
477
+                    to_sexp_2_or_3("divf", dst, a, div)
478
+                } else {
479
+                    if &dst.as_rd() == a {
480
+                        sexp::list(&[A("divrf"), A(dst), A(rem), A(div)])
481
+                    } else {
482
+                        sexp::list(&[A("divrf"), A(dst), A(rem), A(a), A(div)])
483
+                    }
484
+                }
485
+            }
486
+            ArithOp::FloatMod { dst, a, div } => to_sexp_2_or_3("modf", dst, a, div),
487
+            ArithOp::IntToFloat { dst, a } => to_sexp_1_or_2("itf", dst, a),
488
+            ArithOp::FloatToInt { dst, a, mode: FloatToIntMode::Floor } => to_sexp_1_or_2("ftif", dst, a),
489
+            ArithOp::FloatToInt { dst, a, mode: FloatToIntMode::Round } => to_sexp_1_or_2("ftir", dst, a),
490
+            ArithOp::FloatToInt { dst, a, mode: FloatToIntMode::Ceil } => to_sexp_1_or_2("ftic", dst, a),
491
+
319 492
             ArithOp::And { dst, a, b } => to_sexp_2_or_3("and", dst, a, b),
320 493
             ArithOp::Or { dst, a, b } => to_sexp_2_or_3("or", dst, a, b),
321 494
             ArithOp::Xor { dst, a, b } => to_sexp_2_or_3("xor", dst, a, b),
@@ -333,6 +506,8 @@ impl OpTrait for ArithOp {
333 506
             ArithOp::Clz { dst, src, mask: slice } => to_sexp_1_or_2(&format!("clz{}", slice), dst, src),
334 507
             ArithOp::Clo { dst, src, mask: slice } => to_sexp_1_or_2(&format!("clo{}", slice), dst, src),
335 508
             ArithOp::SignExtend { dst, src, mask: slice } => to_sexp_1_or_2(&format!("se{}", slice), dst, src),
509
+
510
+            _ => unimplemented!() // FIXME
336 511
         }
337 512
     }
338 513
 }

+ 261 - 8
crsn_arith/src/parse.rs View File

@@ -4,9 +4,7 @@ use crsn::asm::instr::op::OpKind;
4 4
 use crsn::asm::parse::arg_parser::TokenParser;
5 5
 use crsn::module::ParseRes;
6 6
 use crsn::sexp::SourcePosition;
7
-
8
-use crate::defs::ArithOp;
9
-
7
+use crate::defs::{ArithOp, FloatToIntMode};
10 8
 
11 9
 pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
12 10
     Ok(ParseRes::ext(match keyword {
@@ -33,14 +31,14 @@ pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenP
33 31
                 1 => {
34 32
                     ArithOp::Rng {
35 33
                         dst: args.next_wr()?,
36
-                        min: Rd::immediate(0),
37
-                        max: Rd::immediate(u64::MAX),
34
+                        min: Rd::new_imm(0),
35
+                        max: Rd::new_imm(u64::MAX),
38 36
                     }
39 37
                 }
40 38
                 2 => {
41 39
                     ArithOp::Rng {
42 40
                         dst: args.next_wr()?,
43
-                        min: Rd::immediate(0),
41
+                        min: Rd::new_imm(0),
44 42
                         max: args.next_rd()?,
45 43
                     }
46 44
                 }
@@ -61,12 +59,12 @@ pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenP
61 59
 
62 60
         "inc" => {
63 61
             let (dst, a) = args.parse_wr_rd()?;
64
-            ArithOp::Add { dst, a, b: Rd::immediate(1) }
62
+            ArithOp::Add { dst, a, b: Rd::new_imm(1) }
65 63
         }
66 64
 
67 65
         "dec" => {
68 66
             let (dst, a) = args.parse_wr_rd()?;
69
-            ArithOp::Sub { dst, a, b: Rd::immediate(1) }
67
+            ArithOp::Sub { dst, a, b: Rd::new_imm(1) }
70 68
         }
71 69
 
72 70
         "add" => {
@@ -74,6 +72,11 @@ pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenP
74 72
             ArithOp::Add { dst, a, b }
75 73
         }
76 74
 
75
+        "abs" => {
76
+            let (dst, a) = args.parse_wr_rd()?;
77
+            ArithOp::Abs { dst, a }
78
+        }
79
+
77 80
         "sub" => {
78 81
             let (dst, a, b) = args.parse_wr_rd_rd()?;
79 82
             ArithOp::Sub { dst, a, b }
@@ -84,6 +87,11 @@ pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenP
84 87
             ArithOp::Mul { dst, a, b }
85 88
         }
86 89
 
90
+        "pow" => {
91
+            let (dst, a, pow) = args.parse_wr_rd_rd()?;
92
+            ArithOp::Pow { dst, a, pow }
93
+        }
94
+
87 95
         "divr" => {
88 96
             match args.len() {
89 97
                 3 => {
@@ -191,6 +199,251 @@ pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenP
191 199
             ArithOp::Rbit { dst, src }
192 200
         }
193 201
 
202
+        "cmpf" => {
203
+            let parsed = ArithOp::FloatCompare {
204
+                a: args.next_rd()?.imm_to_float(),
205
+                b: args.next_rd()?.imm_to_float(),
206
+            };
207
+            args.ensure_empty("two input arguments")?;
208
+            parsed
209
+        }
210
+
211
+        "frcmp" => {
212
+            let parsed = ArithOp::FloatRangeTest {
213
+                val: args.next_rd()?.imm_to_float(),
214
+                a: args.next_rd()?.imm_to_float(),
215
+                b: args.next_rd()?.imm_to_float(),
216
+            };
217
+            args.ensure_empty("3 arguments (value, min, max)")?;
218
+            parsed
219
+        }
220
+
221
+        "ftst" => {
222
+            let arg = args.next_rd()?;
223
+            args.ensure_empty("1 input argument")?;
224
+            ArithOp::FloatTest { a: arg.imm_to_float() }
225
+        }
226
+
227
+        "frng" => {
228
+            let parsed = match args.len() {
229
+                1 => {
230
+                    ArithOp::FloatRng {
231
+                        dst: args.next_wr()?,
232
+                        min: Rd::new_float(0.0),
233
+                        max: Rd::new_float(f64::MAX),
234
+                    }
235
+                }
236
+                2 => {
237
+                    ArithOp::FloatRng {
238
+                        dst: args.next_wr()?,
239
+                        min: Rd::new_float(0.0),
240
+                        max: args.next_rd()?.imm_to_float(),
241
+                    }
242
+                }
243
+                3 => {
244
+                    ArithOp::FloatRng {
245
+                        dst: args.next_wr()?,
246
+                        min: args.next_rd()?.imm_to_float(),
247
+                        max: args.next_rd()?.imm_to_float(),
248
+                    }
249
+                }
250
+                _ => {
251
+                    return Err(CrsnError::Parse("Rng requires 1, 2 or 3 arguments".into(), op_pos.clone()));
252
+                }
253
+            };
254
+            args.ensure_empty("1 (dst) or 3 (dst, min, max) arguments")?;
255
+            parsed
256
+        }
257
+
258
+        "fadd" => {
259
+            let (dst, a, b) = args.parse_wr_rd_rd()?;
260
+            ArithOp::FloatAdd {
261
+                dst,
262
+                a: a.imm_to_float(),
263
+                b: b.imm_to_float(),
264
+            }
265
+        }
266
+
267
+        "fsub" => {
268
+            let (dst, a, b) = args.parse_wr_rd_rd()?;
269
+            ArithOp::FloatSub {
270
+                dst,
271
+                a: a.imm_to_float(),
272
+                b: b.imm_to_float(),
273
+            }
274
+        }
275
+
276
+        "fmul" => {
277
+            let (dst, a, b) = args.parse_wr_rd_rd()?;
278
+            ArithOp::FloatMul {
279
+                dst,
280
+                a: a.imm_to_float(),
281
+                b: b.imm_to_float(),
282
+            }
283
+        }
284
+
285
+        "fpow" => {
286
+            let (dst, a, pow) = args.parse_wr_rd_rd()?;
287
+            ArithOp::FloatPow {
288
+                dst,
289
+                a: a.imm_to_float(),
290
+                pow: pow.imm_to_float()
291
+            }
292
+        }
293
+
294
+        "froot" => {
295
+            let (dst, a, root) = args.parse_wr_rd_rd()?;
296
+            ArithOp::FloatRoot {
297
+                dst,
298
+                a: a.imm_to_float(),
299
+                root: root.imm_to_float()
300
+            }
301
+        }
302
+
303
+        "fhyp" => {
304
+            let (dst, a, b) = args.parse_wr_rd_rd()?;
305
+            ArithOp::FloatHyp {
306
+                dst,
307
+                a: a.imm_to_float(),
308
+                b: a.imm_to_float(),
309
+            }
310
+        }
311
+
312
+        "fdiv" => {
313
+            let (dst, a, div) = args.parse_wr_rd_rd()?;
314
+            ArithOp::FloatDiv {
315
+                dst,
316
+                rem: Wr::discard(),
317
+                a: a.imm_to_float(),
318
+                div: div.imm_to_float(),
319
+            }
320
+        }
321
+
322
+        "fdivr" => {
323
+            match args.len() {
324
+                3 => {
325
+                    let dst = args.next_rdwr()?;
326
+                    let rem = args.next_wr()?;
327
+                    let div = args.next_rd()?;
328
+                    ArithOp::FloatDiv {
329
+                        dst: dst.wr(),
330
+                        rem,
331
+                        a: dst.rd().imm_to_float(),
332
+                        div: div.imm_to_float(),
333
+                    }
334
+                }
335
+                4 => {
336
+                    ArithOp::FloatDiv {
337
+                        dst: args.next_wr()?,
338
+                        rem: args.next_wr()?,
339
+                        a: args.next_rd()?.imm_to_float(),
340
+                        div: args.next_rd()?.imm_to_float(),
341
+                    }
342
+                }
343
+                _ => {
344
+                    return Err(CrsnError::Parse("DivRF requires 3 or 4 arguments".into(), op_pos.clone()));
345
+                }
346
+            }
347
+        }
348
+
349
+        "fmod" => {
350
+            let (dst, a, div) = args.parse_wr_rd_rd()?;
351
+            ArithOp::FloatMod {
352
+                dst,
353
+                a: a.imm_to_float(),
354
+                div: div.imm_to_float(),
355
+            }
356
+        }
357
+
358
+        "itf" => {
359
+            let (dst, a) = args.parse_wr_rd()?;
360
+            ArithOp::IntToFloat {
361
+                dst,
362
+                a: a.imm_to_float()
363
+            }
364
+        }
365
+
366
+        "fti" | "ftir" => {
367
+            let (dst, a) = args.parse_wr_rd()?;
368
+            ArithOp::FloatToInt {
369
+                dst,
370
+                a: a.imm_to_float(),
371
+                mode: FloatToIntMode::Round
372
+            }
373
+        }
374
+
375
+        "ftic" => {
376
+            let (dst, a) = args.parse_wr_rd()?;
377
+            ArithOp::FloatToInt {
378
+                dst,
379
+                a: a.imm_to_float(),
380
+                mode: FloatToIntMode::Ceil
381
+            }
382
+        }
383
+
384
+        "ftif" => {
385
+            let (dst, a) = args.parse_wr_rd()?;
386
+            ArithOp::FloatToInt {
387
+                dst,
388
+                a: a.imm_to_float(),
389
+                mode: FloatToIntMode::Floor
390
+            }
391
+        }
392
+
393
+        "fabs" => {
394
+            let (dst, a) = args.parse_wr_rd()?;
395
+            ArithOp::FloatAbs { dst, a: f.imm_to_float() }
396
+        }
397
+
398
+        "fsin" => {
399
+            let (dst, f) = args.parse_wr_rd()?;
400
+            ArithOp::FloatSin { dst, f: f.imm_to_float() }
401
+        }
402
+
403
+        "fasin" => {
404
+            let (dst, a) = args.parse_wr_rd()?;
405
+            ArithOp::FloatAsin { dst, a: a.imm_to_float() }
406
+        }
407
+
408
+        "fcos" => {
409
+            let (dst, f) = args.parse_wr_rd()?;
410
+            ArithOp::FloatCos { dst, f: f.imm_to_float() }
411
+        }
412
+
413
+        "facos" => {
414
+            let (dst, a) = args.parse_wr_rd()?;
415
+            ArithOp::FloatAcos { dst, a: a.imm_to_float() }
416
+        }
417
+
418
+        "ftan" => {
419
+            let (dst, f) = args.parse_wr_rd()?;
420
+            ArithOp::FloatTan { dst, f: f.imm_to_float() }
421
+        }
422
+
423
+        "fatan" => {
424
+            let (dst, a) = args.parse_wr_rd()?;
425
+            ArithOp::FloatAtan { dst, a: a.imm_to_float() }
426
+        }
427
+
428
+        "fatan2" => {
429
+            let (dst, a, b) = args.parse_wr_rd_rd()?;
430
+            ArithOp::FloatAtan2 {
431
+                dst,
432
+                y: a.imm_to_float(),
433
+                x: b.imm_to_float(),
434
+            }
435
+        }
436
+
437
+        "fcot" => {
438
+            let (dst, f) = args.parse_wr_rd()?;
439
+            ArithOp::FloatCot { dst, f: f.imm_to_float() }
440
+        }
441
+
442
+        "facot" => {
443
+            let (dst, a) = args.parse_wr_rd()?;
444
+            ArithOp::FloatAcot { dst, a: a.imm_to_float() }
445
+        }
446
+
194 447
         other => {
195 448
             if let Some((dst, src, mask)) = args.parse_masked_wr_rd(other, "clz")? {
196 449
                 if !dst.disp_equals(src) && mask.dst_pos != 0 {

+ 3 - 3
crsn_buf/src/parse.rs View File

@@ -21,7 +21,7 @@ pub(crate) fn parse<'a>(_pos: &SourcePosition, keyword: &str, mut args: TokenPar
21 21
 
22 22
             let value = match args.next() {
23 23
                 None => {
24
-                    BufValue::Zeros(Rd::immediate(0))
24
+                    BufValue::Zeros(Rd::new_imm(0))
25 25
                 }
26 26
                 Some(tok @ Sexp::Atom(Atom::S(_), _)) |
27 27
                 Some(tok @ Sexp::Atom(Atom::I(_), _)) |
@@ -112,7 +112,7 @@ pub(crate) fn parse<'a>(_pos: &SourcePosition, keyword: &str, mut args: TokenPar
112 112
         "bfrpush" => {
113 113
             BufOps::Insert {
114 114
                 obj: args.next_rdobj()?,
115
-                idx: Rd::immediate(0),
115
+                idx: Rd::new_imm(0),
116 116
                 value: args.next_rd()?,
117 117
             }
118 118
         }
@@ -121,7 +121,7 @@ pub(crate) fn parse<'a>(_pos: &SourcePosition, keyword: &str, mut args: TokenPar
121 121
             BufOps::Remove {
122 122
                 dst: args.next_wr()?,
123 123
                 obj: args.next_rdobj()?,
124
-                idx: Rd::immediate(0),
124
+                idx: Rd::new_imm(0),
125 125
             }
126 126
         }
127 127
 

+ 2 - 2
crsn_screen/src/parse.rs View File

@@ -24,7 +24,7 @@ pub(crate) fn parse<'a>(_pos: &SourcePosition, keyword: &str, mut args: TokenPar
24 24
                 color: if args.len() > 0 {
25 25
                     args.next_rd()?
26 26
                 } else {
27
-                    Rd::immediate(0) // black
27
+                    Rd::new_imm(0) // black
28 28
                 },
29 29
             }
30 30
         }
@@ -60,7 +60,7 @@ pub(crate) fn parse<'a>(_pos: &SourcePosition, keyword: &str, mut args: TokenPar
60 60
                 force: if args.have_more() {
61 61
                     args.next_rd()?
62 62
                 } else {
63
-                    Rd::immediate(1)
63
+                    Rd::new_imm(1)
64 64
                 },
65 65
             }
66 66
         }