cambridge_asm/exec/
arith.rs1use super::{Context, RtError::*, RtResult};
7use crate::inst::Op::{self, *};
8
9#[inline]
10fn checked_add(dest: &mut usize, val: usize, mar: usize) {
11 if let Some(res) = dest.checked_add(val) {
12 *dest = res;
13 } else {
14 warn!("Addition overflow detected at line {}", mar + 1);
15 *dest += val;
16 }
17}
18
19pub fn add(ctx: &mut Context, op: &Op) -> RtResult {
26 match op {
27 MultiOp(ops) => match ops[..] {
28 [ref dest, ref val] if dest.is_read_write() && val.is_usizeable() => {
29 let line = ctx.mar;
30 let val = ctx.read(val)?;
31 ctx.modify(dest, |d| checked_add(d, val, line))?;
32 }
33 [ref dest, ref a, ref b]
34 if dest.is_read_write() && a.is_usizeable() && b.is_usizeable() =>
35 {
36 let mut a = ctx.read(a)?;
37 checked_add(&mut a, ctx.read(b)?, ctx.mar);
38 ctx.modify(dest, |d| *d = a)?;
39 }
40 _ => return Err(InvalidMultiOp),
41 },
42 Null => return Err(NoOperand),
43 val if val.is_usizeable() => {
44 let val = ctx.read(val)?;
45 checked_add(&mut ctx.acc, val, ctx.mar);
46 }
47 _ => return Err(InvalidOperand),
48 }
49
50 Ok(())
51}
52
53#[inline]
54fn checked_sub(dest: &mut usize, val: usize, mar: usize) {
55 if let Some(res) = dest.checked_sub(val) {
56 *dest = res;
57 } else {
58 warn!("Subtraction overflow detected at line {}", mar + 1);
59 *dest -= val;
60 }
61}
62
63pub fn sub(ctx: &mut Context, op: &Op) -> RtResult {
70 match op {
71 MultiOp(ops) => match ops[..] {
72 [ref dest, ref val] if dest.is_read_write() && val.is_usizeable() => {
73 let line = ctx.mar;
74 let val = ctx.read(val)?;
75 ctx.modify(dest, |d| checked_sub(d, val, line))?;
76 }
77 [ref dest, ref a, ref b]
78 if dest.is_read_write() && a.is_usizeable() && b.is_usizeable() =>
79 {
80 let mut a = ctx.read(a)?;
81 checked_sub(&mut a, ctx.read(b)?, ctx.mar);
82 ctx.modify(dest, |d| *d = a)?;
83 }
84 _ => return Err(InvalidMultiOp),
85 },
86 val if val.is_usizeable() => {
87 let val = ctx.read(val)?;
88 checked_sub(&mut ctx.acc, val, ctx.mar);
89 }
90 Null => return Err(NoOperand),
91 _ => return Err(InvalidOperand),
92 }
93
94 Ok(())
95}
96
97pub fn inc(ctx: &mut Context, op: &Op) -> RtResult {
102 match op {
103 dest if dest.is_read_write() => {
104 let line = ctx.mar;
105 ctx.modify(dest, |d| checked_add(d, 1, line))?;
106 }
107 Null => return Err(NoOperand),
108 _ => return Err(InvalidOperand),
109 }
110
111 Ok(())
112}
113
114pub fn dec(ctx: &mut Context, op: &Op) -> RtResult {
119 match op {
120 dest if dest.is_read_write() => {
121 let line = ctx.mar;
122 ctx.modify(dest, |d| checked_sub(d, 1, line))?;
123 }
124 Null => return Err(NoOperand),
125 _ => return Err(InvalidOperand),
126 }
127
128 Ok(())
129}
130
131#[cfg(feature = "extended")]
138pub fn zero(ctx: &mut Context, op: &Op) -> RtResult {
139 match op {
140 MultiOp(ops) => {
141 for op in ops.iter().filter(|op| op.is_read_write()) {
142 ctx.modify(op, |val| *val = 0)?;
143 }
144 }
145 Null => ctx.acc = 0,
146 op if op.is_read_write() => ctx.modify(op, |val| *val = 0)?,
147 _ => return Err(InvalidOperand),
148 }
149
150 Ok(())
151}