cambridge_asm/exec/
mov.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/// Load immediate values into a register
10///
11/// # Syntax
12///
13/// 1. `LDM [lit]` - loads to `ACC`
14/// 2. `LDM [reg],[lit]` - loads to `reg`
15pub fn ldm(ctx: &mut Context, op: &Op) -> RtResult {
16    match op {
17        MultiOp(ops) => match ops[..] {
18            [ref op, Literal(val)] if op.is_register() => {
19                *ctx.get_mut_register(op) = val;
20                Ok(())
21            }
22            _ => Err(InvalidMultiOp),
23        },
24        &Literal(val) => {
25            ctx.acc = val;
26            Ok(())
27        }
28        Null => Err(NoOperand),
29        _ => Err(InvalidOperand),
30    }
31}
32
33/// Load values from memory into a register
34///
35/// # Syntax
36///
37/// 1. `LDD [addr]` - loads to `ACC`
38/// 2. `LDD [reg],[addr]` - loads to `reg`
39pub fn ldd(ctx: &mut Context, op: &Op) -> RtResult {
40    match op {
41        Addr(addr) => {
42            ctx.acc = ctx.mem.get(addr).copied()?;
43            Ok(())
44        }
45        MultiOp(ops) => match ops[..] {
46            [ref reg, Addr(ref addr)] if reg.is_register() => {
47                *ctx.get_mut_register(reg) = ctx.mem.get(addr).copied()?;
48                Ok(())
49            }
50            _ => Err(InvalidMultiOp),
51        },
52        Null => Err(NoOperand),
53        _ => Err(InvalidOperand),
54    }
55}
56
57/// Load values from memory using indirect addressing into a register
58///
59/// # Syntax
60///
61/// 1. `LDM [addr]` - loads to `ACC`
62/// 2. `LDM [reg],[addr]` - loads to `reg`
63pub fn ldi(ctx: &mut Context, op: &Op) -> RtResult {
64    match op {
65        &Addr(addr) => {
66            let addr2 = ctx.mem.get(&addr)?;
67
68            ctx.acc = ctx
69                .mem
70                .get(addr2)
71                .copied()
72                .map_err(|_| InvalidIndirectAddr {
73                    src: addr,
74                    redirect: *addr2,
75                })?;
76
77            Ok(())
78        }
79        MultiOp(ops) => match ops[..] {
80            [ref reg, Addr(addr)] if reg.is_register() => {
81                let addr2 = ctx.mem.get(&addr)?;
82
83                *ctx.get_mut_register(reg) =
84                    ctx.mem
85                        .get(addr2)
86                        .copied()
87                        .map_err(|_| InvalidIndirectAddr {
88                            src: addr,
89                            redirect: *addr2,
90                        })?;
91
92                Ok(())
93            }
94            _ => Err(InvalidMultiOp),
95        },
96        Null => Err(NoOperand),
97        _ => Err(InvalidOperand),
98    }
99}
100
101/// Load value from memory using indexed addressing into register
102///
103/// # Syntax
104///
105/// 1. `LDM [addr]` - loads to `ACC`
106/// 2. `LDM [reg],[addr]` - loads to `reg`
107pub fn ldx(ctx: &mut Context, op: &Op) -> RtResult {
108    match op {
109        &Addr(addr) => {
110            ctx.acc = ctx
111                .mem
112                .get(&(addr + ctx.ix))
113                .copied()
114                .map_err(|_| InvalidIndexedAddr {
115                    src: addr,
116                    offset: ctx.ix,
117                })?;
118
119            Ok(())
120        }
121        MultiOp(ops) => match ops[..] {
122            [ref reg, Addr(addr)] if reg.is_register() => {
123                *ctx.get_mut_register(reg) =
124                    ctx.mem
125                        .get(&(addr + ctx.ix))
126                        .copied()
127                        .map_err(|_| InvalidIndexedAddr {
128                            src: addr,
129                            offset: ctx.ix,
130                        })?;
131
132                Ok(())
133            }
134            _ => Err(InvalidMultiOp),
135        },
136        Null => Err(NoOperand),
137        _ => Err(InvalidOperand),
138    }
139}
140
141/// Load immediate value into `IX`
142///
143/// # Syntax
144/// `LDR [lit]`
145pub fn ldr(ctx: &mut Context, op: &Op) -> RtResult {
146    match op {
147        &Literal(val) => ctx.ix = val,
148        Null => return Err(NoOperand),
149        _ => return Err(InvalidOperand),
150    }
151
152    Ok(())
153}
154
155/// Move value from `ACC` to a register
156/// OR
157/// Move values between registers and memory addresses
158///
159/// # Syntax
160///
161/// 1. `MOV [reg]` - move `ACC` value to `reg`
162/// 2. `MOV [reg | addr],[reg | addr]` - move second value to first
163pub fn mov(ctx: &mut Context, op: &Op) -> RtResult {
164    match op {
165        MultiOp(ops) => match ops[..] {
166            [ref dest, ref src] if dest.is_read_write() && src.is_usizeable() => {
167                let src = ctx.read(src)?;
168                ctx.modify(dest, |val| *val = src)?;
169            }
170            _ => return Err(InvalidMultiOp),
171        },
172        reg if reg.is_register() => *ctx.get_mut_register(reg) = ctx.acc,
173        Null => return Err(NoOperand),
174        _ => return Err(InvalidOperand),
175    }
176
177    Ok(())
178}
179
180/// Store `ACC` value in memory
181///
182/// # Syntax
183/// `STO [addr]`
184pub fn sto(ctx: &mut Context, op: &Op) -> RtResult {
185    match op {
186        Addr(x) => {
187            *ctx.mem.get_mut(x)? = ctx.acc;
188
189            Ok(())
190        }
191        Null => Err(NoOperand),
192        _ => Err(InvalidOperand),
193    }
194}