ch8_isa/data/
mov_data.rs

1/*
2 * mov_data.rs
3 * Defines a struct that holds data for the MOV instruction
4 * Created on 12/4/2019
5 * Created by Andrew Davis
6 *
7 * Copyright (C) 2019  Andrew Davis
8 *
9 * This program is free software: you can redistribute it and/or modify   
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 * 
19 * You should have received a copy of the GNU General Public License
20 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23//usage statements
24use super::Register;
25use super::super::codegen::CodeGen;
26
27/// Contextual data for the `MOV` instruction
28pub struct MovData {
29    /// The destination register 
30    dest: Register,
31
32    /// The source register
33    src_reg: Option<Register>,
34
35    /// The source constant
36    src_cst: Option<u16>
37}
38
39//implementation
40impl MovData {
41    /// Constructs a new `MovData` instance
42    /// with a source register
43    /// 
44    /// # Arguments
45    ///
46    /// * `new_dest` - The destination register
47    /// * `new_src` - The source register
48    /// 
49    /// # Panics
50    ///
51    /// This method will panic if `new_dest` or `new_src`
52    /// refers to the `I` register 
53    ///
54    /// # Returns
55    ///
56    /// A new `MovData` instance with the given properties
57    pub fn with_register(new_dest: Register, new_src: Register)
58        -> MovData {
59        //validate the registers
60        if new_dest == Register::I {
61            panic!("Index register must be assigned from a constant");
62        }
63        if new_src == Register::I {
64            panic!("Index register cannot be assigned from");
65        }
66
67        //and call the new method
68        return MovData::new(new_dest, Some(new_src), None);
69    }
70
71    /// Constructs a new `MovData` instance with a source constant
72    ///
73    /// # Arguments
74    ///
75    /// * `new_dest` - The destination register
76    /// * `new_src` - The source constant
77    ///
78    /// # Returns
79    ///
80    /// A new `MovData` instance with the given properties
81    pub fn with_constant(new_dest: Register, new_src: u16) -> MovData {
82        //mask the source value
83        let new_src = match new_dest {
84            Register::I => new_src & 0x0FFF,
85            _ => new_src & 0x00FF
86        };
87
88        //call the new method
89        return MovData::new(new_dest, None, Some(new_src));
90    }
91
92    /// Constructs a new `MovData` instance
93    ///
94    /// # Arguments
95    ///
96    /// * `new_dest` - The destination register
97    /// * `new_src_reg` - The source register
98    /// * `new_src_cst` - The source constant
99    ///
100    /// # Returns
101    ///
102    /// A new `MovData` instance with the given properties
103    fn new(new_dest: Register, new_src_reg: Option<Register>,
104           new_src_cst: Option<u16>) -> MovData {
105        return MovData {
106            dest: new_dest,
107            src_reg: new_src_reg,
108            src_cst: new_src_cst 
109        };
110    }
111}
112
113//CodeGen implementation
114impl CodeGen for MovData {
115    /// Generates an opcode from the data
116    /// 
117    /// # Returns
118    ///
119    /// An opcode generated from the data
120    fn gen_opcode(&self) -> u16 {
121        //handle destination objects
122        match self.dest {
123            Register::I => {
124                match self.src_cst.clone() {
125                    Some(cst) => {
126                        let mut code = 0xA000;
127                        code |= cst;
128                        return code;
129                    },
130                    None => {
131                        panic!("Invalid source value");
132                    }
133                };
134            },
135            _ => { //normal register
136                //handle different source values
137                match self.src_reg.clone() {
138                    Some(reg) => { //source is a register
139                        let mut code = 0x8000;
140                        code |= (self.dest.to_id() as u16) << 8;
141                        code |= (reg.to_id() as u16) << 4;
142                        return code;
143                    },
144                    None => { //source is a constant
145                        match self.src_cst {
146                            Some(cst) => {
147                                let mut code = 0x6000;
148                                code |= (self.dest.to_id() as u16) << 8;
149                                code |= cst;
150                                return code;
151                            },
152                            None => { //should not be reached
153                                panic!("Invalid RHS of MOV instruction");
154                            }
155                        };
156                    }
157                };
158            }
159        };
160    }
161}
162
163//tests
164#[cfg(test)]
165mod tests {
166    //import the MovData structure
167    use super::*;
168
169    //this test checks that constant values are masked
170    #[test]
171    fn test_constants_are_masked() {
172        let d1 = MovData::with_constant(Register::I, 0xFFFF);
173        assert_eq!(d1.src_cst.unwrap(), 0x0FFF);
174        let d2 = MovData::with_constant(Register::V0, 0xFFFF);
175        assert_eq!(d2.src_cst.unwrap(), 0x00FF);
176    }
177
178    //this test checks that the I register cannot be assigned from
179    #[test]
180    #[should_panic]
181    fn test_cannot_assign_from_index() {
182        let _b1 = MovData::with_register(Register::V0, Register::I);
183    }
184
185    //this test checks that the I register cannot have a register
186    //assigned to it
187    #[test]
188    #[should_panic]
189    fn test_cannot_assign_register_to_index() {
190        let _b1 = MovData::with_register(Register::I, Register::V0);
191    }
192
193    //this test checks generating opcodes
194    #[test]
195    fn test_opcode_gen() {
196        let m1 = MovData::with_register(Register::V1, Register::V2);
197        assert_eq!(m1.gen_opcode(), 0x8120);
198        let m2 = MovData::with_constant(Register::V1, 0xFC);
199        assert_eq!(m2.gen_opcode(), 0x61FC);
200        let m3 = MovData::with_constant(Register::I, 0x0FC1);
201        assert_eq!(m3.gen_opcode(), 0xAFC1);
202    }
203}
204
205//end of file