Skip to main content

cambridge_asm/exec/
cmp.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/// Jump
10///
11/// # Syntax
12/// 1. `JMP [ref]` - jump to addr
13/// 2. `JMP [ref],[ref]` - jump to first if CMP true, second if CMP false
14pub fn jmp(ctx: &mut Context, op: &Op) -> RtResult {
15    match op {
16        &Addr(x) => {
17            ctx.override_flow_control();
18            ctx.mar = x;
19        }
20        MultiOp(ops) => match ops[..] {
21            [Addr(eq), Addr(ne)] => {
22                ctx.override_flow_control();
23                if ctx.cmp {
24                    ctx.mar = eq;
25                } else {
26                    ctx.mar = ne;
27                }
28            }
29            _ => return Err(InvalidMultiOp),
30        },
31        Null => return Err(NoOperand),
32        _ => return Err(InvalidOperand),
33    }
34
35    Ok(())
36}
37
38/// Compare
39///
40/// # Syntax
41/// 1. `CMP [lit | reg | addr]` - compare to ACC
42/// 2. `CMP [lit | reg | addr],[lit | reg | addr]` - compare both values
43pub fn cmp(ctx: &mut Context, op: &Op) -> RtResult {
44    match op {
45        MultiOp(ops) => match ops[..] {
46            [ref a, ref b] if a.is_usizeable() && b.is_usizeable() => {
47                ctx.cmp = ctx.read(a)? == ctx.read(b)?;
48            }
49            _ => return Err(InvalidMultiOp),
50        },
51        val if val.is_usizeable() => ctx.cmp = ctx.acc == ctx.read(val)?,
52        Null => return Err(NoOperand),
53        _ => return Err(InvalidOperand),
54    }
55
56    Ok(())
57}
58
59/// Compare with indirect addressing
60///
61/// # Syntax
62/// 1. `CMI [addr]`
63/// 2. `CMI [lit | reg | addr],[addr]`
64pub fn cmi(ctx: &mut Context, op: &Op) -> RtResult {
65    match op {
66        &Addr(addr) => {
67            let addr2 = ctx.mem.get(&addr)?;
68
69            ctx.cmp = ctx.acc
70                == ctx
71                    .mem
72                    .get(addr2)
73                    .copied()
74                    .map_err(|_| InvalidIndirectAddr {
75                        src: addr,
76                        redirect: *addr2,
77                    })?;
78
79            Ok(())
80        }
81        MultiOp(ops) => match ops[..] {
82            [ref dest, Addr(addr)] if dest.is_usizeable() => {
83                let addr2 = ctx.mem.get(&addr)?;
84
85                ctx.cmp = ctx.read(dest)?
86                    == ctx
87                        .mem
88                        .get(addr2)
89                        .copied()
90                        .map_err(|_| InvalidIndirectAddr {
91                            src: addr,
92                            redirect: *addr2,
93                        })?;
94
95                Ok(())
96            }
97            _ => Err(InvalidMultiOp),
98        },
99        Null => Err(NoOperand),
100        _ => Err(InvalidOperand),
101    }
102}
103
104/// Jump if equal
105///
106/// # Syntax
107/// `JPE [addr]`
108pub fn jpe(ctx: &mut Context, op: &Op) -> RtResult {
109    match op {
110        &Addr(addr) => {
111            if ctx.cmp {
112                ctx.override_flow_control();
113                ctx.mar = addr;
114            }
115
116            Ok(())
117        }
118        Null => Err(NoOperand),
119        _ => Err(InvalidOperand),
120    }
121}
122
123/// Jump if not equal
124///
125/// # Syntax
126/// `JPN [addr]`
127pub fn jpn(ctx: &mut Context, op: &Op) -> RtResult {
128    match op {
129        &Addr(addr) => {
130            if !ctx.cmp {
131                ctx.override_flow_control();
132                ctx.mar = addr;
133            }
134
135            Ok(())
136        }
137        Null => Err(NoOperand),
138        _ => Err(InvalidOperand),
139    }
140}