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}