Skip to main content

cambridge_asm/exec/
bitman.rs

1// Copyright (c) 2021 Saadi Save
2// This Source Code Form is subject to the terms of the Mozilla Public
3// License, v. 2.0. If a copy of the MPL was not distributed with this
4// file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
6use super::{Context, RtError::*, RtResult};
7use crate::inst::Op::{self, *};
8
9/// Bitwise AND
10///
11/// # Syntax
12/// 1. `AND [lit | reg | addr]` - AND with `ACC`
13/// 2. `AND [reg | addr],[lit | reg | addr]` - store second AND first to first
14/// 3. `AND [reg | addr],[lit | reg | addr],[lit | reg | addr]` - store second AND third to first
15pub fn and(ctx: &mut Context, op: &Op) -> RtResult {
16    match op {
17        MultiOp(ops) => match ops[..] {
18            [ref dest, ref val] if dest.is_read_write() && val.is_usizeable() => {
19                let val = ctx.read(val)?;
20                ctx.modify(dest, |d| *d &= val)?;
21            }
22            [ref dest, ref a, ref b]
23                if dest.is_read_write() && a.is_usizeable() && b.is_usizeable() =>
24            {
25                let val = ctx.read(a)? & ctx.read(b)?;
26                ctx.modify(dest, |d| *d = val)?;
27            }
28            _ => return Err(InvalidMultiOp),
29        },
30        val if val.is_usizeable() => ctx.acc &= ctx.read(val)?,
31        Null => return Err(NoOperand),
32        _ => return Err(InvalidOperand),
33    }
34
35    Ok(())
36}
37
38/// Bitwise OR
39///
40/// # Syntax
41/// 1. `OR [lit | reg | addr]` - OR with `ACC`
42/// 2. `OR [reg | addr],[lit | reg | addr]` - store second OR first to first
43/// 3. `OR [reg | addr],[lit | reg | addr],[lit | reg | addr]` - store second OR third to first
44pub fn or(ctx: &mut Context, op: &Op) -> RtResult {
45    match op {
46        MultiOp(ops) => match ops[..] {
47            [ref dest, ref val] if dest.is_read_write() && val.is_usizeable() => {
48                let val = ctx.read(val)?;
49                ctx.modify(dest, |d| *d |= val)?;
50            }
51            [ref dest, ref a, ref b]
52                if dest.is_read_write() && a.is_usizeable() && b.is_usizeable() =>
53            {
54                let val = ctx.read(a)? | ctx.read(b)?;
55                ctx.modify(dest, |d| *d = val)?;
56            }
57            _ => return Err(InvalidMultiOp),
58        },
59        val if val.is_usizeable() => ctx.acc |= ctx.read(val)?,
60        Null => return Err(NoOperand),
61        _ => return Err(InvalidOperand),
62    }
63
64    Ok(())
65}
66
67/// Bitwise XOR
68///
69/// # Syntax
70/// 1. `XOR [lit | reg | addr]` - XOR with `ACC`
71/// 2. `XOR [reg | addr],[lit | reg | addr]` - store second XOR first to first
72/// 3. `XOR [reg | addr],[lit | reg | addr],[lit | reg | addr]` - store second XOR third to first
73pub fn xor(ctx: &mut Context, op: &Op) -> RtResult {
74    match op {
75        MultiOp(ops) => match ops[..] {
76            [ref dest, ref val] if dest.is_read_write() && val.is_usizeable() => {
77                let val = ctx.read(val)?;
78                ctx.modify(dest, |d| *d ^= val)?;
79            }
80            [ref dest, ref a, ref b]
81                if dest.is_read_write() && a.is_usizeable() && b.is_usizeable() =>
82            {
83                let val = ctx.read(a)? ^ ctx.read(b)?;
84                ctx.modify(dest, |d| *d = val)?;
85            }
86            _ => return Err(InvalidMultiOp),
87        },
88        val if val.is_usizeable() => ctx.acc ^= ctx.read(val)?,
89        Null => return Err(NoOperand),
90        _ => return Err(InvalidOperand),
91    }
92
93    Ok(())
94}
95
96/// Logical shift left
97///
98/// # Syntax
99/// 1. `LSL [lit | reg | addr]` - LSL with `ACC`
100/// 2. `LSL [reg | addr],[lit | reg | addr]` - store second LSL first to first
101/// 3. `LSL [reg | addr],[lit | reg | addr],[lit | reg | addr]` - store second LSL third to first
102pub fn lsl(ctx: &mut Context, op: &Op) -> RtResult {
103    #[allow(clippy::cast_possible_truncation)]
104    fn checked_shl(dest: &mut usize, val: usize, mar: usize) {
105        if let Some(res) = dest.checked_shl(val as u32) {
106            *dest = res;
107        } else {
108            warn!("Shift left overflow detected at line {}", mar + 1);
109            *dest <<= val;
110        }
111    }
112
113    match op {
114        MultiOp(ops) => {
115            let line = ctx.mar;
116            match ops[..] {
117                [ref dest, ref val] if dest.is_read_write() && val.is_usizeable() => {
118                    let val = ctx.read(val)?;
119                    ctx.modify(dest, |d| checked_shl(d, val, line))
120                }
121                [ref dest, ref a, ref b]
122                    if dest.is_read_write() && a.is_usizeable() && b.is_usizeable() =>
123                {
124                    let mut a = ctx.read(a)?;
125                    checked_shl(&mut a, ctx.read(b)?, line);
126                    ctx.modify(dest, |d| *d = a)
127                }
128                _ => Err(InvalidMultiOp),
129            }
130        }
131        val if val.is_usizeable() => {
132            let x = ctx.read(val)?;
133            checked_shl(&mut ctx.acc, x, ctx.mar);
134            Ok(())
135        }
136        Null => Err(NoOperand),
137        _ => Err(InvalidOperand),
138    }
139}
140
141/// Logical shift right
142///
143/// # Syntax
144/// 1. `LSR [lit | reg | addr]` - LSR with `ACC`
145/// 2. `LSR [reg | addr],[lit | reg | addr]` - store second LSR first to first
146/// 3. `LSR [reg | addr],[lit | reg | addr],[lit | reg | addr]` - store second LSR third to first
147pub fn lsr(ctx: &mut Context, op: &Op) -> RtResult {
148    match op {
149        MultiOp(ops) => match ops[..] {
150            [ref dest, ref val] if dest.is_read_write() && val.is_usizeable() => {
151                let val = ctx.read(val)?;
152                ctx.modify(dest, |d| *d >>= val)
153            }
154            [ref dest, ref a, ref b]
155                if dest.is_read_write() && a.is_usizeable() && b.is_usizeable() =>
156            {
157                let val = ctx.read(a)? >> ctx.read(b)?;
158                ctx.modify(dest, |d| *d = val)
159            }
160            _ => Err(InvalidMultiOp),
161        },
162        val if val.is_usizeable() => {
163            ctx.acc >>= ctx.read(val)?;
164            Ok(())
165        }
166        Null => Err(NoOperand),
167        _ => Err(InvalidOperand),
168    }
169}