ch8_isa/codegen/
instruction.rs

1/*
2 * instruction.rs
3 * Enumerates instructions for the Chip-8 ISA
4 * Created on 12/6/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::super::data;
25use super::CodeGen;
26
27/// A Chip-8 instruction.
28/// All instructions that
29/// execute a calculation 
30/// store the result in their
31/// first argument. 
32pub enum Instruction {
33    /// Clears the screen
34    CLS,
35
36    /// Returns from a subroutine
37    RET,
38
39    /// Unconditionally jumps to an address
40    JMP(data::JmpData),
41
42    /// Calls a subroutine
43    CALL(data::CallData),
44
45    /// Skips the next instruction if
46    /// a `SkipType` condition is met
47    SKIP(data::SkipData),
48
49    /// Assigns values to registers
50    /// or moves one register's value
51    /// into another
52    MOV(data::MovData),
53
54    /// Adds two registers, or
55    /// a register and a value. 
56    /// When both operands are
57    /// registers, `VF` is set to `1` 
58    /// when the result
59    /// exceeds the size of the
60    /// destination register, and `0`
61    /// otherwise. 
62    ADD(data::AddData),
63
64    /// Bitwise ORs two registers
65    OR(data::OrData),
66
67    /// Bitwise ANDs two registers
68    AND(data::AndData),
69
70    /// Bitwise XORs two registers
71    XOR(data::XorData),
72
73    /// Subtracts one register
74    /// from another, with the
75    /// second register subtracted
76    /// from the first. `VF` is
77    /// set to `0` when there's
78    /// a borrow, and `1` if
79    /// there isn't. 
80    SUB(data::SubData),
81
82    /// Stores the least significant
83    /// bit of a register in `VF`
84    /// and shifts that register
85    /// to the right 1 bit
86    SHR(data::ShrData),
87
88    /// Subtracts one register
89    /// from another, with the 
90    /// first register subtracted
91    /// from the second. `VF` is 
92    /// set to `0` when there's
93    /// a borrow, and `1` when 
94    /// there isn't. 
95    SUBN(data::SubnData),
96
97    /// Stores the most significant
98    /// bit of a register in `VF`
99    /// and shifts that register
100    /// to the left one bit
101    SHL(data::ShlData),
102
103    /// Unconditionally jumps to
104    /// an address defined by
105    /// a constant plus the
106    /// `V0` register
107    JPC(data::JpcData),
108
109    /// Stores a random 8-bit 
110    /// integer bitwise ANDed
111    /// with a given constant 
112    /// in a register
113    RAND(data::RandData),
114
115    /// Draws a sprite at
116    /// coordinates defined
117    /// by two registers with
118    /// a width of 8 pixels
119    /// and a given height. The
120    /// sprite is read as bits
121    /// from memory starting at 
122    /// address `I`. `VF` is set
123    /// to `1` if any pixels are
124    /// flipped from on to off, and
125    /// to `0` if not. 
126    DRAW(data::DrawData),
127
128    /// Sets a register to the 
129    /// current value of the
130    /// delay timer
131    GDL(data::GdlData),
132
133    /// Stops execution until a key is
134    /// pressed, then stores that key
135    /// in a register
136    KEY(data::KeyData),
137
138    /// Sets the delay timer to
139    /// the value of a register
140    SDL(data::SdlData),
141
142    /// Sets the sound timer to
143    /// the value of a register
144    SND(data::SndData),
145
146    /// Puts the memory location
147    /// of the hex character 
148    /// corresponding to the value
149    /// of a register into `I`
150    SCH(data::SchData),
151
152    /// Stores the binary-coded decimal
153    /// representation of a register
154    /// in memory location `I`, with
155    /// the hundreds digit in the lowest
156    /// byte. 
157    BCD(data::BcdData),
158
159    /// Dumps the contents of all registers
160    /// up to and including a specified register
161    /// into memory starting at location `I`
162    RDP(data::RdpData),
163
164    /// Loads all registers up to and including
165    /// a specified register from data starting
166    /// at location `I`
167    RLD(data::RldData)
168}
169
170//CodeGen implementation
171impl CodeGen for Instruction {
172    /// Generates the opcode for
173    /// the `Instruction`
174    ///
175    /// # Returns
176    ///
177    /// The opcode corresponding to
178    /// the instruction and its
179    /// data fields
180    fn gen_opcode(&self) -> u16 {
181        return match *self {
182            Instruction::CLS => 0x00E0,
183            Instruction::RET => 0x00EE,
184            Instruction::JMP(ref data) => data.gen_opcode(),
185            Instruction::CALL(ref data) => data.gen_opcode(),
186            Instruction::SKIP(ref data) => data.gen_opcode(),
187            Instruction::MOV(ref data) => data.gen_opcode(),
188            Instruction::ADD(ref data) => data.gen_opcode(),
189            Instruction::OR(ref data) => data.gen_opcode(),
190            Instruction::AND(ref data) => data.gen_opcode(),
191            Instruction::XOR(ref data) => data.gen_opcode(),
192            Instruction::SUB(ref data) => data.gen_opcode(),
193            Instruction::SHR(ref data) => data.gen_opcode(),
194            Instruction::SUBN(ref data) => data.gen_opcode(),
195            Instruction::SHL(ref data) => data.gen_opcode(),
196            Instruction::JPC(ref data) => data.gen_opcode(),
197            Instruction::RAND(ref data) => data.gen_opcode(),
198            Instruction::DRAW(ref data) => data.gen_opcode(),
199            Instruction::GDL(ref data) => data.gen_opcode(),
200            Instruction::KEY(ref data) => data.gen_opcode(),
201            Instruction::SDL(ref data) => data.gen_opcode(),
202            Instruction::SND(ref data) => data.gen_opcode(),
203            Instruction::SCH(ref data) => data.gen_opcode(),
204            Instruction::BCD(ref data) => data.gen_opcode(),
205            Instruction::RDP(ref data) => data.gen_opcode(),
206            Instruction::RLD(ref data) => data.gen_opcode()
207        };
208    }
209}
210
211//unit tests
212#[cfg(test)]
213mod tests {
214    //import the Instruction enum
215    use super::*;
216
217    //this test checks generation 
218    //of the CLS opcode
219    #[test]
220    fn test_cls_opcode_gen() {
221        let instr = Instruction::CLS;
222        assert_eq!(instr.gen_opcode(), 0x00E0);
223    }
224
225    //this test checks generation
226    //of the RET opcode
227    #[test]
228    fn test_ret_opcode_gen() {
229        let instr = Instruction::RET;
230        assert_eq!(instr.gen_opcode(), 0x00EE);
231    }
232}
233
234//end of file