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