mos_hardware/mega65/math.rs
1// copyright 2023 mikael lund aka wombat
2//
3// licensed under the apache license, version 2.0 (the "license");
4// you may not use this file except in compliance with the license.
5// you may obtain a copy of the license at
6//
7// http://www.apache.org/licenses/license-2.0
8//
9// unless required by applicable law or agreed to in writing, software
10// distributed under the license is distributed on an "as is" basis,
11// without warranties or conditions of any kind, either express or implied.
12// see the license for the specific language governing permissions and
13// limitations under the license.
14
15//! Mathematical support functions
16
17use super::MATH_STATUS;
18use bitflags::bitflags;
19use volatile_register::{RO, WO};
20
21bitflags! {
22 /// Control flags for hardware multiplier/divider
23 pub struct StatusFlags: u8 {
24 const DIVBUSY = 0b1000_0000; // bit 7
25 const MULBUSY = 0b0100_0000; // bit 6
26 }
27}
28
29/// Registers for Math Acceleration
30///
31/// See the MEGA64 book, Section G-19.
32/// The hardware registers use little endian storage.
33#[repr(C, packed)]
34pub struct MathAccelerator {
35 /// 32-bit fractional part DIVOUT(0-3) of MULTINA divided by MULTINB
36 pub divout_fraction: RO<u32>, // 0x00
37 /// 32-bit whole part DIVOUT(4-7) of MULTINA divided by MULTINB
38 pub divout_whole: RO<u32>, // 0x04
39 /// 32-bit input A
40 pub multin_a: WO<u32>, // 0x08
41 /// 32-bit input B
42 pub multin_b: WO<u32>, // 0x0c
43 /// 64-bit product MULTOUT of MULTINA and MULTINB
44 pub multout: RO<u64>, // 0x10
45}
46
47impl MathAccelerator {
48 /// 32 bit multiplication using hardware multiplier
49 ///
50 /// Cycles: 1
51 pub fn multiply(&self, a: u32, b: u32) -> u64 {
52 unsafe {
53 self.multin_a.write(a);
54 self.multin_b.write(b);
55 }
56 self.multout.read()
57 }
58
59 /// 32 bit multiplication and division using hardware multiplier
60 ///
61 /// Returns a tuple with:
62 /// 1. 64-bit `a x b` product
63 /// 2. 32-bit whole part of `a / b`;
64 /// 3. 32-bit fractional part of `a / b`
65 ///
66 /// Cycles: less than 20
67 pub fn multiply_divide(&self, a: u32, b: u32) -> (u64, u32, u32) {
68 let product = self.multiply(a, b);
69 while unsafe { &(*MATH_STATUS) }
70 .read()
71 .contains(StatusFlags::DIVBUSY)
72 {}
73 (
74 product,
75 self.divout_whole.read(),
76 self.divout_fraction.read(),
77 )
78 }
79}