jasm/assembler.rs
1#[derive(Copy, Clone)]
2pub enum Register {
3 A,
4 B,
5 C,
6 D,
7 H,
8 Z,
9}
10
11pub enum RegisterOrImm {
12 Reg(Register),
13 Imm8(u8),
14 Imm16(u16),
15}
16
17pub struct Assembler {
18 buffer: Vec<u8>,
19}
20
21impl Assembler {
22 pub fn new() -> Assembler {
23 Assembler { buffer: Vec::new() }
24 }
25
26 pub fn bytes(&self) -> Vec<u8> {
27 self.buffer.clone()
28 }
29
30 /// Moves a register or 8-bit immediate value from `src` into a register `dest`.
31 ///
32 /// # Panics
33 ///
34 /// Panics if the `src` operand is not `RegisterOrImm::Reg()` or `RegisterOrImm:Imm8()`.
35 pub fn mw(&mut self, dest: Register, src: RegisterOrImm) {
36 match src {
37 RegisterOrImm::Reg(reg) => {
38 self.buffer.push(0x08 | dest as u8);
39 self.buffer.push(reg as u8);
40 }
41 RegisterOrImm::Imm8(value) => {
42 self.buffer.push(dest as u8);
43 self.buffer.push(value);
44 }
45 _ => panic!("invalid source operand"),
46 }
47 }
48
49 /// Loads a 8-bit value from memory into a register `dest`.
50 /// If `src` is `Some(...)`, the value passed in `src` is used as the source address.
51 /// If `src` is `None`, the value in the `HL` register is used as the source address.
52 pub fn lw(&mut self, dest: Register, src: Option<u16>) {
53 match src {
54 Some(addr) => {
55 self.buffer.push(0x01 << 4 | dest as u8);
56 self.emit_u16(addr);
57 }
58 None => {
59 self.buffer.push(0x01 << 4 | 0x08 | dest as u8);
60 }
61 }
62 }
63
64 /// Stores an 8-bit value from a register `src` into memory.
65 /// If `dest` is `Some(...)`, the value passed in `dest` is used as the destination address.
66 /// If `dest` is `None`, the value in the `HL` register is used as the destination address.
67 pub fn sw(&mut self, dest: Option<u16>, src: Register) {
68 match dest {
69 Some(addr) => {
70 self.buffer.push(0x02 << 4 | src as u8);
71 self.emit_u16(addr);
72 }
73 None => {
74 self.buffer.push(0x02 << 4 | 0x08 | src as u8);
75 }
76 }
77 }
78
79 /// Pushes a register or 8-bit immediate value onto the stack.
80 ///
81 /// # Panics
82 ///
83 /// Panics if the `src` operand is not `RegisterOrImm::Reg()` or `RegisterOrImm:Imm8()`.
84 pub fn push(&mut self, src: RegisterOrImm) {
85 match src {
86 RegisterOrImm::Reg(reg) => {
87 self.buffer.push(0x03 << 4 | 0x08 | reg as u8);
88 }
89 RegisterOrImm::Imm8(value) => {
90 self.buffer.push(0x03 << 4);
91 self.buffer.push(value);
92 }
93 _ => panic!("invalid source operand"),
94 }
95 }
96
97 /// Pops a value from the stack and loads it into a register `dest`.
98 pub fn pop(&mut self, dest: Register) {
99 self.buffer.push(0x04 << 4 | 0x08 | dest as u8);
100 }
101
102 /// Loads a 16-bit value from memory into the `HL` register.
103 pub fn lda(&mut self, addr: u16) {
104 self.buffer.push(5 << 4);
105 self.emit_u16(addr);
106 }
107
108 /// Jumps to the address specified by the `HL` register if the immediate value `src` or the
109 /// value in the register `src` is not zero.
110 ///
111 /// # Panics
112 ///
113 /// Panics if the `src` operand is not `RegisterOrImm::Reg()` or `RegisterOrImm:Imm8()`.
114 pub fn jnz(&mut self, src: RegisterOrImm) {
115 match src {
116 RegisterOrImm::Reg(reg) => {
117 self.buffer.push(0x06 << 4 | 0x08 | reg as u8);
118 }
119 RegisterOrImm::Imm8(value) => {
120 self.buffer.push(0x06 << 4);
121 self.buffer.push(value);
122 }
123 _ => panic!("invalid source operand"),
124 }
125 }
126
127 /// Reads a byte from the port specified by `src` into a register `dest`.
128 ///
129 /// # Panics
130 ///
131 /// Panics if the `src` operand is not `RegisterOrImm::Reg()` or `RegisterOrImm:Imm8()`.
132 pub fn inb(&mut self, dest: Register, src: RegisterOrImm) {
133 match src {
134 RegisterOrImm::Reg(reg) => {
135 self.buffer.push(0x07 << 4 | 0x08 | dest as u8);
136 self.buffer.push(reg as u8);
137 }
138 RegisterOrImm::Imm8(value) => {
139 self.buffer.push(0x07 << 4 | dest as u8);
140 self.buffer.push(value);
141 }
142 _ => panic!("invalid source operand"),
143 }
144 }
145
146 /// Writes a byte from a register `src` to the port specified by `dest`.
147 ///
148 /// # Panics
149 ///
150 /// Panics if the `dest` operand is not `RegisterOrImm::Reg()` or `RegisterOrImm:Imm8()`.
151 pub fn outb(&mut self, dest: RegisterOrImm, src: Register) {
152 match dest {
153 RegisterOrImm::Reg(reg) => {
154 self.buffer.push(0x08 << 4 | 0x08 | src as u8);
155 self.buffer.push(reg as u8);
156 }
157 RegisterOrImm::Imm8(value) => {
158 self.buffer.push(0x08 << 4 | src as u8);
159 self.buffer.push(value);
160 }
161 _ => panic!("invalid destination operand"),
162 }
163 }
164
165 /// Adds a register or 8-bit immediate value `src` and the value in a register `dest`.
166 /// The result is stored in the register `dest`.
167 ///
168 /// # Panics
169 ///
170 /// Panics if the `src` operand is not `RegisterOrImm::Reg()` or `RegisterOrImm:Imm8()`.
171 pub fn add(&mut self, dest: Register, src: RegisterOrImm) {
172 match src {
173 RegisterOrImm::Reg(reg) => {
174 self.buffer.push(0x09 << 4 | 0x08 | dest as u8);
175 self.buffer.push(reg as u8);
176 }
177 RegisterOrImm::Imm8(value) => {
178 self.buffer.push(0x09 << 4 | dest as u8);
179 self.buffer.push(value);
180 }
181 _ => panic!("invalid source operand"),
182 }
183 }
184
185 /// Adds with carry a register or 8-bit immediate value `src` and the value in a register `dest`.
186 /// The result is stored in the register `dest`.
187 ///
188 /// # Panics
189 ///
190 /// Panics if the `src` operand is not `RegisterOrImm::Reg()` or `RegisterOrImm:Imm8()`.
191 pub fn adc(&mut self, dest: Register, src: RegisterOrImm) {
192 match src {
193 RegisterOrImm::Reg(reg) => {
194 self.buffer.push(0x0A << 4 | 0x08 | dest as u8);
195 self.buffer.push(reg as u8);
196 }
197 RegisterOrImm::Imm8(value) => {
198 self.buffer.push(0x0A << 4 | dest as u8);
199 self.buffer.push(value);
200 }
201 _ => panic!("invalid source operand"),
202 }
203 }
204
205 /// Performs a bitwise AND operating on a register or 8-bit immediate value `src` and the value in a register `dest`.
206 /// The result is stored in the register `dest`.
207 ///
208 /// # Panics
209 ///
210 /// Panics if the `src` operand is not `RegisterOrImm::Reg()` or `RegisterOrImm:Imm8()`.
211 pub fn and(&mut self, dest: Register, src: RegisterOrImm) {
212 match src {
213 RegisterOrImm::Reg(reg) => {
214 self.buffer.push(0x0B << 4 | 0x08 | dest as u8);
215 self.buffer.push(reg as u8);
216 }
217 RegisterOrImm::Imm8(value) => {
218 self.buffer.push(0x0B << 4 | dest as u8);
219 self.buffer.push(value);
220 }
221 _ => panic!("invalid source operand"),
222 }
223 }
224
225 /// Performs a bitwise OR operating on a register or 8-bit immediate value `src` and the value in a register `dest`.
226 /// The result is stored in the register `dest`.
227 ///
228 /// # Panics
229 ///
230 /// Panics if the `src` operand is not `RegisterOrImm::Reg()` or `RegisterOrImm:Imm8()`.
231 pub fn or(&mut self, dest: Register, src: RegisterOrImm) {
232 match src {
233 RegisterOrImm::Reg(reg) => {
234 self.buffer.push(0x0C << 4 | 0x08 | dest as u8);
235 self.buffer.push(reg as u8);
236 }
237 RegisterOrImm::Imm8(value) => {
238 self.buffer.push(0x0C << 4 | dest as u8);
239 self.buffer.push(value);
240 }
241 _ => panic!("invalid source operand"),
242 }
243 }
244
245 /// Performs a bitwise NOR operating on a register or 8-bit immediate value `src` and the value in a register `dest`.
246 /// The result is stored in the register `dest`.
247 ///
248 /// # Panics
249 ///
250 /// Panics if the `src` operand is not `RegisterOrImm::Reg()` or `RegisterOrImm:Imm8()`.
251 pub fn nor(&mut self, dest: Register, src: RegisterOrImm) {
252 match src {
253 RegisterOrImm::Reg(reg) => {
254 self.buffer.push(0x0D << 4 | 0x08 | dest as u8);
255 self.buffer.push(reg as u8);
256 }
257 RegisterOrImm::Imm8(value) => {
258 self.buffer.push(0x0D << 4 | dest as u8);
259 self.buffer.push(value);
260 }
261 _ => panic!("invalid source operand"),
262 }
263 }
264
265 /// Compares a register or 8-bit immediate value `src` and the value in a register `dest`.
266 /// Sets the flags register accordingly.
267 ///
268 /// # Panics
269 ///
270 /// Panics if the `src` operand is not `RegisterOrImm::Reg()` or `RegisterOrImm:Imm8()`.
271 pub fn cmp(&mut self, left: Register, right: RegisterOrImm) {
272 match right {
273 RegisterOrImm::Reg(reg) => {
274 self.buffer.push(0x0E << 4 | 0x08 | left as u8);
275 self.buffer.push(reg as u8);
276 }
277 RegisterOrImm::Imm8(value) => {
278 self.buffer.push(0x0E << 4 | left as u8);
279 self.buffer.push(value);
280 }
281 _ => panic!("invalid source operand"),
282 }
283 }
284
285 /// Subtracts a register or 8-bit immediate value `src` from the value in a register `dest`.
286 /// The result is stored in the register `dest`.
287 ///
288 /// # Panics
289 ///
290 /// Panics if the `src` operand is not `RegisterOrImm::Reg()` or `RegisterOrImm:Imm8()`.
291 pub fn sbb(&mut self, dest: Register, src: RegisterOrImm) {
292 match src {
293 RegisterOrImm::Reg(reg) => {
294 self.buffer.push(0x0F << 4 | 0x08 | dest as u8);
295 self.buffer.push(reg as u8);
296 }
297 RegisterOrImm::Imm8(value) => {
298 self.buffer.push(0x0F << 4 | dest as u8);
299 self.buffer.push(value);
300 }
301 _ => panic!("invalid source operand"),
302 }
303 }
304
305 #[inline(always)]
306 fn emit_u16(&mut self, value: u16) {
307 self.buffer.push((value & 0xFF) as u8);
308 self.buffer.push((value >> 8) as u8);
309 }
310}