├── .gitignore ├── LICENSE ├── README.md ├── build.zig ├── src ├── c.zig ├── cpu.zig ├── disassembler.zig ├── main.zig └── opcode.zig └── testdata ├── sprite_priority.gb └── test.s /.gitignore: -------------------------------------------------------------------------------- 1 | /zig-cache 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gbemu 2 | 3 | Zig Game Boy emulator 4 | 5 | ## Why Zig? 6 | 7 | Zig is a promising new language aimed at replacing C. Many Game Boy emulators 8 | are written in C, C++, and Rust. While these languages definitely succeed in 9 | emulating a Game Boy, I wanted to test out the power of Zig on a major project. 10 | 11 | ## Resources 12 | 13 | There are many resources dedicated to Game Boy emulator development. A great 14 | list can be found [here](https://github.com/avivace/awesome-gbdev). 15 | 16 | ## Assembler/Compiler 17 | 18 | gbemu does not contain an assembler nor a compiler at this time. I highly 19 | recommend using RGBDS for Game Boy development. 20 | 21 | ## Roadmap 22 | 23 | - [x] CPU implementation 24 | - [x] Disassembler 25 | - [ ] Video emulation 26 | - [ ] Audio emulation 27 | -------------------------------------------------------------------------------- /build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const Builder = std.build.Builder; 3 | 4 | pub fn build(b: *Builder) void { 5 | const mode = b.standardReleaseOptions(); 6 | const exe = b.addExecutable("gbemu", "src/main.zig"); 7 | exe.addLibPath("/usr/lib/x86_64-linux-gnu"); 8 | exe.linkSystemLibrary("c"); 9 | exe.linkSystemLibrary("SDL2"); 10 | exe.setBuildMode(mode); 11 | 12 | const run_cmd = exe.run(); 13 | 14 | const run_step = b.step("run", "Run gbemu"); 15 | run_step.dependOn(&run_cmd.step); 16 | 17 | b.default_step.dependOn(&exe.step); 18 | b.installArtifact(exe); 19 | } 20 | -------------------------------------------------------------------------------- /src/c.zig: -------------------------------------------------------------------------------- 1 | pub use @cImport({ 2 | @cInclude("SDL2/SDL.h"); 3 | }); 4 | -------------------------------------------------------------------------------- /src/cpu.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const builtin = @import("builtin"); 3 | 4 | const opcode = @import("opcode.zig"); 5 | 6 | pub const Registers = struct { 7 | af: u16, 8 | bc: u16, 9 | de: u16, 10 | hl: u16, 11 | sp: u16, 12 | pc: u16, 13 | 14 | pub fn a(self: *const Registers) u8 { 15 | return @truncate(u8, self.af >> 8); 16 | } 17 | 18 | pub fn setA(self: *Registers, value: u8) void { 19 | self.af = (u16(value) << 8) | self.f(); 20 | } 21 | 22 | pub fn b(self: *const Registers) u8 { 23 | return @truncate(u8, self.bc >> 8); 24 | } 25 | 26 | pub fn setB(self: *Registers, value: u8) void { 27 | self.bc = (u16(value) << 8) | self.c(); 28 | } 29 | 30 | pub fn c(self: *const Registers) u8 { 31 | return @truncate(u8, self.bc); 32 | } 33 | 34 | pub fn setC(self: *Registers, value: u8) void { 35 | self.bc = (u16(self.b()) << 8) | value; 36 | } 37 | 38 | pub fn d(self: *const Registers) u8 { 39 | return @truncate(u8, self.de >> 8); 40 | } 41 | 42 | pub fn setD(self: *Registers, value: u8) void { 43 | self.de = (u16(value) << 8) | self.e(); 44 | } 45 | 46 | pub fn e(self: *const Registers) u8 { 47 | return @truncate(u8, self.de); 48 | } 49 | 50 | pub fn setE(self: *Registers, value: u8) void { 51 | self.de = (u16(self.d()) << 8) | value; 52 | } 53 | 54 | pub fn f(self: *const Registers) u8 { 55 | return @truncate(u8, self.af); 56 | } 57 | 58 | pub fn setF(self: *Registers, value: u8) void { 59 | self.af = (u16(self.a()) << 8) | value; 60 | } 61 | 62 | pub fn h(self: *const Registers) u8 { 63 | return @truncate(u8, self.hl >> 8); 64 | } 65 | 66 | pub fn setH(self: *Registers, value: u8) void { 67 | self.hl = (u16(value) << 8) | self.l(); 68 | } 69 | 70 | pub fn l(self: *const Registers) u8 { 71 | return @truncate(u8, self.hl); 72 | } 73 | 74 | pub fn setL(self: *Registers, value: u8) void { 75 | self.hl = (u16(self.h()) << 8) | value; 76 | } 77 | 78 | const zero_flag_mask: u8 = 0x80; 79 | const subtract_flag_mask: u8 = 0x40; 80 | const half_carry_flag_mask: u8 = 0x20; 81 | const carry_flag_mask: u8 = 0x10; 82 | 83 | pub fn zeroFlag(self: *const Registers) bool { 84 | return (self.f() & zero_flag_mask) != 0; 85 | } 86 | 87 | pub fn setZeroFlag(self: *Registers, value: bool) void { 88 | if (value == true) { 89 | self.setF(self.f() | zero_flag_mask); 90 | } else { 91 | self.setF(self.f() & (~zero_flag_mask)); 92 | } 93 | } 94 | 95 | pub fn subtractFlag(self: *const Registers) bool { 96 | return (self.f() & subtract_flag_mask) != 0; 97 | } 98 | 99 | pub fn setSubtractFlag(self: *Registers, value: bool) void { 100 | if (value == true) { 101 | self.setF(self.f() | subtract_flag_mask); 102 | } else { 103 | self.setF(self.f() & (~subtract_flag_mask)); 104 | } 105 | } 106 | 107 | pub fn halfCarryFlag(self: *const Registers) bool { 108 | return (self.f() & half_carry_flag_mask) != 0; 109 | } 110 | 111 | pub fn setHalfCarryFlag(self: *Registers, value: bool) void { 112 | if (value == true) { 113 | self.setF(self.f() | half_carry_flag_mask); 114 | } else { 115 | self.setF(self.f() & (~half_carry_flag_mask)); 116 | } 117 | } 118 | 119 | pub fn carryFlag(self: *const Registers) bool { 120 | return (self.f() & carry_flag_mask) != 0; 121 | } 122 | 123 | pub fn setCarryFlag(self: *Registers, value: bool) void { 124 | if (value == true) { 125 | self.setF(self.f() | carry_flag_mask); 126 | } else { 127 | self.setF(self.f() & (~carry_flag_mask)); 128 | } 129 | } 130 | }; 131 | 132 | test "Registers" { 133 | var registers: Registers = undefined; 134 | registers.af = 0xFF11; 135 | std.debug.assert(registers.a() == 0xFF); 136 | std.debug.assert(registers.f() == 0x11); 137 | registers.setA(0x11); 138 | registers.setF(0x55); 139 | std.debug.assert(registers.a() == 0x11); 140 | std.debug.assert(registers.f() == 0x55); 141 | 142 | registers.bc = 0xFF11; 143 | std.debug.assert(registers.b() == 0xFF); 144 | std.debug.assert(registers.c() == 0x11); 145 | registers.setB(0x11); 146 | registers.setC(0x55); 147 | std.debug.assert(registers.b() == 0x11); 148 | std.debug.assert(registers.c() == 0x55); 149 | 150 | registers.de = 0xFF11; 151 | std.debug.assert(registers.d() == 0xFF); 152 | std.debug.assert(registers.e() == 0x11); 153 | registers.setD(0x11); 154 | registers.setE(0x55); 155 | std.debug.assert(registers.d() == 0x11); 156 | std.debug.assert(registers.e() == 0x55); 157 | 158 | registers.hl = 0xFF11; 159 | std.debug.assert(registers.h() == 0xFF); 160 | std.debug.assert(registers.l() == 0x11); 161 | registers.setH(0x11); 162 | registers.setL(0x55); 163 | std.debug.assert(registers.h() == 0x11); 164 | std.debug.assert(registers.l() == 0x55); 165 | } 166 | 167 | pub const Memory = struct { 168 | const memory_len = 0xFFFF - 0x2000; 169 | 170 | allocator: *std.mem.Allocator, 171 | memory: []u8, 172 | 173 | pub fn init(allocator: *std.mem.Allocator) !Memory { 174 | return Memory{ 175 | .allocator = allocator, 176 | .memory = try allocator.alloc(u8, memory_len), 177 | }; 178 | } 179 | 180 | pub fn deinit(self: *Memory) void { 181 | self.allocator.free(self.memory); 182 | } 183 | 184 | fn internalIndex(index: u16) u16 { 185 | if (index < 0xE000) { 186 | return index; 187 | } 188 | return index - 0x2000; 189 | } 190 | 191 | pub fn get(self: *const Memory, index: u16) u8 { 192 | return self.memory[internalIndex(index)]; 193 | } 194 | 195 | pub fn set(self: *Memory, index: u16, value: u8) void { 196 | self.memory[internalIndex(index)] = value; 197 | } 198 | 199 | pub fn sliceConst(self: *const Memory, index: u16, len: usize) []const u8 { 200 | const offset = internalIndex(index); 201 | return self.memory[offset .. offset + len]; 202 | } 203 | 204 | pub fn slice(self: *Memory, index: u16, len: usize) []u8 { 205 | const offset = internalIndex(index); 206 | return self.memory[offset .. offset + len]; 207 | } 208 | }; 209 | 210 | pub const CPU = struct { 211 | pub const Stream = std.io.InStream(error{}); 212 | pub const EmptyErrorSet = error{}; 213 | pub const Mode = enum { 214 | Default, 215 | Halt, 216 | Stop, 217 | DisableInterrupts, 218 | EnableInterrupts, 219 | }; 220 | 221 | registers: Registers, 222 | memory: Memory, 223 | stream: Stream, 224 | 225 | pub fn init(allocator: *std.mem.Allocator) !CPU { 226 | return CPU{ 227 | .registers = undefined, 228 | .memory = try Memory.init(allocator), 229 | .stream = Stream{ .readFn = CPU.readFn }, 230 | }; 231 | } 232 | 233 | pub fn deinit(self: *CPU) void { 234 | self.memory.deinit(); 235 | } 236 | 237 | fn readFn(in_stream: *Stream, buffer: []u8) EmptyErrorSet!usize { 238 | const self = @fieldParentPtr(CPU, "stream", in_stream); 239 | var len: usize = undefined; 240 | if (usize(self.registers.pc) + buffer.len > 0xFFFF) { 241 | len = 0xFFFF - self.registers.pc; 242 | } else { 243 | len = buffer.len; 244 | } 245 | std.mem.copy(u8, buffer, self.memory.sliceConst(self.registers.pc, len)); 246 | self.registers.pc +%= @truncate(u16, len); 247 | return len; 248 | } 249 | 250 | fn push(self: *CPU, value: var) void { 251 | const len = @sizeOf(@typeOf(value)); 252 | self.registers.sp -%= len; 253 | std.mem.writeIntSliceLittle(@typeOf(value), self.memory.slice(self.registers.sp, len), value); 254 | } 255 | 256 | fn pop(self: *CPU, comptime T: type) T { 257 | const value = std.mem.readIntSliceLittle(T, self.memory.sliceConst(self.registers.sp, @sizeOf(T))); 258 | self.registers.sp +%= @sizeOf(T); 259 | return value; 260 | } 261 | 262 | fn add(self: *CPU, comptime T: type, a: T, b: T) T { 263 | const B = @IntType(false, @sizeOf(T) * 16); 264 | const high_test_bit_num_trailing_zeros = @sizeOf(T) * 8; 265 | const high_test_bit: B = 1 << high_test_bit_num_trailing_zeros; 266 | const high_operand_mask = high_test_bit - 1; 267 | const low_test_bit = high_test_bit >> 4; 268 | const low_operand_mask = (low_test_bit) - 1; 269 | const result = a + b; 270 | self.registers.setHalfCarryFlag((((a & low_operand_mask) + (b & low_operand_mask)) & low_test_bit) == low_test_bit); 271 | self.registers.setCarryFlag((((a & high_operand_mask) + (b & high_operand_mask)) & high_test_bit) == high_test_bit); 272 | self.registers.setZeroFlag(result == 0); 273 | self.registers.setSubtractFlag(false); 274 | return result; 275 | } 276 | 277 | fn sub(self: *CPU, a: u8, b: u8) u8 { 278 | const result = a - b; 279 | self.registers.setHalfCarryFlag((((a & 0xF) - (b & 0xF)) & 0x10) == 0x10); 280 | self.registers.setCarryFlag(((((a >> 4) & 0xF) - ((b >> 4) & 0xF)) & 0x10) == 0x10); 281 | self.registers.setZeroFlag(result == 0); 282 | self.registers.setSubtractFlag(true); 283 | return @bitCast(u8, result); 284 | } 285 | 286 | fn bitwiseAnd(self: *CPU, a: u8, b: u8) u8 { 287 | const result = a & b; 288 | self.registers.setHalfCarryFlag(true); 289 | self.registers.setCarryFlag(false); 290 | self.registers.setZeroFlag(result == 0); 291 | self.registers.setSubtractFlag(false); 292 | return result; 293 | } 294 | 295 | fn bitwiseOr(self: *CPU, a: u8, b: u8) u8 { 296 | const result = a | b; 297 | self.registers.setHalfCarryFlag(false); 298 | self.registers.setCarryFlag(false); 299 | self.registers.setZeroFlag(result == 0); 300 | self.registers.setSubtractFlag(false); 301 | return result; 302 | } 303 | 304 | fn bitwiseXor(self: *CPU, a: u8, b: u8) u8 { 305 | const result = a ^ b; 306 | self.registers.setHalfCarryFlag(false); 307 | self.registers.setCarryFlag(false); 308 | self.registers.setZeroFlag(result == 0); 309 | self.registers.setSubtractFlag(false); 310 | return result; 311 | } 312 | 313 | fn swap(self: *CPU, x: u8) u8 { 314 | const high_nibble = x & 0xF0; 315 | const low_nibble = x & 0x0F; 316 | const result = low_nibble << 4 | (high_nibble >> 4); 317 | self.registers.setHalfCarryFlag(false); 318 | self.registers.setCarryFlag(false); 319 | self.registers.setZeroFlag(result == 0); 320 | self.registers.setSubtractFlag(false); 321 | return result; 322 | } 323 | 324 | fn rlc(self: *CPU, x: u8) u8 { 325 | const result = (x << 1) | (x >> 7); 326 | self.registers.setCarryFlag((x & 0x80) != 0); 327 | self.registers.setHalfCarryFlag(false); 328 | self.registers.setSubtractFlag(false); 329 | self.registers.setZeroFlag(result == 0); 330 | return result; 331 | } 332 | 333 | fn rl(self: *CPU, x: u8) u8 { 334 | const carry_flag = @boolToInt(self.registers.carryFlag()); 335 | const result = x << 1 | carry_flag; 336 | self.registers.setCarryFlag((x & 0x80) != 0); 337 | self.registers.setHalfCarryFlag(false); 338 | self.registers.setSubtractFlag(false); 339 | self.registers.setZeroFlag(result == 0); 340 | return result; 341 | } 342 | 343 | fn rrc(self: *CPU, x: u8) u8 { 344 | const result = (x << 7) | (x >> 1); 345 | self.registers.setCarryFlag((x & 0x01) != 0); 346 | self.registers.setHalfCarryFlag(false); 347 | self.registers.setSubtractFlag(false); 348 | self.registers.setZeroFlag(result == 0); 349 | return result; 350 | } 351 | 352 | fn rr(self: *CPU, x: u8) u8 { 353 | const result = (u8(@boolToInt(self.registers.carryFlag())) << 7) | (x >> 1); 354 | self.registers.setCarryFlag((x & 0x01) != 0); 355 | self.registers.setHalfCarryFlag(false); 356 | self.registers.setSubtractFlag(false); 357 | self.registers.setZeroFlag(result == 0); 358 | return result; 359 | } 360 | 361 | fn sla(self: *CPU, x: u8) u8 { 362 | const result = x << 1; 363 | self.registers.setCarryFlag((x & 0x80) != 0); 364 | self.registers.setHalfCarryFlag(false); 365 | self.registers.setSubtractFlag(false); 366 | self.registers.setZeroFlag(result == 0); 367 | std.debug.assert((result & 0x01) == 0); 368 | return result; 369 | } 370 | 371 | fn sra(self: *CPU, x: u8) u8 { 372 | const result = (x & 0x80) | x >> 1; 373 | self.registers.setCarryFlag((x & 0x01) != 0); 374 | self.registers.setHalfCarryFlag(false); 375 | self.registers.setSubtractFlag(false); 376 | self.registers.setZeroFlag(result == 0); 377 | std.debug.assert((result & 0x80) == (x & 0x80)); 378 | return result; 379 | } 380 | 381 | fn srl(self: *CPU, x: u8) u8 { 382 | const result = x >> 1; 383 | self.registers.setCarryFlag((x & 0x01) != 0); 384 | self.registers.setHalfCarryFlag(false); 385 | self.registers.setSubtractFlag(false); 386 | self.registers.setZeroFlag(result == 0); 387 | std.debug.assert((result & 0x80) == 0); 388 | return result; 389 | } 390 | 391 | fn testBit(self: *CPU, x: u8, pos: u8) void { 392 | const n = @truncate(u3, pos); 393 | const result = (x & (u8(1) << n)) != 0; 394 | self.registers.setZeroFlag(!result); 395 | self.registers.setSubtractFlag(false); 396 | self.registers.setHalfCarryFlag(true); 397 | } 398 | 399 | fn jumpRelative(self: *CPU, n: i8) void { 400 | const UnsignedAddress = @typeOf(self.registers.pc); 401 | const SignedAddress = @IntType(true, UnsignedAddress.bit_count << 1); 402 | const result = @intCast(SignedAddress, self.registers.pc) + n; 403 | self.registers.pc = @truncate(u16, @intCast(UnsignedAddress, result)); 404 | } 405 | 406 | fn call(self: *CPU, call_address: u16) void { 407 | const return_address: u16 = self.registers.pc + 1; 408 | self.push(return_address); 409 | self.registers.pc = call_address; 410 | } 411 | 412 | pub fn execute(self: *CPU) !Mode { 413 | switch (@intToEnum(opcode.Opcode, try self.stream.readByte())) { 414 | opcode.Opcode.NOP => { 415 | // NOP 416 | }, 417 | opcode.Opcode.LD_BC_nn => { 418 | // LD BC,nn 419 | self.registers.bc = try self.stream.readIntLittle(u16); 420 | }, 421 | opcode.Opcode.LD_BC_A => { 422 | // LD (BC),A 423 | self.memory.set(self.registers.bc, self.registers.a()); 424 | }, 425 | opcode.Opcode.INC_BC => { 426 | // INC BC 427 | self.registers.bc = self.add(u16, self.registers.bc, 1); 428 | }, 429 | opcode.Opcode.INC_B => { 430 | // INC B 431 | self.registers.setB(self.add(u8, self.registers.b(), 1)); 432 | }, 433 | opcode.Opcode.DEC_B => { 434 | // DEC B 435 | self.registers.setB(self.sub(self.registers.b(), 1)); 436 | }, 437 | opcode.Opcode.LD_B_n => { 438 | // LD B,n 439 | self.registers.setB(try self.stream.readByte()); 440 | }, 441 | opcode.Opcode.RLCA => { 442 | // RLCA 443 | self.registers.setA(self.rlc(self.registers.a())); 444 | }, 445 | opcode.Opcode.LD_nn_SP => { 446 | // LD (nn),SP 447 | const value = try self.stream.readIntLittle(u16); 448 | self.memory.set(value, @truncate(u8, (self.registers.sp & 0xFF00) >> 8)); 449 | self.memory.set(value + 1, @truncate(u8, self.registers.sp)); 450 | }, 451 | opcode.Opcode.ADD_HL_BC => { 452 | // ADD HL,BC 453 | self.registers.hl = self.add(u16, self.registers.hl, self.registers.bc); 454 | }, 455 | opcode.Opcode.LD_A_BC => { 456 | // LD A,(BC) 457 | self.registers.setA(self.memory.get(self.registers.bc)); 458 | }, 459 | opcode.Opcode.DEC_BC => { 460 | // DEC BC 461 | self.registers.bc -%= 1; 462 | }, 463 | opcode.Opcode.INC_C => { 464 | // INC C 465 | self.registers.setC(self.add(u8, self.registers.c(), 1)); 466 | }, 467 | opcode.Opcode.DEC_C => { 468 | // DEC D 469 | self.registers.setD(self.sub(self.registers.d(), 1)); 470 | }, 471 | opcode.Opcode.LD_C_n => { 472 | // LD C,n 473 | self.registers.setC(try self.stream.readByte()); 474 | }, 475 | opcode.Opcode.RRCA => { 476 | // RRCA 477 | self.registers.setA(self.rrc(self.registers.a())); 478 | }, 479 | opcode.Opcode.STOP_FIRST_BYTE => { 480 | // STOP 481 | switch (try self.stream.readByte()) { 482 | 0x00 => { 483 | return Mode.Stop; 484 | }, 485 | else => { 486 | unreachable; 487 | }, 488 | } 489 | }, 490 | opcode.Opcode.LD_DE_nn => { 491 | // LD DE,nn 492 | self.registers.de = try self.stream.readIntLittle(u16); 493 | }, 494 | opcode.Opcode.LD_DE_A => { 495 | // LD (DE),A 496 | self.memory.set(self.registers.de, self.registers.a()); 497 | }, 498 | opcode.Opcode.INC_DE => { 499 | // INC DE 500 | self.registers.de = self.add(u16, self.registers.de, 1); 501 | }, 502 | opcode.Opcode.INC_D => { 503 | // INC D 504 | self.registers.setD(self.add(u8, self.registers.d(), 1)); 505 | }, 506 | opcode.Opcode.DEC_D => { 507 | // DEC D 508 | self.registers.setD(self.sub(self.registers.d(), 1)); 509 | }, 510 | opcode.Opcode.LD_D_n => { 511 | // LD D,n 512 | self.registers.setD(try self.stream.readByte()); 513 | }, 514 | opcode.Opcode.RLA => { 515 | // RLA 516 | self.registers.setA(self.rl(self.registers.a())); 517 | }, 518 | opcode.Opcode.JR_n => { 519 | // JR 520 | const n = try self.stream.readByteSigned(); 521 | self.jumpRelative(n); 522 | }, 523 | opcode.Opcode.ADD_HL_DE => { 524 | // ADD HL,DE 525 | self.registers.hl = self.add(u16, self.registers.hl, self.registers.de); 526 | }, 527 | opcode.Opcode.LD_A_DE => { 528 | // LD A,(DE) 529 | self.registers.setA(self.memory.get(self.registers.de)); 530 | }, 531 | opcode.Opcode.DEC_DE => { 532 | // DEC DE 533 | self.registers.de -%= 1; 534 | }, 535 | opcode.Opcode.INC_E => { 536 | // INC E 537 | self.registers.setE(self.add(u8, self.registers.e(), 1)); 538 | }, 539 | opcode.Opcode.DEC_E => { 540 | // DEC E 541 | self.registers.setE(self.sub(self.registers.e(), 1)); 542 | }, 543 | opcode.Opcode.LD_E_n => { 544 | // LD E,n 545 | self.registers.setE(try self.stream.readByte()); 546 | }, 547 | opcode.Opcode.RRA => { 548 | // RRA 549 | self.registers.setA(self.rr(self.registers.a())); 550 | }, 551 | opcode.Opcode.JR_NZ_n => { 552 | // JR NZ,n 553 | const n = try self.stream.readByteSigned(); 554 | if (!self.registers.zeroFlag()) { 555 | self.jumpRelative(n); 556 | } 557 | }, 558 | opcode.Opcode.LD_HL_nn => { 559 | // LD HL,nn 560 | self.registers.hl = try self.stream.readIntLittle(u16); 561 | }, 562 | opcode.Opcode.LDI_HL_A => { 563 | // LDI (HL),A 564 | self.memory.set(self.registers.hl, self.registers.a()); 565 | self.registers.hl +%= 1; 566 | }, 567 | opcode.Opcode.INC_HL => { 568 | // INC HL 569 | self.registers.hl = self.add(u16, self.registers.hl, 1); 570 | }, 571 | opcode.Opcode.INC_H => { 572 | // INC H 573 | self.registers.setH(self.add(u8, self.registers.h(), 1)); 574 | }, 575 | opcode.Opcode.DEC_H => { 576 | // DEC H 577 | self.registers.setH(self.sub(self.registers.h(), 1)); 578 | }, 579 | opcode.Opcode.LD_H_n => { 580 | // LD H,n 581 | self.registers.setH(try self.stream.readByte()); 582 | }, 583 | opcode.Opcode.DAA => { 584 | // DAA 585 | var carry = false; 586 | if (!self.registers.subtractFlag()) { 587 | if (self.registers.carryFlag() or self.registers.a() > 0x99) { 588 | self.registers.setA(self.registers.a() +% 0x60); 589 | carry = true; 590 | } 591 | if (self.registers.halfCarryFlag() or (self.registers.a() & 0x0F) > 0x09) { 592 | self.registers.setA(self.registers.a() +% 0x06); 593 | } 594 | } else if (self.registers.carryFlag()) { 595 | carry = true; 596 | const adjustment = if (self.registers.halfCarryFlag()) u8(0x9A) else u8(0xA0); 597 | self.registers.setA(self.registers.a() +% adjustment); 598 | } else if (self.registers.halfCarryFlag()) { 599 | self.registers.setA(self.registers.a() +% 0xFA); 600 | } 601 | 602 | self.registers.setZeroFlag(self.registers.a() == 0); 603 | self.registers.setCarryFlag(carry); 604 | self.registers.setHalfCarryFlag(false); 605 | }, 606 | opcode.Opcode.JR_Z_n => { 607 | // JR Z,n 608 | const n = try self.stream.readByteSigned(); 609 | if (self.registers.zeroFlag()) { 610 | self.jumpRelative(n); 611 | } 612 | }, 613 | opcode.Opcode.ADD_HL_HL => { 614 | // ADD HL,HL 615 | self.registers.hl = self.add(u16, self.registers.hl, self.registers.hl); 616 | }, 617 | opcode.Opcode.LDI_A_HL => { 618 | // LDI A,(HL) 619 | self.registers.setA(self.memory.get(self.registers.hl)); 620 | self.registers.hl +%= 1; 621 | }, 622 | opcode.Opcode.DEC_HL => { 623 | // DEC HL 624 | self.registers.hl -%= 1; 625 | }, 626 | opcode.Opcode.INC_L => { 627 | // INC L 628 | self.registers.setL(self.add(u8, self.registers.l(), 1)); 629 | }, 630 | opcode.Opcode.DEC_L => { 631 | // DEC L 632 | self.registers.setL(self.sub(self.registers.l(), 1)); 633 | }, 634 | opcode.Opcode.LD_L_n => { 635 | // LD L,n 636 | self.registers.setL(try self.stream.readByte()); 637 | }, 638 | opcode.Opcode.CPL => { 639 | // CPL 640 | self.registers.setA(~self.registers.a()); 641 | self.registers.setSubtractFlag(true); 642 | self.registers.setHalfCarryFlag(true); 643 | }, 644 | opcode.Opcode.JR_NC_n => { 645 | // JR NC,n 646 | const n = try self.stream.readByteSigned(); 647 | if (!self.registers.carryFlag()) { 648 | self.jumpRelative(n); 649 | } 650 | }, 651 | opcode.Opcode.LD_SP_nn => { 652 | // LD SP,nn 653 | self.registers.sp = try self.stream.readIntLittle(u16); 654 | }, 655 | opcode.Opcode.LDD_HL_A => { 656 | // LDD (HL),A 657 | self.memory.set(self.registers.hl, self.registers.a()); 658 | self.registers.hl -%= 1; 659 | }, 660 | opcode.Opcode.INC_SP => { 661 | // INC SP 662 | self.registers.sp = self.add(u16, self.registers.sp, 1); 663 | }, 664 | opcode.Opcode.INC_mem_HL => { 665 | // INC (HL) 666 | self.memory.set(self.registers.hl, self.add(u8, self.memory.get(self.registers.hl), 1)); 667 | }, 668 | opcode.Opcode.DEC_mem_HL => { 669 | // DEC (HL) 670 | self.memory.set(self.registers.hl, self.sub(self.memory.get(self.registers.hl), 1)); 671 | }, 672 | opcode.Opcode.LD_HL_n => { 673 | // LD (HL),n 674 | self.memory.set(self.registers.hl, try self.stream.readByte()); 675 | }, 676 | opcode.Opcode.SCF => { 677 | // SCF 678 | self.registers.setSubtractFlag(false); 679 | self.registers.setHalfCarryFlag(false); 680 | self.registers.setCarryFlag(true); 681 | }, 682 | opcode.Opcode.JR_C_n => { 683 | // JR C,n 684 | const n = try self.stream.readByteSigned(); 685 | if (self.registers.carryFlag()) { 686 | self.jumpRelative(n); 687 | } 688 | }, 689 | opcode.Opcode.ADD_HL_SP => { 690 | // ADD HL,SP 691 | self.registers.hl = self.add(u16, self.registers.hl, self.registers.sp); 692 | }, 693 | opcode.Opcode.LDD_A_HL => { 694 | // LDD A,(HL) 695 | self.registers.setA(self.memory.get(self.registers.hl)); 696 | self.registers.hl -%= 1; 697 | }, 698 | opcode.Opcode.DEC_SP => { 699 | // DEC HL 700 | self.registers.hl -%= 1; 701 | }, 702 | opcode.Opcode.INC_A => { 703 | // INC A 704 | self.registers.setA(self.add(u8, self.registers.a(), 1)); 705 | }, 706 | opcode.Opcode.DEC_A => { 707 | // DEC A 708 | self.registers.setA(self.sub(self.registers.a(), 1)); 709 | }, 710 | opcode.Opcode.LD_A_n => { 711 | // LD A,n 712 | self.registers.setA(try self.stream.readByte()); 713 | }, 714 | opcode.Opcode.CCF => { 715 | // CCF 716 | self.registers.setSubtractFlag(false); 717 | self.registers.setHalfCarryFlag(false); 718 | self.registers.setCarryFlag(!self.registers.carryFlag()); 719 | }, 720 | opcode.Opcode.LD_B_B => { 721 | // LD B,B 722 | self.registers.setB(self.registers.b()); 723 | }, 724 | opcode.Opcode.LD_B_C => { 725 | // LD B,C 726 | self.registers.setB(self.registers.c()); 727 | }, 728 | opcode.Opcode.LD_B_D => { 729 | // LD B,D 730 | self.registers.setB(self.registers.d()); 731 | }, 732 | opcode.Opcode.LD_B_E => { 733 | // LD B,E 734 | self.registers.setB(self.registers.e()); 735 | }, 736 | opcode.Opcode.LD_B_H => { 737 | // LD B,H 738 | self.registers.setB(self.registers.h()); 739 | }, 740 | opcode.Opcode.LD_B_L => { 741 | // LD B,L 742 | self.registers.setB(self.registers.l()); 743 | }, 744 | opcode.Opcode.LD_B_HL => { 745 | // LD B,(HL) 746 | self.registers.setB(self.memory.get(self.registers.hl)); 747 | }, 748 | opcode.Opcode.LD_B_A => { 749 | // LD B,A 750 | self.registers.setB(self.registers.a()); 751 | }, 752 | opcode.Opcode.LD_C_B => { 753 | // LD C,B 754 | self.registers.setC(self.registers.b()); 755 | }, 756 | opcode.Opcode.LD_C_C => { 757 | // LD C,C 758 | self.registers.setC(self.registers.c()); 759 | }, 760 | opcode.Opcode.LD_C_D => { 761 | // LD C,D 762 | self.registers.setC(self.registers.d()); 763 | }, 764 | opcode.Opcode.LD_C_E => { 765 | // LD C,E 766 | self.registers.setC(self.registers.e()); 767 | }, 768 | opcode.Opcode.LD_C_H => { 769 | // LD C,H 770 | self.registers.setC(self.registers.h()); 771 | }, 772 | opcode.Opcode.LD_C_L => { 773 | // LD C,L 774 | self.registers.setC(self.registers.l()); 775 | }, 776 | opcode.Opcode.LD_C_HL => { 777 | // LD C,(HL) 778 | self.registers.setC(self.memory.get(self.registers.hl)); 779 | }, 780 | opcode.Opcode.LD_C_A => { 781 | // LD C,A 782 | self.registers.setC(self.registers.a()); 783 | }, 784 | opcode.Opcode.LD_D_B => { 785 | // LD D,B 786 | self.registers.setD(self.registers.b()); 787 | }, 788 | opcode.Opcode.LD_D_C => { 789 | // LD D,C 790 | self.registers.setD(self.registers.c()); 791 | }, 792 | opcode.Opcode.LD_D_D => { 793 | // LD D,D 794 | self.registers.setD(self.registers.d()); 795 | }, 796 | opcode.Opcode.LD_D_E => { 797 | // LD D,E 798 | self.registers.setD(self.registers.e()); 799 | }, 800 | opcode.Opcode.LD_D_H => { 801 | // LD D,H 802 | self.registers.setD(self.registers.h()); 803 | }, 804 | opcode.Opcode.LD_D_L => { 805 | // LD D,L 806 | self.registers.setD(self.registers.l()); 807 | }, 808 | opcode.Opcode.LD_D_HL => { 809 | // LD D,(HL) 810 | self.registers.setD(self.memory.get(self.registers.hl)); 811 | }, 812 | opcode.Opcode.LD_D_A => { 813 | // LD D,A 814 | self.registers.setD(self.registers.a()); 815 | }, 816 | opcode.Opcode.LD_E_B => { 817 | // LD E,B 818 | self.registers.setE(self.registers.b()); 819 | }, 820 | opcode.Opcode.LD_E_C => { 821 | // LD E,C 822 | self.registers.setE(self.registers.c()); 823 | }, 824 | opcode.Opcode.LD_E_D => { 825 | // LD E,D 826 | self.registers.setE(self.registers.d()); 827 | }, 828 | opcode.Opcode.LD_E_E => { 829 | // LD E,E 830 | self.registers.setE(self.registers.e()); 831 | }, 832 | opcode.Opcode.LD_E_H => { 833 | // LD E,H 834 | self.registers.setE(self.registers.h()); 835 | }, 836 | opcode.Opcode.LD_E_L => { 837 | // LD E,L 838 | self.registers.setE(self.registers.l()); 839 | }, 840 | opcode.Opcode.LD_E_HL => { 841 | // LD E,(HL) 842 | self.registers.setE(self.memory.get(self.registers.hl)); 843 | }, 844 | opcode.Opcode.LD_E_A => { 845 | // LD E,A 846 | self.registers.setE(self.registers.a()); 847 | }, 848 | opcode.Opcode.LD_H_B => { 849 | // LD H,B 850 | self.registers.setH(self.registers.b()); 851 | }, 852 | opcode.Opcode.LD_H_C => { 853 | // LD H,C 854 | self.registers.setH(self.registers.c()); 855 | }, 856 | opcode.Opcode.LD_H_D => { 857 | // LD H,D 858 | self.registers.setH(self.registers.d()); 859 | }, 860 | opcode.Opcode.LD_H_E => { 861 | // LD H,E 862 | self.registers.setH(self.registers.e()); 863 | }, 864 | opcode.Opcode.LD_H_H => { 865 | // LD H,H 866 | self.registers.setH(self.registers.h()); 867 | }, 868 | opcode.Opcode.LD_H_L => { 869 | // LD H,L 870 | self.registers.setH(self.registers.l()); 871 | }, 872 | opcode.Opcode.LD_H_HL => { 873 | // LD H,(HL) 874 | self.registers.setH(self.memory.get(self.registers.hl)); 875 | }, 876 | opcode.Opcode.LD_H_A => { 877 | // LD H,A 878 | self.registers.setH(self.registers.a()); 879 | }, 880 | opcode.Opcode.LD_L_B => { 881 | // LD L,B 882 | self.registers.setL(self.registers.b()); 883 | }, 884 | opcode.Opcode.LD_L_C => { 885 | // LD L,C 886 | self.registers.setL(self.registers.c()); 887 | }, 888 | opcode.Opcode.LD_L_D => { 889 | // LD L,D 890 | self.registers.setL(self.registers.d()); 891 | }, 892 | opcode.Opcode.LD_L_E => { 893 | // LD L,E 894 | self.registers.setL(self.registers.e()); 895 | }, 896 | opcode.Opcode.LD_L_H => { 897 | // LD L,H 898 | self.registers.setL(self.registers.h()); 899 | }, 900 | opcode.Opcode.LD_L_L => { 901 | // LD L,L 902 | self.registers.setL(self.registers.l()); 903 | }, 904 | opcode.Opcode.LD_L_HL => { 905 | // LD L,(HL) 906 | self.registers.setL(self.memory.get(self.registers.hl)); 907 | }, 908 | opcode.Opcode.LD_L_A => { 909 | // LD L,A 910 | self.registers.setL(self.registers.a()); 911 | }, 912 | opcode.Opcode.LD_HL_B => { 913 | // LD (HL),B 914 | self.memory.set(self.registers.hl, self.registers.b()); 915 | }, 916 | opcode.Opcode.LD_HL_C => { 917 | // LD (HL),C 918 | self.memory.set(self.registers.hl, self.registers.c()); 919 | }, 920 | opcode.Opcode.LD_HL_D => { 921 | // LD (HL),D 922 | self.memory.set(self.registers.hl, self.registers.d()); 923 | }, 924 | opcode.Opcode.LD_HL_E => { 925 | // LD (HL),E 926 | self.memory.set(self.registers.hl, self.registers.e()); 927 | }, 928 | opcode.Opcode.LD_HL_H => { 929 | // LD (HL),H 930 | self.memory.set(self.registers.hl, self.registers.h()); 931 | }, 932 | opcode.Opcode.LD_HL_L => { 933 | // LD (HL),L 934 | self.memory.set(self.registers.hl, self.registers.l()); 935 | }, 936 | opcode.Opcode.HALT => { 937 | // HALT 938 | return Mode.Halt; 939 | }, 940 | opcode.Opcode.LD_HL_A => { 941 | // LD (HL),A 942 | self.memory.set(self.registers.hl, self.registers.a()); 943 | }, 944 | opcode.Opcode.LD_A_B => { 945 | // LD A,B 946 | self.registers.setA(self.registers.b()); 947 | }, 948 | opcode.Opcode.LD_A_C => { 949 | // LD A,C 950 | self.registers.setA(self.registers.c()); 951 | }, 952 | opcode.Opcode.LD_A_D => { 953 | // LD A,D 954 | self.registers.setA(self.registers.d()); 955 | }, 956 | opcode.Opcode.LD_A_E => { 957 | // LD A,E 958 | self.registers.setA(self.registers.e()); 959 | }, 960 | opcode.Opcode.LD_A_H => { 961 | // LD A,H 962 | self.registers.setA(self.registers.h()); 963 | }, 964 | opcode.Opcode.LD_A_L => { 965 | // LD A,L 966 | self.registers.setA(self.registers.l()); 967 | }, 968 | opcode.Opcode.LD_A_HL => { 969 | // LD A,(HL) 970 | self.registers.setA(self.memory.get(self.registers.hl)); 971 | }, 972 | opcode.Opcode.ADD_A_B => { 973 | // ADD A,B 974 | self.registers.setA(self.add(u8, self.registers.a(), self.registers.b())); 975 | }, 976 | opcode.Opcode.ADD_A_C => { 977 | // ADD A,C 978 | self.registers.setA(self.add(u8, self.registers.a(), self.registers.c())); 979 | }, 980 | opcode.Opcode.ADD_A_D => { 981 | // ADD A,D 982 | self.registers.setA(self.add(u8, self.registers.a(), self.registers.d())); 983 | }, 984 | opcode.Opcode.ADD_A_E => { 985 | // ADD A,E 986 | self.registers.setA(self.add(u8, self.registers.a(), self.registers.e())); 987 | }, 988 | opcode.Opcode.ADD_A_H => { 989 | // ADD A,H 990 | self.registers.setA(self.add(u8, self.registers.a(), self.registers.h())); 991 | }, 992 | opcode.Opcode.ADD_A_L => { 993 | // ADD A,L 994 | self.registers.setA(self.add(u8, self.registers.a(), self.registers.l())); 995 | }, 996 | opcode.Opcode.ADD_A_HL => { 997 | // ADD A,(HL) 998 | self.registers.setA(self.add(u8, self.registers.a(), self.memory.get(self.registers.hl))); 999 | }, 1000 | opcode.Opcode.ADD_A_A => { 1001 | // ADD A,A 1002 | self.registers.setA(self.add(u8, self.registers.a(), self.registers.a())); 1003 | }, 1004 | opcode.Opcode.ADC_A_B => { 1005 | // ADC A,B 1006 | self.registers.setA(self.add(u8, self.registers.a(), self.registers.b() + @boolToInt(self.registers.carryFlag()))); 1007 | }, 1008 | opcode.Opcode.ADC_A_C => { 1009 | // ADC A,C 1010 | self.registers.setA(self.add(u8, self.registers.a(), self.registers.c() + @boolToInt(self.registers.carryFlag()))); 1011 | }, 1012 | opcode.Opcode.ADC_A_D => { 1013 | // ADC A,D 1014 | self.registers.setA(self.add(u8, self.registers.a(), self.registers.d() + @boolToInt(self.registers.carryFlag()))); 1015 | }, 1016 | opcode.Opcode.ADC_A_E => { 1017 | // ADC A,E 1018 | self.registers.setA(self.add(u8, self.registers.a(), self.registers.e() + @boolToInt(self.registers.carryFlag()))); 1019 | }, 1020 | opcode.Opcode.ADC_A_H => { 1021 | // ADC A,H 1022 | self.registers.setA(self.add(u8, self.registers.a(), self.registers.h() + @boolToInt(self.registers.carryFlag()))); 1023 | }, 1024 | opcode.Opcode.ADC_A_L => { 1025 | // ADC A,L 1026 | self.registers.setA(self.add(u8, self.registers.a(), self.registers.l() + @boolToInt(self.registers.carryFlag()))); 1027 | }, 1028 | opcode.Opcode.ADC_A_HL => { 1029 | // ADC A,(HL) 1030 | self.registers.setA(self.add(u8, self.registers.a(), self.memory.get(self.registers.hl) + @boolToInt(self.registers.carryFlag()))); 1031 | }, 1032 | opcode.Opcode.ADC_A_A => { 1033 | // ADC A,A 1034 | self.registers.setA(self.add(u8, self.registers.a(), self.registers.a() + @boolToInt(self.registers.carryFlag()))); 1035 | }, 1036 | opcode.Opcode.SUB_A_B => { 1037 | // SUB A,B 1038 | self.registers.setA(self.sub(self.registers.a(), self.registers.b())); 1039 | }, 1040 | opcode.Opcode.SUB_A_C => { 1041 | // SUB A,C 1042 | self.registers.setA(self.sub(self.registers.a(), self.registers.c())); 1043 | }, 1044 | opcode.Opcode.SUB_A_D => { 1045 | // SUB A,D 1046 | self.registers.setA(self.sub(self.registers.a(), self.registers.d())); 1047 | }, 1048 | opcode.Opcode.SUB_A_E => { 1049 | // SUB A,E 1050 | self.registers.setA(self.sub(self.registers.a(), self.registers.e())); 1051 | }, 1052 | opcode.Opcode.SUB_A_H => { 1053 | // SUB A,H 1054 | self.registers.setA(self.sub(self.registers.a(), self.registers.h())); 1055 | }, 1056 | opcode.Opcode.SUB_A_L => { 1057 | // SUB A,L 1058 | self.registers.setA(self.sub(self.registers.a(), self.registers.l())); 1059 | }, 1060 | opcode.Opcode.SUB_A_HL => { 1061 | // SUB A,(HL) 1062 | self.registers.setA(self.sub(self.registers.a(), self.memory.get(self.registers.hl))); 1063 | }, 1064 | opcode.Opcode.SUB_A_A => { 1065 | // SUB A,A 1066 | self.registers.setA(self.sub(self.registers.a(), self.registers.a())); 1067 | }, 1068 | opcode.Opcode.SBC_A_B => { 1069 | // SBC A,B 1070 | self.registers.setA(self.sub(self.registers.a(), self.registers.b() + @boolToInt(self.registers.carryFlag()))); 1071 | }, 1072 | opcode.Opcode.SBC_A_C => { 1073 | // SBC A,C 1074 | self.registers.setA(self.sub(self.registers.a(), self.registers.c() + @boolToInt(self.registers.carryFlag()))); 1075 | }, 1076 | opcode.Opcode.SBC_A_D => { 1077 | // SBC A,D 1078 | self.registers.setA(self.sub(self.registers.a(), self.registers.d() + @boolToInt(self.registers.carryFlag()))); 1079 | }, 1080 | opcode.Opcode.SBC_A_E => { 1081 | // SBC A,E 1082 | self.registers.setA(self.sub(self.registers.a(), self.registers.e() + @boolToInt(self.registers.carryFlag()))); 1083 | }, 1084 | opcode.Opcode.SBC_A_H => { 1085 | // SBC A,H 1086 | self.registers.setA(self.sub(self.registers.a(), self.registers.h() + @boolToInt(self.registers.carryFlag()))); 1087 | }, 1088 | opcode.Opcode.SBC_A_L => { 1089 | // SBC A,L 1090 | self.registers.setA(self.sub(self.registers.a(), self.registers.l() + @boolToInt(self.registers.carryFlag()))); 1091 | }, 1092 | opcode.Opcode.SBC_A_HL => { 1093 | // SBC A,(HL) 1094 | self.registers.setA(self.sub(self.registers.a(), self.memory.get(self.registers.hl) + @boolToInt(self.registers.carryFlag()))); 1095 | }, 1096 | opcode.Opcode.SBC_A_A => { 1097 | // SBC A,A 1098 | self.registers.setA(self.sub(self.registers.a(), self.registers.a() + @boolToInt(self.registers.carryFlag()))); 1099 | }, 1100 | opcode.Opcode.AND_A_B => { 1101 | // AND A,B 1102 | self.registers.setA(self.bitwiseAnd(self.registers.a(), self.registers.b())); 1103 | }, 1104 | opcode.Opcode.AND_A_C => { 1105 | // AND A,C 1106 | self.registers.setA(self.bitwiseAnd(self.registers.a(), self.registers.c())); 1107 | }, 1108 | opcode.Opcode.AND_A_D => { 1109 | // AND A,D 1110 | self.registers.setA(self.bitwiseAnd(self.registers.a(), self.registers.d())); 1111 | }, 1112 | opcode.Opcode.AND_A_E => { 1113 | // AND A,E 1114 | self.registers.setA(self.bitwiseAnd(self.registers.a(), self.registers.e())); 1115 | }, 1116 | opcode.Opcode.AND_A_H => { 1117 | // AND A,H 1118 | self.registers.setA(self.bitwiseAnd(self.registers.a(), self.registers.h())); 1119 | }, 1120 | opcode.Opcode.AND_A_L => { 1121 | // AND A,L 1122 | self.registers.setA(self.bitwiseAnd(self.registers.a(), self.registers.l())); 1123 | }, 1124 | opcode.Opcode.AND_A_HL => { 1125 | // AND A,(HL) 1126 | self.registers.setA(self.bitwiseAnd(self.registers.a(), self.memory.get(self.registers.hl))); 1127 | }, 1128 | opcode.Opcode.AND_A_A => { 1129 | // AND A,A 1130 | self.registers.setA(self.bitwiseAnd(self.registers.a(), self.registers.a())); 1131 | }, 1132 | opcode.Opcode.XOR_A_B => { 1133 | // XOR A,B 1134 | self.registers.setA(self.bitwiseXor(self.registers.a(), self.registers.b())); 1135 | }, 1136 | opcode.Opcode.XOR_A_C => { 1137 | // XOR A,C 1138 | self.registers.setA(self.bitwiseXor(self.registers.a(), self.registers.c())); 1139 | }, 1140 | opcode.Opcode.XOR_A_D => { 1141 | // XOR A,D 1142 | self.registers.setA(self.bitwiseXor(self.registers.a(), self.registers.d())); 1143 | }, 1144 | opcode.Opcode.XOR_A_E => { 1145 | // XOR A,E 1146 | self.registers.setA(self.bitwiseXor(self.registers.a(), self.registers.e())); 1147 | }, 1148 | opcode.Opcode.XOR_A_H => { 1149 | // XOR A,H 1150 | self.registers.setA(self.bitwiseXor(self.registers.a(), self.registers.h())); 1151 | }, 1152 | opcode.Opcode.XOR_A_L => { 1153 | // XOR A,L 1154 | self.registers.setA(self.bitwiseXor(self.registers.a(), self.registers.l())); 1155 | }, 1156 | opcode.Opcode.XOR_A_HL => { 1157 | // XOR A,(HL) 1158 | self.registers.setA(self.bitwiseXor(self.registers.a(), self.memory.get(self.registers.hl))); 1159 | }, 1160 | opcode.Opcode.XOR_A_A => { 1161 | // XOR A,A 1162 | self.registers.setA(self.bitwiseXor(self.registers.a(), self.registers.a())); 1163 | }, 1164 | opcode.Opcode.OR_A_B => { 1165 | // OR A,B 1166 | self.registers.setA(self.bitwiseOr(self.registers.a(), self.registers.b())); 1167 | }, 1168 | opcode.Opcode.OR_A_C => { 1169 | // OR A,C 1170 | self.registers.setA(self.bitwiseOr(self.registers.a(), self.registers.c())); 1171 | }, 1172 | opcode.Opcode.OR_A_D => { 1173 | // OR A,D 1174 | self.registers.setA(self.bitwiseOr(self.registers.a(), self.registers.d())); 1175 | }, 1176 | opcode.Opcode.OR_A_E => { 1177 | // OR A,E 1178 | self.registers.setA(self.bitwiseOr(self.registers.a(), self.registers.e())); 1179 | }, 1180 | opcode.Opcode.OR_A_H => { 1181 | // OR A,H 1182 | self.registers.setA(self.bitwiseOr(self.registers.a(), self.registers.h())); 1183 | }, 1184 | opcode.Opcode.OR_A_L => { 1185 | // OR A,L 1186 | self.registers.setA(self.bitwiseOr(self.registers.a(), self.registers.l())); 1187 | }, 1188 | opcode.Opcode.OR_A_HL => { 1189 | // OR A,(HL) 1190 | self.registers.setA(self.bitwiseOr(self.registers.a(), self.memory.get(self.registers.hl))); 1191 | }, 1192 | opcode.Opcode.OR_A_A => { 1193 | // OR A,A 1194 | self.registers.setA(self.bitwiseOr(self.registers.a(), self.registers.a())); 1195 | }, 1196 | opcode.Opcode.CP_A_B => { 1197 | // CP A,B 1198 | _ = self.sub(self.registers.a(), self.registers.b()); 1199 | }, 1200 | opcode.Opcode.CP_A_C => { 1201 | // CP A,C 1202 | _ = self.sub(self.registers.a(), self.registers.c()); 1203 | }, 1204 | opcode.Opcode.CP_A_D => { 1205 | // CP A,D 1206 | _ = self.sub(self.registers.a(), self.registers.d()); 1207 | }, 1208 | opcode.Opcode.CP_A_E => { 1209 | // CP A,E 1210 | _ = self.sub(self.registers.a(), self.registers.e()); 1211 | }, 1212 | opcode.Opcode.CP_A_H => { 1213 | // CP A,H 1214 | _ = self.sub(self.registers.a(), self.registers.h()); 1215 | }, 1216 | opcode.Opcode.CP_A_L => { 1217 | // CP A,B 1218 | _ = self.sub(self.registers.a(), self.registers.l()); 1219 | }, 1220 | opcode.Opcode.CP_A_HL => { 1221 | // CP A,B 1222 | _ = self.sub(self.registers.a(), self.memory.get(self.registers.hl)); 1223 | }, 1224 | opcode.Opcode.CP_A_A => { 1225 | // CP A,A 1226 | _ = self.sub(self.registers.a(), self.registers.a()); 1227 | }, 1228 | opcode.Opcode.RET_NZ => { 1229 | // RET NZ 1230 | if (!self.registers.zeroFlag()) { 1231 | self.registers.pc = self.pop(u16); 1232 | } 1233 | }, 1234 | opcode.Opcode.POP_BC => { 1235 | // POP BC 1236 | self.registers.bc = self.pop(u16); 1237 | }, 1238 | opcode.Opcode.JP_NZ_nn => { 1239 | // JP NZ,nn 1240 | const address = try self.stream.readIntLittle(u16); 1241 | if (!self.registers.zeroFlag()) { 1242 | self.registers.pc = address; 1243 | } 1244 | }, 1245 | opcode.Opcode.JP_nn => { 1246 | // JP 1247 | self.registers.pc = try self.stream.readIntLittle(u16); 1248 | }, 1249 | opcode.Opcode.CALL_NZ_nn => { 1250 | // CALL NZ,nn 1251 | if (!self.registers.zeroFlag()) { 1252 | self.call(try self.stream.readIntLittle(u16)); 1253 | } 1254 | }, 1255 | opcode.Opcode.PUSH_BC => { 1256 | // PUSH BC 1257 | self.push(self.registers.bc); 1258 | }, 1259 | opcode.Opcode.ADC_A_n => { 1260 | // ADD A,n 1261 | self.registers.setA(self.add(u8, self.registers.a(), try self.stream.readByte())); 1262 | }, 1263 | opcode.Opcode.RST_00, opcode.Opcode.RST_08, opcode.Opcode.RST_10, opcode.Opcode.RST_18, opcode.Opcode.RST_20, opcode.Opcode.RST_28, opcode.Opcode.RST_30, opcode.Opcode.RST_38 => |op| { 1264 | // RST n 1265 | self.registers.pc = switch (op) { 1266 | opcode.Opcode.RST_00 => u16(0x00), 1267 | opcode.Opcode.RST_08 => u16(0x08), 1268 | opcode.Opcode.RST_10 => u16(0x10), 1269 | opcode.Opcode.RST_18 => u16(0x18), 1270 | opcode.Opcode.RST_20 => u16(0x20), 1271 | opcode.Opcode.RST_28 => u16(0x28), 1272 | opcode.Opcode.RST_30 => u16(0x30), 1273 | opcode.Opcode.RST_38 => u16(0x38), 1274 | else => unreachable, 1275 | }; 1276 | }, 1277 | opcode.Opcode.RET_Z => { 1278 | // RET Z 1279 | if (self.registers.zeroFlag()) { 1280 | self.registers.pc = self.pop(u16); 1281 | } 1282 | }, 1283 | opcode.Opcode.RET => { 1284 | // RET 1285 | self.registers.pc = self.pop(u16); 1286 | }, 1287 | opcode.Opcode.JP_Z_nn => { 1288 | // JP Z,nn 1289 | const address = try self.stream.readIntLittle(u16); 1290 | if (self.registers.zeroFlag()) { 1291 | self.registers.pc = address; 1292 | } 1293 | }, 1294 | opcode.Opcode.MISC => { 1295 | switch (@intToEnum(opcode.MiscOpcode, try self.stream.readByte())) { 1296 | opcode.MiscOpcode.RLC_B => { 1297 | // RLC B 1298 | self.registers.setB(self.rlc(self.registers.b())); 1299 | }, 1300 | opcode.MiscOpcode.RLC_C => { 1301 | // RLC C 1302 | self.registers.setC(self.rlc(self.registers.c())); 1303 | }, 1304 | opcode.MiscOpcode.RLC_D => { 1305 | // RLC D 1306 | self.registers.setD(self.rlc(self.registers.d())); 1307 | }, 1308 | opcode.MiscOpcode.RLC_E => { 1309 | // RLC E 1310 | self.registers.setE(self.rlc(self.registers.e())); 1311 | }, 1312 | opcode.MiscOpcode.RLC_H => { 1313 | // RLC H 1314 | self.registers.setH(self.rlc(self.registers.h())); 1315 | }, 1316 | opcode.MiscOpcode.RLC_L => { 1317 | // RLC L 1318 | self.registers.setL(self.rlc(self.registers.l())); 1319 | }, 1320 | opcode.MiscOpcode.RLC_HL => { 1321 | // RLC (HL) 1322 | self.memory.set(self.registers.hl, self.rlc(self.memory.get(self.registers.hl))); 1323 | }, 1324 | opcode.MiscOpcode.RLC_A => { 1325 | // RLC A 1326 | self.registers.setA(self.rlc(self.registers.a())); 1327 | }, 1328 | opcode.MiscOpcode.RRC_B => { 1329 | // RRC B 1330 | self.registers.setB(self.rrc(self.registers.b())); 1331 | }, 1332 | opcode.MiscOpcode.RRC_C => { 1333 | // RRC C 1334 | self.registers.setC(self.rrc(self.registers.c())); 1335 | }, 1336 | opcode.MiscOpcode.RRC_D => { 1337 | // RRC D 1338 | self.registers.setD(self.rrc(self.registers.d())); 1339 | }, 1340 | opcode.MiscOpcode.RRC_E => { 1341 | // RRC E 1342 | self.registers.setE(self.rrc(self.registers.e())); 1343 | }, 1344 | opcode.MiscOpcode.RRC_H => { 1345 | // RRC H 1346 | self.registers.setH(self.rrc(self.registers.h())); 1347 | }, 1348 | opcode.MiscOpcode.RRC_L => { 1349 | // RRC L 1350 | self.registers.setL(self.rrc(self.registers.l())); 1351 | }, 1352 | opcode.MiscOpcode.RRC_HL => { 1353 | // RRC (HL) 1354 | self.memory.set(self.registers.hl, self.rrc(self.memory.get(self.registers.hl))); 1355 | }, 1356 | opcode.MiscOpcode.RRC_A => { 1357 | // RRC A 1358 | self.registers.setA(self.rrc(self.registers.a())); 1359 | }, 1360 | opcode.MiscOpcode.RL_B => { 1361 | // RL B 1362 | self.registers.setB(self.rl(self.registers.b())); 1363 | }, 1364 | opcode.MiscOpcode.RL_C => { 1365 | // RL C 1366 | self.registers.setC(self.rl(self.registers.c())); 1367 | }, 1368 | opcode.MiscOpcode.RL_D => { 1369 | // RL D 1370 | self.registers.setD(self.rl(self.registers.d())); 1371 | }, 1372 | opcode.MiscOpcode.RL_E => { 1373 | // RL E 1374 | self.registers.setE(self.rl(self.registers.e())); 1375 | }, 1376 | opcode.MiscOpcode.RL_H => { 1377 | // RL H 1378 | self.registers.setH(self.rl(self.registers.h())); 1379 | }, 1380 | opcode.MiscOpcode.RL_L => { 1381 | // RL L 1382 | self.registers.setL(self.rl(self.registers.l())); 1383 | }, 1384 | opcode.MiscOpcode.RL_HL => { 1385 | // RL (HL) 1386 | self.memory.set(self.registers.hl, self.rl(self.memory.get(self.registers.hl))); 1387 | }, 1388 | opcode.MiscOpcode.RL_A => { 1389 | // RL A 1390 | self.registers.setA(self.rl(self.registers.a())); 1391 | }, 1392 | opcode.MiscOpcode.RR_B => { 1393 | // RR B 1394 | self.registers.setB(self.rr(self.registers.b())); 1395 | }, 1396 | opcode.MiscOpcode.RR_C => { 1397 | // RR C 1398 | self.registers.setC(self.rr(self.registers.c())); 1399 | }, 1400 | opcode.MiscOpcode.RR_D => { 1401 | // RR D 1402 | self.registers.setD(self.rr(self.registers.d())); 1403 | }, 1404 | opcode.MiscOpcode.RR_E => { 1405 | // RR E 1406 | self.registers.setE(self.rr(self.registers.e())); 1407 | }, 1408 | opcode.MiscOpcode.RR_H => { 1409 | // RR H 1410 | self.registers.setH(self.rr(self.registers.h())); 1411 | }, 1412 | opcode.MiscOpcode.RR_L => { 1413 | // RR L 1414 | self.registers.setL(self.rr(self.registers.l())); 1415 | }, 1416 | opcode.MiscOpcode.RR_HL => { 1417 | // RR (HL) 1418 | self.memory.set(self.registers.hl, self.rr(self.memory.get(self.registers.hl))); 1419 | }, 1420 | opcode.MiscOpcode.RR_A => { 1421 | // RR A 1422 | self.registers.setA(self.rr(self.registers.a())); 1423 | }, 1424 | opcode.MiscOpcode.SLA_B => { 1425 | // SLA B 1426 | self.registers.setB(self.sla(self.registers.b())); 1427 | }, 1428 | opcode.MiscOpcode.SLA_C => { 1429 | // SLA C 1430 | self.registers.setC(self.sla(self.registers.c())); 1431 | }, 1432 | opcode.MiscOpcode.SLA_D => { 1433 | // SLA D 1434 | self.registers.setD(self.sla(self.registers.d())); 1435 | }, 1436 | opcode.MiscOpcode.SLA_E => { 1437 | // SLA E 1438 | self.registers.setE(self.sla(self.registers.e())); 1439 | }, 1440 | opcode.MiscOpcode.SLA_H => { 1441 | // SLA H 1442 | self.registers.setH(self.sla(self.registers.h())); 1443 | }, 1444 | opcode.MiscOpcode.SLA_L => { 1445 | // SLA L 1446 | self.registers.setL(self.sla(self.registers.l())); 1447 | }, 1448 | opcode.MiscOpcode.SLA_HL => { 1449 | // SLA (HL) 1450 | self.memory.set(self.registers.hl, self.sla(self.memory.get(self.registers.hl))); 1451 | }, 1452 | opcode.MiscOpcode.SLA_A => { 1453 | // SLA A 1454 | self.registers.setA(self.sla(self.registers.a())); 1455 | }, 1456 | opcode.MiscOpcode.SRA_B => { 1457 | // SRA B 1458 | self.registers.setB(self.sra(self.registers.b())); 1459 | }, 1460 | opcode.MiscOpcode.SRA_C => { 1461 | // SRA C 1462 | self.registers.setC(self.sra(self.registers.c())); 1463 | }, 1464 | opcode.MiscOpcode.SRA_D => { 1465 | // SRA D 1466 | self.registers.setD(self.sra(self.registers.d())); 1467 | }, 1468 | opcode.MiscOpcode.SRA_E => { 1469 | // SRA E 1470 | self.registers.setE(self.sra(self.registers.e())); 1471 | }, 1472 | opcode.MiscOpcode.SRA_H => { 1473 | // SRA H 1474 | self.registers.setH(self.sra(self.registers.h())); 1475 | }, 1476 | opcode.MiscOpcode.SRA_L => { 1477 | // SRA L 1478 | self.registers.setL(self.sra(self.registers.l())); 1479 | }, 1480 | opcode.MiscOpcode.SRA_HL => { 1481 | // SRA (HL) 1482 | self.memory.set(self.registers.hl, self.sra(self.memory.get(self.registers.hl))); 1483 | }, 1484 | opcode.MiscOpcode.SRA_A => { 1485 | // SRA A 1486 | self.registers.setA(self.sra(self.registers.a())); 1487 | }, 1488 | opcode.MiscOpcode.SWAP_B => { 1489 | // SWAP B 1490 | self.registers.setB(self.swap(self.registers.b())); 1491 | }, 1492 | opcode.MiscOpcode.SWAP_C => { 1493 | // SWAP C 1494 | self.registers.setC(self.swap(self.registers.c())); 1495 | }, 1496 | opcode.MiscOpcode.SWAP_D => { 1497 | // SWAP D 1498 | self.registers.setD(self.swap(self.registers.d())); 1499 | }, 1500 | opcode.MiscOpcode.SWAP_E => { 1501 | // SWAP E 1502 | self.registers.setE(self.swap(self.registers.e())); 1503 | }, 1504 | opcode.MiscOpcode.SWAP_H => { 1505 | // SWAP H 1506 | self.registers.setH(self.swap(self.registers.h())); 1507 | }, 1508 | opcode.MiscOpcode.SWAP_L => { 1509 | // SWAP L 1510 | self.registers.setL(self.swap(self.registers.l())); 1511 | }, 1512 | opcode.MiscOpcode.SWAP_HL => { 1513 | // SWAP (HL) 1514 | self.memory.set(self.registers.hl, self.swap(self.memory.get(self.registers.hl))); 1515 | }, 1516 | opcode.MiscOpcode.SWAP_A => { 1517 | // SWAP A 1518 | self.registers.setA(self.swap(self.registers.a())); 1519 | }, 1520 | opcode.MiscOpcode.SRL_B => { 1521 | // SRL B 1522 | self.registers.setB(self.srl(self.registers.b())); 1523 | }, 1524 | opcode.MiscOpcode.SRL_C => { 1525 | // SRL C 1526 | self.registers.setC(self.srl(self.registers.c())); 1527 | }, 1528 | opcode.MiscOpcode.SRL_D => { 1529 | // SRL D 1530 | self.registers.setD(self.srl(self.registers.d())); 1531 | }, 1532 | opcode.MiscOpcode.SRL_E => { 1533 | // SRL E 1534 | self.registers.setE(self.srl(self.registers.e())); 1535 | }, 1536 | opcode.MiscOpcode.SRL_H => { 1537 | // SRL H 1538 | self.registers.setH(self.srl(self.registers.h())); 1539 | }, 1540 | opcode.MiscOpcode.SRL_L => { 1541 | // SRL L 1542 | self.registers.setL(self.srl(self.registers.l())); 1543 | }, 1544 | opcode.MiscOpcode.SRL_HL => { 1545 | // SRL (HL) 1546 | self.memory.set(self.registers.hl, self.srl(self.memory.get(self.registers.hl))); 1547 | }, 1548 | opcode.MiscOpcode.SRL_A => { 1549 | // SRL A 1550 | self.registers.setA(self.srl(self.registers.a())); 1551 | }, 1552 | opcode.MiscOpcode.BIT_B => { 1553 | // BIT n,B 1554 | self.testBit(self.registers.b(), try self.stream.readByte()); 1555 | }, 1556 | opcode.MiscOpcode.BIT_C => { 1557 | // BIT n,C 1558 | self.testBit(self.registers.c(), try self.stream.readByte()); 1559 | }, 1560 | opcode.MiscOpcode.BIT_D => { 1561 | // BIT n,D 1562 | self.testBit(self.registers.d(), try self.stream.readByte()); 1563 | }, 1564 | opcode.MiscOpcode.BIT_E => { 1565 | // BIT n,E 1566 | self.testBit(self.registers.e(), try self.stream.readByte()); 1567 | }, 1568 | opcode.MiscOpcode.BIT_H => { 1569 | // BIT n,H 1570 | self.testBit(self.registers.h(), try self.stream.readByte()); 1571 | }, 1572 | opcode.MiscOpcode.BIT_L => { 1573 | // BIT n,L 1574 | self.testBit(self.registers.l(), try self.stream.readByte()); 1575 | }, 1576 | opcode.MiscOpcode.BIT_HL => { 1577 | // BIT n,(HL) 1578 | self.testBit(self.memory.get(self.registers.hl), try self.stream.readByte()); 1579 | }, 1580 | opcode.MiscOpcode.BIT_A => { 1581 | // BIT n,A 1582 | self.testBit(self.registers.a(), try self.stream.readByte()); 1583 | }, 1584 | opcode.MiscOpcode.RES_B => { 1585 | // RES n,B 1586 | self.registers.setB(self.registers.b() & ~(u8(1) << @truncate(u3, try self.stream.readByte()))); 1587 | }, 1588 | opcode.MiscOpcode.RES_C => { 1589 | // RES n,C 1590 | self.registers.setC(self.registers.c() & ~(u8(1) << @truncate(u3, try self.stream.readByte()))); 1591 | }, 1592 | opcode.MiscOpcode.RES_D => { 1593 | // RES n,D 1594 | self.registers.setD(self.registers.d() & ~(u8(1) << @truncate(u3, try self.stream.readByte()))); 1595 | }, 1596 | opcode.MiscOpcode.RES_E => { 1597 | // RES n,E 1598 | self.registers.setE(self.registers.e() & ~(u8(1) << @truncate(u3, try self.stream.readByte()))); 1599 | }, 1600 | opcode.MiscOpcode.RES_H => { 1601 | // RES n,H 1602 | self.registers.setH(self.registers.h() & ~(u8(1) << @truncate(u3, try self.stream.readByte()))); 1603 | }, 1604 | opcode.MiscOpcode.RES_L => { 1605 | // RES n,L 1606 | self.registers.setL(self.registers.l() & ~(u8(1) << @truncate(u3, try self.stream.readByte()))); 1607 | }, 1608 | opcode.MiscOpcode.RES_HL => { 1609 | // RES n,(HL) 1610 | self.memory.set(self.registers.hl, self.memory.get(self.registers.hl) & ~(u8(1) << @truncate(u3, try self.stream.readByte()))); 1611 | }, 1612 | opcode.MiscOpcode.RES_A => { 1613 | // RES n,A 1614 | self.registers.setA(self.registers.a() & ~(u8(1) << @truncate(u3, try self.stream.readByte()))); 1615 | }, 1616 | opcode.MiscOpcode.SET_B => { 1617 | // SET n,B 1618 | self.registers.setB(self.registers.b() | (u8(1) << @truncate(u3, try self.stream.readByte()))); 1619 | }, 1620 | opcode.MiscOpcode.SET_C => { 1621 | // SET n,C 1622 | self.registers.setC(self.registers.c() | (u8(1) << @truncate(u3, try self.stream.readByte()))); 1623 | }, 1624 | opcode.MiscOpcode.SET_D => { 1625 | // SET n,D 1626 | self.registers.setD(self.registers.d() | (u8(1) << @truncate(u3, try self.stream.readByte()))); 1627 | }, 1628 | opcode.MiscOpcode.SET_E => { 1629 | // SET n,E 1630 | self.registers.setE(self.registers.e() | (u8(1) << @truncate(u3, try self.stream.readByte()))); 1631 | }, 1632 | opcode.MiscOpcode.SET_H => { 1633 | // SET n,H 1634 | self.registers.setH(self.registers.h() | (u8(1) << @truncate(u3, try self.stream.readByte()))); 1635 | }, 1636 | opcode.MiscOpcode.SET_L => { 1637 | // SET n,L 1638 | self.registers.setL(self.registers.l() | (u8(1) << @truncate(u3, try self.stream.readByte()))); 1639 | }, 1640 | opcode.MiscOpcode.SET_HL => { 1641 | // SET n,(HL) 1642 | self.memory.set(self.registers.hl, self.memory.get(self.registers.hl) | (u8(1) << @truncate(u3, try self.stream.readByte()))); 1643 | }, 1644 | opcode.MiscOpcode.SET_A => { 1645 | // SET n,A 1646 | self.registers.setA(self.registers.a() | (u8(1) << @truncate(u3, try self.stream.readByte()))); 1647 | }, 1648 | else => { 1649 | unreachable; 1650 | }, 1651 | } 1652 | }, 1653 | opcode.Opcode.CALL_Z_nn => { 1654 | // CALL Z,nn 1655 | if (self.registers.zeroFlag()) { 1656 | self.call(try self.stream.readIntLittle(u16)); 1657 | } 1658 | }, 1659 | opcode.Opcode.CALL_nn => { 1660 | // CALL nn 1661 | self.call(try self.stream.readIntLittle(u16)); 1662 | }, 1663 | opcode.Opcode.ADD_A_n => { 1664 | // ADC A,n 1665 | self.registers.setA(self.add(u8, self.registers.a(), (try self.stream.readByte()) + @boolToInt(self.registers.carryFlag()))); 1666 | }, 1667 | opcode.Opcode.RET_NC => { 1668 | // RET NC 1669 | if (!self.registers.carryFlag()) { 1670 | self.registers.pc = self.pop(u16); 1671 | } 1672 | }, 1673 | opcode.Opcode.POP_DE => { 1674 | // POP DE 1675 | self.registers.de = self.pop(u16); 1676 | }, 1677 | opcode.Opcode.JP_NC_nn => { 1678 | // JP NC,nn 1679 | const address = try self.stream.readIntLittle(u16); 1680 | if (!self.registers.carryFlag()) { 1681 | self.registers.pc = address; 1682 | } 1683 | }, 1684 | opcode.Opcode.CALL_NC_nn => { 1685 | // CALL NC,nn 1686 | if (!self.registers.carryFlag()) { 1687 | self.call(try self.stream.readIntLittle(u16)); 1688 | } 1689 | }, 1690 | opcode.Opcode.PUSH_DE => { 1691 | // PUSH DE 1692 | self.push(self.registers.de); 1693 | }, 1694 | opcode.Opcode.SBC_A_n => { 1695 | // SUB A,n 1696 | self.registers.setA(self.sub(self.registers.a(), try self.stream.readByte())); 1697 | }, 1698 | opcode.Opcode.RET_C => { 1699 | // RET C 1700 | if (self.registers.carryFlag()) { 1701 | self.registers.pc = self.pop(u16); 1702 | } 1703 | }, 1704 | opcode.Opcode.RETI => { 1705 | // RETI 1706 | self.registers.pc = self.pop(u16); 1707 | return Mode.EnableInterrupts; 1708 | }, 1709 | opcode.Opcode.JP_C_nn => { 1710 | // JP C,nn 1711 | const address = try self.stream.readIntLittle(u16); 1712 | if (self.registers.carryFlag()) { 1713 | self.registers.pc = address; 1714 | } 1715 | }, 1716 | opcode.Opcode.CALL_C_nn => { 1717 | // CALL C,nn 1718 | if (self.registers.carryFlag()) { 1719 | self.call(try self.stream.readIntLittle(u16)); 1720 | } 1721 | }, 1722 | opcode.Opcode.SUB_A_n => { 1723 | // SBC A,n 1724 | self.registers.setA(self.sub(self.registers.a(), (try self.stream.readByte()) + @boolToInt(self.registers.carryFlag()))); 1725 | }, 1726 | opcode.Opcode.LDH_n_A => { 1727 | // LDH ($FF00+n),A 1728 | self.memory.set(0xFF00 | u16(try self.stream.readByte()), self.registers.a()); 1729 | }, 1730 | opcode.Opcode.POP_HL => { 1731 | // POP HL 1732 | self.registers.hl = self.pop(u16); 1733 | }, 1734 | opcode.Opcode.LD_mem_C_A => { 1735 | // LD ($FF00+C),A 1736 | self.memory.set(0xFF00 | u16(self.registers.c()), self.registers.a()); 1737 | }, 1738 | opcode.Opcode.PUSH_HL => { 1739 | // PUSH HL 1740 | self.push(self.registers.hl); 1741 | }, 1742 | opcode.Opcode.AND_A_n => { 1743 | // AND A,n 1744 | self.registers.setA(self.bitwiseAnd(self.registers.a(), try self.stream.readByte())); 1745 | }, 1746 | opcode.Opcode.ADD_SP_n => { 1747 | // ADD SP,n 1748 | self.registers.sp = self.add(u16, self.registers.sp, try self.stream.readByte()); 1749 | }, 1750 | opcode.Opcode.JP_HL => { 1751 | // JP (HL) 1752 | self.registers.pc = self.memory.get(self.registers.hl); 1753 | }, 1754 | opcode.Opcode.LD_nn_A => { 1755 | // LD (nn),A 1756 | self.memory.set(try self.stream.readIntLittle(u16), self.registers.a()); 1757 | }, 1758 | opcode.Opcode.XOR_A_n => { 1759 | // XOR A,n 1760 | self.registers.setA(self.bitwiseXor(self.registers.a(), try self.stream.readByte())); 1761 | }, 1762 | opcode.Opcode.LDH_A_n => { 1763 | // LDH A,($FF00+n) 1764 | self.registers.setA(self.memory.get(0xFF00 | u16(try self.stream.readByte()))); 1765 | }, 1766 | opcode.Opcode.POP_AF => { 1767 | // POP AF 1768 | self.registers.af = self.pop(u16); 1769 | }, 1770 | opcode.Opcode.LD_A_mem_C => { 1771 | // LD A,($FF00+C) 1772 | self.registers.setA(self.memory.get(u16(0xFF00) | self.registers.c())); 1773 | }, 1774 | opcode.Opcode.DI => { 1775 | // DI 1776 | return Mode.DisableInterrupts; 1777 | }, 1778 | opcode.Opcode.PUSH_AF => { 1779 | // PUSH AF 1780 | self.push(self.registers.af); 1781 | }, 1782 | opcode.Opcode.OR_A_n => { 1783 | // OR A,n 1784 | self.registers.setA(self.bitwiseOr(self.registers.a(), try self.stream.readByte())); 1785 | }, 1786 | opcode.Opcode.LDHL_SP_n => { 1787 | // LDHL SP,n 1788 | const n = try self.stream.readByte(); 1789 | self.registers.hl = self.add(u8, @truncate(u8, self.registers.sp), n); 1790 | }, 1791 | opcode.Opcode.LD_SP_HL => { 1792 | // LD SP,HL 1793 | self.registers.sp = self.registers.hl; 1794 | }, 1795 | opcode.Opcode.LD_A_nn => { 1796 | // LD A,(HL) 1797 | const address = try self.stream.readIntLittle(u16); 1798 | self.registers.setA(self.memory.get(address)); 1799 | }, 1800 | opcode.Opcode.EI => { 1801 | return Mode.EnableInterrupts; 1802 | }, 1803 | opcode.Opcode.CP_A_n => { 1804 | // CP A,n 1805 | _ = self.sub(self.registers.a(), try self.stream.readByte()); 1806 | }, 1807 | else => { 1808 | unreachable; 1809 | }, 1810 | } 1811 | return Mode.Default; 1812 | } 1813 | }; 1814 | 1815 | test "CPU" { 1816 | var cpu = try CPU.init(std.debug.global_allocator); 1817 | cpu.registers.pc = 0; 1818 | cpu.registers.hl = 0x55; 1819 | cpu.memory.set(0x0, 0x7E); 1820 | cpu.memory.set(0x55, 0x20); 1821 | _ = try cpu.execute(); 1822 | std.debug.assert(cpu.registers.a() == 0x20); 1823 | std.debug.assert(cpu.registers.pc == 1); 1824 | std.debug.assert(cpu.add(u8, 0x4, 0x6) == 0xA); 1825 | std.debug.assert(!cpu.registers.halfCarryFlag()); 1826 | std.debug.assert(cpu.add(u8, 0xA, 0x6) == 0x10); 1827 | std.debug.assert(cpu.registers.halfCarryFlag()); 1828 | cpu.deinit(); 1829 | } 1830 | -------------------------------------------------------------------------------- /src/disassembler.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | const opcode = @import("opcode.zig"); 4 | 5 | pub const Disassembler = struct { 6 | const InStream = std.io.InStream(std.os.File.ReadError); 7 | const OutStream = std.io.OutStream(std.os.File.WriteError); 8 | 9 | input: *InStream, 10 | output: *OutStream, 11 | buffer: ?u8, 12 | 13 | pub fn init(input: *InStream, output: *OutStream) Disassembler { 14 | return Disassembler{ 15 | .input = input, 16 | .output = output, 17 | .buffer = null, 18 | }; 19 | } 20 | 21 | pub fn disassemble(self: *Disassembler) !void { 22 | const byte = self.buffer orelse try self.input.readByte(); 23 | self.buffer = null; 24 | switch (byte) { 25 | @enumToInt(opcode.Opcode.NOP) => try self.output.print("nop\n"), 26 | @enumToInt(opcode.Opcode.LD_A_n) => try self.output.print("ld a,${x}\n", try self.input.readByte()), 27 | @enumToInt(opcode.Opcode.LD_B_n) => try self.output.print("ld b,${x}\n", try self.input.readByte()), 28 | @enumToInt(opcode.Opcode.LD_C_n) => try self.output.print("ld c,${x}\n", try self.input.readByte()), 29 | @enumToInt(opcode.Opcode.LD_D_n) => try self.output.print("ld d,${x}\n", try self.input.readByte()), 30 | @enumToInt(opcode.Opcode.LD_E_n) => try self.output.print("ld e,${x}\n", try self.input.readByte()), 31 | @enumToInt(opcode.Opcode.LD_H_n) => try self.output.print("ld h,${x}\n", try self.input.readByte()), 32 | @enumToInt(opcode.Opcode.LD_L_n) => try self.output.print("ld l,${x}\n", try self.input.readByte()), 33 | @enumToInt(opcode.Opcode.LD_A_A) => try self.output.print("ld a,a\n"), 34 | @enumToInt(opcode.Opcode.LD_A_B) => try self.output.print("ld a,b\n"), 35 | @enumToInt(opcode.Opcode.LD_A_C) => try self.output.print("ld a,c\n"), 36 | @enumToInt(opcode.Opcode.LD_A_D) => try self.output.print("ld a,d\n"), 37 | @enumToInt(opcode.Opcode.LD_A_E) => try self.output.print("ld a,e\n"), 38 | @enumToInt(opcode.Opcode.LD_A_H) => try self.output.print("ld a,h\n"), 39 | @enumToInt(opcode.Opcode.LD_A_L) => try self.output.print("ld a,l\n"), 40 | @enumToInt(opcode.Opcode.LD_A_HL) => try self.output.print("ld a,(hl)\n"), 41 | @enumToInt(opcode.Opcode.LD_B_B) => try self.output.print("ld b,b\n"), 42 | @enumToInt(opcode.Opcode.LD_B_C) => try self.output.print("ld b,c\n"), 43 | @enumToInt(opcode.Opcode.LD_B_D) => try self.output.print("ld b,d\n"), 44 | @enumToInt(opcode.Opcode.LD_B_E) => try self.output.print("ld b,e\n"), 45 | @enumToInt(opcode.Opcode.LD_B_H) => try self.output.print("ld b,h\n"), 46 | @enumToInt(opcode.Opcode.LD_B_L) => try self.output.print("ld b,l\n"), 47 | @enumToInt(opcode.Opcode.LD_B_HL) => try self.output.print("ld b,(hl)\n"), 48 | @enumToInt(opcode.Opcode.LD_C_B) => try self.output.print("ld c,b\n"), 49 | @enumToInt(opcode.Opcode.LD_C_C) => try self.output.print("ld c,c\n"), 50 | @enumToInt(opcode.Opcode.LD_C_D) => try self.output.print("ld c,d\n"), 51 | @enumToInt(opcode.Opcode.LD_C_E) => try self.output.print("ld c,e\n"), 52 | @enumToInt(opcode.Opcode.LD_C_H) => try self.output.print("ld c,h\n"), 53 | @enumToInt(opcode.Opcode.LD_C_L) => try self.output.print("ld c,l\n"), 54 | @enumToInt(opcode.Opcode.LD_C_HL) => try self.output.print("ld c,(hl)\n"), 55 | @enumToInt(opcode.Opcode.LD_D_B) => try self.output.print("ld d,b\n"), 56 | @enumToInt(opcode.Opcode.LD_D_C) => try self.output.print("ld d,c\n"), 57 | @enumToInt(opcode.Opcode.LD_D_D) => try self.output.print("ld d,d\n"), 58 | @enumToInt(opcode.Opcode.LD_D_E) => try self.output.print("ld d,e\n"), 59 | @enumToInt(opcode.Opcode.LD_D_H) => try self.output.print("ld d,h\n"), 60 | @enumToInt(opcode.Opcode.LD_D_L) => try self.output.print("ld d,l\n"), 61 | @enumToInt(opcode.Opcode.LD_D_HL) => try self.output.print("ld d,(hl)\n"), 62 | @enumToInt(opcode.Opcode.LD_E_B) => try self.output.print("ld e,b\n"), 63 | @enumToInt(opcode.Opcode.LD_E_C) => try self.output.print("ld e,c\n"), 64 | @enumToInt(opcode.Opcode.LD_E_D) => try self.output.print("ld e,d\n"), 65 | @enumToInt(opcode.Opcode.LD_E_E) => try self.output.print("ld e,e\n"), 66 | @enumToInt(opcode.Opcode.LD_E_H) => try self.output.print("ld e,h\n"), 67 | @enumToInt(opcode.Opcode.LD_E_L) => try self.output.print("ld e,l\n"), 68 | @enumToInt(opcode.Opcode.LD_E_HL) => try self.output.print("ld e,(hl)\n"), 69 | @enumToInt(opcode.Opcode.LD_H_B) => try self.output.print("ld h,b\n"), 70 | @enumToInt(opcode.Opcode.LD_H_C) => try self.output.print("ld h,c\n"), 71 | @enumToInt(opcode.Opcode.LD_H_D) => try self.output.print("ld h,d\n"), 72 | @enumToInt(opcode.Opcode.LD_H_E) => try self.output.print("ld h,e\n"), 73 | @enumToInt(opcode.Opcode.LD_H_H) => try self.output.print("ld h,h\n"), 74 | @enumToInt(opcode.Opcode.LD_H_L) => try self.output.print("ld h,l\n"), 75 | @enumToInt(opcode.Opcode.LD_H_HL) => try self.output.print("ld h,(hl)\n"), 76 | @enumToInt(opcode.Opcode.LD_L_B) => try self.output.print("ld l,b\n"), 77 | @enumToInt(opcode.Opcode.LD_L_C) => try self.output.print("ld l,c\n"), 78 | @enumToInt(opcode.Opcode.LD_L_D) => try self.output.print("ld l,d\n"), 79 | @enumToInt(opcode.Opcode.LD_L_E) => try self.output.print("ld l,e\n"), 80 | @enumToInt(opcode.Opcode.LD_L_H) => try self.output.print("ld l,h\n"), 81 | @enumToInt(opcode.Opcode.LD_L_L) => try self.output.print("ld l,l\n"), 82 | @enumToInt(opcode.Opcode.LD_L_HL) => try self.output.print("ld l,(hl)\n"), 83 | @enumToInt(opcode.Opcode.LD_HL_B) => try self.output.print("ld (hl),b\n"), 84 | @enumToInt(opcode.Opcode.LD_HL_C) => try self.output.print("ld (hl),c\n"), 85 | @enumToInt(opcode.Opcode.LD_HL_D) => try self.output.print("ld (hl),d\n"), 86 | @enumToInt(opcode.Opcode.LD_HL_E) => try self.output.print("ld (hl),e\n"), 87 | @enumToInt(opcode.Opcode.LD_HL_H) => try self.output.print("ld (hl),h\n"), 88 | @enumToInt(opcode.Opcode.LD_HL_L) => try self.output.print("ld (hl),l\n"), 89 | @enumToInt(opcode.Opcode.LD_HL_n) => try self.output.print("ld (hl),${x}\n", try self.input.readByte()), 90 | @enumToInt(opcode.Opcode.LD_A_BC) => try self.output.print("ld a,(bc)\n"), 91 | @enumToInt(opcode.Opcode.LD_A_DE) => try self.output.print("ld a,(de)\n"), 92 | @enumToInt(opcode.Opcode.LD_A_nn) => try self.output.print("ld a,(${x})\n", try self.input.readIntLittle(u16)), 93 | @enumToInt(opcode.Opcode.LD_B_A) => try self.output.print("ld b,a\n"), 94 | @enumToInt(opcode.Opcode.LD_C_A) => try self.output.print("ld c,a\n"), 95 | @enumToInt(opcode.Opcode.LD_D_A) => try self.output.print("ld d,a\n"), 96 | @enumToInt(opcode.Opcode.LD_E_A) => try self.output.print("ld e,a\n"), 97 | @enumToInt(opcode.Opcode.LD_H_A) => try self.output.print("ld h,a\n"), 98 | @enumToInt(opcode.Opcode.LD_L_A) => try self.output.print("ld l,a\n"), 99 | @enumToInt(opcode.Opcode.LD_BC_A) => try self.output.print("ld (bc),a\n"), 100 | @enumToInt(opcode.Opcode.LD_DE_A) => try self.output.print("ld (de),a\n"), 101 | @enumToInt(opcode.Opcode.LD_HL_A) => try self.output.print("ld (hl),a\n"), 102 | @enumToInt(opcode.Opcode.LD_nn_A) => try self.output.print("ld (${x}),a\n", try self.input.readIntLittle(u16)), 103 | @enumToInt(opcode.Opcode.LD_A_mem_C) => try self.output.print("ld a,($FF00 + c)\n"), 104 | @enumToInt(opcode.Opcode.LD_mem_C_A) => try self.output.print("ld ($FF00 + c),a\n"), 105 | @enumToInt(opcode.Opcode.LDD_A_HL) => try self.output.print("ldd a,(hl)\n"), 106 | @enumToInt(opcode.Opcode.LDD_HL_A) => try self.output.print("ldd (hl),a\n"), 107 | @enumToInt(opcode.Opcode.LDI_A_HL) => try self.output.print("ldi a,(hl)\n"), 108 | @enumToInt(opcode.Opcode.LDI_HL_A) => try self.output.print("ldi (hl),a\n"), 109 | @enumToInt(opcode.Opcode.LDH_n_A) => try self.output.print("ld ${x},a\n", u16(0xFF00) | try self.input.readByte()), 110 | @enumToInt(opcode.Opcode.LDH_A_n) => try self.output.print("ld a,${x}\n", try self.input.readByte()), 111 | @enumToInt(opcode.Opcode.LD_BC_nn) => try self.output.print("ld bc,${x}\n", try self.input.readIntLittle(u16)), 112 | @enumToInt(opcode.Opcode.LD_DE_nn) => try self.output.print("ld de,${x}\n", try self.input.readIntLittle(u16)), 113 | @enumToInt(opcode.Opcode.LD_HL_nn) => try self.output.print("ld hl,${x}\n", try self.input.readIntLittle(u16)), 114 | @enumToInt(opcode.Opcode.LD_SP_nn) => try self.output.print("ld sp,${x}\n", try self.input.readIntLittle(u16)), 115 | @enumToInt(opcode.Opcode.LD_SP_HL) => try self.output.print("ld sp,hl\n"), 116 | @enumToInt(opcode.Opcode.LDHL_SP_n) => try self.output.print("ld hl,sp+${x}\n", try self.input.readByteSigned()), 117 | @enumToInt(opcode.Opcode.LD_nn_SP) => try self.output.print("ld (${x}),sp\n", try self.input.readIntLittle(u16)), 118 | @enumToInt(opcode.Opcode.PUSH_AF) => try self.output.print("push af\n"), 119 | @enumToInt(opcode.Opcode.PUSH_BC) => try self.output.print("push bc\n"), 120 | @enumToInt(opcode.Opcode.PUSH_DE) => try self.output.print("push de\n"), 121 | @enumToInt(opcode.Opcode.PUSH_HL) => try self.output.print("push hl\n"), 122 | @enumToInt(opcode.Opcode.POP_AF) => try self.output.print("pop af\n"), 123 | @enumToInt(opcode.Opcode.POP_BC) => try self.output.print("pop bc\n"), 124 | @enumToInt(opcode.Opcode.POP_DE) => try self.output.print("pop de\n"), 125 | @enumToInt(opcode.Opcode.POP_HL) => try self.output.print("pop hl\n"), 126 | @enumToInt(opcode.Opcode.ADD_A_A) => try self.output.print("add a,a\n"), 127 | @enumToInt(opcode.Opcode.ADD_A_B) => try self.output.print("add a,b\n"), 128 | @enumToInt(opcode.Opcode.ADD_A_C) => try self.output.print("add a,c\n"), 129 | @enumToInt(opcode.Opcode.ADD_A_D) => try self.output.print("add a,d\n"), 130 | @enumToInt(opcode.Opcode.ADD_A_E) => try self.output.print("add a,e\n"), 131 | @enumToInt(opcode.Opcode.ADD_A_H) => try self.output.print("add a,h\n"), 132 | @enumToInt(opcode.Opcode.ADD_A_L) => try self.output.print("add a,l\n"), 133 | @enumToInt(opcode.Opcode.ADD_A_HL) => try self.output.print("add a,(hl)\n"), 134 | @enumToInt(opcode.Opcode.ADD_A_n) => try self.output.print("add a,${x}\n", try self.input.readByte()), 135 | @enumToInt(opcode.Opcode.ADC_A_A) => try self.output.print("adc a,a\n"), 136 | @enumToInt(opcode.Opcode.ADC_A_B) => try self.output.print("adc a,b\n"), 137 | @enumToInt(opcode.Opcode.ADC_A_C) => try self.output.print("adc a,c\n"), 138 | @enumToInt(opcode.Opcode.ADC_A_D) => try self.output.print("adc a,d\n"), 139 | @enumToInt(opcode.Opcode.ADC_A_E) => try self.output.print("adc a,e\n"), 140 | @enumToInt(opcode.Opcode.ADC_A_H) => try self.output.print("adc a,h\n"), 141 | @enumToInt(opcode.Opcode.ADC_A_L) => try self.output.print("adc a,l\n"), 142 | @enumToInt(opcode.Opcode.ADC_A_HL) => try self.output.print("adc a,(hl)\n"), 143 | @enumToInt(opcode.Opcode.ADC_A_n) => try self.output.print("adc a,${x}\n", try self.input.readByte()), 144 | @enumToInt(opcode.Opcode.SUB_A_A) => try self.output.print("sub a,a\n"), 145 | @enumToInt(opcode.Opcode.SUB_A_B) => try self.output.print("sub a,b\n"), 146 | @enumToInt(opcode.Opcode.SUB_A_C) => try self.output.print("sub a,c\n"), 147 | @enumToInt(opcode.Opcode.SUB_A_D) => try self.output.print("sub a,d\n"), 148 | @enumToInt(opcode.Opcode.SUB_A_E) => try self.output.print("sub a,e\n"), 149 | @enumToInt(opcode.Opcode.SUB_A_H) => try self.output.print("sub a,h\n"), 150 | @enumToInt(opcode.Opcode.SUB_A_L) => try self.output.print("sub a,l\n"), 151 | @enumToInt(opcode.Opcode.SUB_A_HL) => try self.output.print("sub a,(hl)\n"), 152 | @enumToInt(opcode.Opcode.SUB_A_n) => try self.output.print("sub a,${x}\n", try self.input.readByte()), 153 | @enumToInt(opcode.Opcode.SBC_A_A) => try self.output.print("sbc a,a\n"), 154 | @enumToInt(opcode.Opcode.SBC_A_B) => try self.output.print("sbc a,b\n"), 155 | @enumToInt(opcode.Opcode.SBC_A_C) => try self.output.print("sbc a,c\n"), 156 | @enumToInt(opcode.Opcode.SBC_A_D) => try self.output.print("sbc a,d\n"), 157 | @enumToInt(opcode.Opcode.SBC_A_E) => try self.output.print("sbc a,e\n"), 158 | @enumToInt(opcode.Opcode.SBC_A_H) => try self.output.print("sbc a,h\n"), 159 | @enumToInt(opcode.Opcode.SBC_A_L) => try self.output.print("sbc a,l\n"), 160 | @enumToInt(opcode.Opcode.SBC_A_HL) => try self.output.print("sbc a,(hl)\n"), 161 | @enumToInt(opcode.Opcode.SBC_A_n) => try self.output.print("sbc a,${x}\n", try self.input.readByte()), 162 | @enumToInt(opcode.Opcode.AND_A_A) => try self.output.print("and a,a\n"), 163 | @enumToInt(opcode.Opcode.AND_A_B) => try self.output.print("and a,b\n"), 164 | @enumToInt(opcode.Opcode.AND_A_C) => try self.output.print("and a,c\n"), 165 | @enumToInt(opcode.Opcode.AND_A_D) => try self.output.print("and a,d\n"), 166 | @enumToInt(opcode.Opcode.AND_A_E) => try self.output.print("and a,e\n"), 167 | @enumToInt(opcode.Opcode.AND_A_H) => try self.output.print("and a,h\n"), 168 | @enumToInt(opcode.Opcode.AND_A_L) => try self.output.print("and a,l\n"), 169 | @enumToInt(opcode.Opcode.AND_A_HL) => try self.output.print("and a,(hl)\n"), 170 | @enumToInt(opcode.Opcode.AND_A_n) => try self.output.print("and a,${x}\n", try self.input.readByte()), 171 | @enumToInt(opcode.Opcode.OR_A_A) => try self.output.print("or a,a\n"), 172 | @enumToInt(opcode.Opcode.OR_A_B) => try self.output.print("or a,b\n"), 173 | @enumToInt(opcode.Opcode.OR_A_C) => try self.output.print("or a,c\n"), 174 | @enumToInt(opcode.Opcode.OR_A_D) => try self.output.print("or a,d\n"), 175 | @enumToInt(opcode.Opcode.OR_A_E) => try self.output.print("or a,e\n"), 176 | @enumToInt(opcode.Opcode.OR_A_H) => try self.output.print("or a,h\n"), 177 | @enumToInt(opcode.Opcode.OR_A_L) => try self.output.print("or a,l\n"), 178 | @enumToInt(opcode.Opcode.OR_A_HL) => try self.output.print("or a,(hl)\n"), 179 | @enumToInt(opcode.Opcode.OR_A_n) => try self.output.print("or a,${x}\n", try self.input.readByte()), 180 | @enumToInt(opcode.Opcode.XOR_A_A) => try self.output.print("xor a,a\n"), 181 | @enumToInt(opcode.Opcode.XOR_A_B) => try self.output.print("xor a,b\n"), 182 | @enumToInt(opcode.Opcode.XOR_A_C) => try self.output.print("xor a,c\n"), 183 | @enumToInt(opcode.Opcode.XOR_A_D) => try self.output.print("xor a,d\n"), 184 | @enumToInt(opcode.Opcode.XOR_A_E) => try self.output.print("xor a,e\n"), 185 | @enumToInt(opcode.Opcode.XOR_A_H) => try self.output.print("xor a,h\n"), 186 | @enumToInt(opcode.Opcode.XOR_A_L) => try self.output.print("xor a,l\n"), 187 | @enumToInt(opcode.Opcode.XOR_A_HL) => try self.output.print("xor a,(hl)\n"), 188 | @enumToInt(opcode.Opcode.XOR_A_n) => try self.output.print("xor a,${x}\n", try self.input.readByte()), 189 | @enumToInt(opcode.Opcode.CP_A_A) => try self.output.print("cp a,a\n"), 190 | @enumToInt(opcode.Opcode.CP_A_B) => try self.output.print("cp a,b\n"), 191 | @enumToInt(opcode.Opcode.CP_A_C) => try self.output.print("cp a,c\n"), 192 | @enumToInt(opcode.Opcode.CP_A_D) => try self.output.print("cp a,d\n"), 193 | @enumToInt(opcode.Opcode.CP_A_E) => try self.output.print("cp a,e\n"), 194 | @enumToInt(opcode.Opcode.CP_A_H) => try self.output.print("cp a,h\n"), 195 | @enumToInt(opcode.Opcode.CP_A_L) => try self.output.print("cp a,l\n"), 196 | @enumToInt(opcode.Opcode.CP_A_HL) => try self.output.print("cp a,(hl)\n"), 197 | @enumToInt(opcode.Opcode.CP_A_n) => try self.output.print("cp a,${x}\n", try self.input.readByte()), 198 | @enumToInt(opcode.Opcode.INC_A) => try self.output.print("inc a\n"), 199 | @enumToInt(opcode.Opcode.INC_B) => try self.output.print("inc b\n"), 200 | @enumToInt(opcode.Opcode.INC_C) => try self.output.print("inc c\n"), 201 | @enumToInt(opcode.Opcode.INC_D) => try self.output.print("inc d\n"), 202 | @enumToInt(opcode.Opcode.INC_E) => try self.output.print("inc e\n"), 203 | @enumToInt(opcode.Opcode.INC_H) => try self.output.print("inc h\n"), 204 | @enumToInt(opcode.Opcode.INC_L) => try self.output.print("inc l\n"), 205 | @enumToInt(opcode.Opcode.INC_mem_HL) => try self.output.print("inc (hl)\n"), 206 | @enumToInt(opcode.Opcode.DEC_A) => try self.output.print("dec a\n"), 207 | @enumToInt(opcode.Opcode.DEC_B) => try self.output.print("dec b\n"), 208 | @enumToInt(opcode.Opcode.DEC_C) => try self.output.print("dec c\n"), 209 | @enumToInt(opcode.Opcode.DEC_D) => try self.output.print("dec d\n"), 210 | @enumToInt(opcode.Opcode.DEC_E) => try self.output.print("dec e\n"), 211 | @enumToInt(opcode.Opcode.DEC_H) => try self.output.print("dec h\n"), 212 | @enumToInt(opcode.Opcode.DEC_L) => try self.output.print("dec l\n"), 213 | @enumToInt(opcode.Opcode.DEC_mem_HL) => try self.output.print("dec (hl)\n"), 214 | @enumToInt(opcode.Opcode.ADD_HL_BC) => try self.output.print("add hl,bc\n"), 215 | @enumToInt(opcode.Opcode.ADD_HL_DE) => try self.output.print("add hl,de\n"), 216 | @enumToInt(opcode.Opcode.ADD_HL_HL) => try self.output.print("add hl,hl\n"), 217 | @enumToInt(opcode.Opcode.ADD_HL_SP) => try self.output.print("add hl,sp\n"), 218 | @enumToInt(opcode.Opcode.ADD_SP_n) => try self.output.print("add hl,${x}\n", self.input.readByteSigned()), 219 | @enumToInt(opcode.Opcode.INC_BC) => try self.output.print("inc bc\n"), 220 | @enumToInt(opcode.Opcode.INC_DE) => try self.output.print("inc de\n"), 221 | @enumToInt(opcode.Opcode.INC_HL) => try self.output.print("inc hl\n"), 222 | @enumToInt(opcode.Opcode.INC_SP) => try self.output.print("inc sp\n"), 223 | @enumToInt(opcode.Opcode.DEC_BC) => try self.output.print("dec bc\n"), 224 | @enumToInt(opcode.Opcode.DEC_DE) => try self.output.print("dec de\n"), 225 | @enumToInt(opcode.Opcode.DEC_HL) => try self.output.print("dec hl\n"), 226 | @enumToInt(opcode.Opcode.DEC_SP) => try self.output.print("dec sp\n"), 227 | @enumToInt(opcode.Opcode.DAA) => try self.output.print("daa\n"), 228 | @enumToInt(opcode.Opcode.CPL) => try self.output.print("cpl\n"), 229 | @enumToInt(opcode.Opcode.CCF) => try self.output.print("ccf\n"), 230 | @enumToInt(opcode.Opcode.SCF) => try self.output.print("scf\n"), 231 | @enumToInt(opcode.Opcode.HALT) => try self.output.print("halt\n"), 232 | @enumToInt(opcode.Opcode.STOP_FIRST_BYTE) => { 233 | const second_byte = try self.input.readByte(); 234 | if (second_byte != 0) { 235 | self.buffer = second_byte; 236 | try self.output.print("${x}\n", @enumToInt(opcode.Opcode.STOP_FIRST_BYTE)); 237 | } else { 238 | try self.output.print("stop\n"); 239 | } 240 | }, 241 | @enumToInt(opcode.Opcode.DI) => try self.output.print("di\n"), 242 | @enumToInt(opcode.Opcode.EI) => try self.output.print("ei\n"), 243 | @enumToInt(opcode.Opcode.RLCA) => try self.output.print("rlca\n"), 244 | @enumToInt(opcode.Opcode.RLA) => try self.output.print("rla\n"), 245 | @enumToInt(opcode.Opcode.RRCA) => try self.output.print("rrca\n"), 246 | @enumToInt(opcode.Opcode.RRA) => try self.output.print("rra\n"), 247 | @enumToInt(opcode.Opcode.JP_nn) => try self.output.print("jp ${x}\n", try self.input.readIntLittle(u16)), 248 | @enumToInt(opcode.Opcode.JP_NZ_nn) => try self.output.print("jp nz,${x}\n", try self.input.readIntLittle(u16)), 249 | @enumToInt(opcode.Opcode.JP_Z_nn) => try self.output.print("jp z,${x}\n", try self.input.readIntLittle(u16)), 250 | @enumToInt(opcode.Opcode.JP_NC_nn) => try self.output.print("jp nc,${x}\n", try self.input.readIntLittle(u16)), 251 | @enumToInt(opcode.Opcode.JP_C_nn) => try self.output.print("jp c,${x}\n", try self.input.readIntLittle(u16)), 252 | @enumToInt(opcode.Opcode.JP_HL) => try self.output.print("jp (HL)\n"), 253 | @enumToInt(opcode.Opcode.JR_n) => try self.output.print("jr ${x}\n", try self.input.readByteSigned()), 254 | @enumToInt(opcode.Opcode.JR_NZ_n) => try self.output.print("jr nz,${x}\n", try self.input.readByteSigned()), 255 | @enumToInt(opcode.Opcode.JR_Z_n) => try self.output.print("jr z,${x}\n", try self.input.readByteSigned()), 256 | @enumToInt(opcode.Opcode.JR_NC_n) => try self.output.print("jr nc,${x}\n", try self.input.readByteSigned()), 257 | @enumToInt(opcode.Opcode.JR_C_n) => try self.output.print("jr c,${x}\n", try self.input.readByteSigned()), 258 | @enumToInt(opcode.Opcode.CALL_nn) => try self.output.print("call ${x}\n", try self.input.readIntLittle(u16)), 259 | @enumToInt(opcode.Opcode.CALL_NZ_nn) => try self.output.print("call nz,${x}\n", try self.input.readIntLittle(u16)), 260 | @enumToInt(opcode.Opcode.CALL_Z_nn) => try self.output.print("call z,${x}\n", try self.input.readIntLittle(u16)), 261 | @enumToInt(opcode.Opcode.CALL_NC_nn) => try self.output.print("call nc,${x}\n", try self.input.readIntLittle(u16)), 262 | @enumToInt(opcode.Opcode.CALL_C_nn) => try self.output.print("call c,${x}\n", try self.input.readIntLittle(u16)), 263 | @enumToInt(opcode.Opcode.RST_00) => try self.output.print("rst $00\n"), 264 | @enumToInt(opcode.Opcode.RST_08) => try self.output.print("rst $08\n"), 265 | @enumToInt(opcode.Opcode.RST_10) => try self.output.print("rst $10\n"), 266 | @enumToInt(opcode.Opcode.RST_18) => try self.output.print("rst $18\n"), 267 | @enumToInt(opcode.Opcode.RST_20) => try self.output.print("rst $20\n"), 268 | @enumToInt(opcode.Opcode.RST_28) => try self.output.print("rst $28\n"), 269 | @enumToInt(opcode.Opcode.RST_30) => try self.output.print("rst $30\n"), 270 | @enumToInt(opcode.Opcode.RST_38) => try self.output.print("rst $38\n"), 271 | @enumToInt(opcode.Opcode.RET) => try self.output.print("ret\n"), 272 | @enumToInt(opcode.Opcode.RET_NZ) => try self.output.print("ret nz\n"), 273 | @enumToInt(opcode.Opcode.RET_Z) => try self.output.print("ret z\n"), 274 | @enumToInt(opcode.Opcode.RET_NC) => try self.output.print("ret nc\n"), 275 | @enumToInt(opcode.Opcode.RET_C) => try self.output.print("ret c\n"), 276 | @enumToInt(opcode.Opcode.RETI) => try self.output.print("reti\n"), 277 | @enumToInt(opcode.Opcode.MISC) => { 278 | const next_byte = try self.input.readByte(); 279 | switch (next_byte) { 280 | @enumToInt(opcode.MiscOpcode.SWAP_A) => try self.output.print("swap a\n"), 281 | @enumToInt(opcode.MiscOpcode.SWAP_B) => try self.output.print("swap b\n"), 282 | @enumToInt(opcode.MiscOpcode.SWAP_C) => try self.output.print("swap c\n"), 283 | @enumToInt(opcode.MiscOpcode.SWAP_D) => try self.output.print("swap d\n"), 284 | @enumToInt(opcode.MiscOpcode.SWAP_E) => try self.output.print("swap e\n"), 285 | @enumToInt(opcode.MiscOpcode.SWAP_H) => try self.output.print("swap h\n"), 286 | @enumToInt(opcode.MiscOpcode.SWAP_L) => try self.output.print("swap l\n"), 287 | @enumToInt(opcode.MiscOpcode.SWAP_HL) => try self.output.print("swap (hl)\n"), 288 | @enumToInt(opcode.MiscOpcode.RLC_A) => try self.output.print("rlc a\n"), 289 | @enumToInt(opcode.MiscOpcode.RLC_B) => try self.output.print("rlc b\n"), 290 | @enumToInt(opcode.MiscOpcode.RLC_C) => try self.output.print("rlc c\n"), 291 | @enumToInt(opcode.MiscOpcode.RLC_D) => try self.output.print("rlc d\n"), 292 | @enumToInt(opcode.MiscOpcode.RLC_E) => try self.output.print("rlc e\n"), 293 | @enumToInt(opcode.MiscOpcode.RLC_H) => try self.output.print("rlc h\n"), 294 | @enumToInt(opcode.MiscOpcode.RLC_L) => try self.output.print("rlc l\n"), 295 | @enumToInt(opcode.MiscOpcode.RLC_HL) => try self.output.print("rlc (hl)\n"), 296 | @enumToInt(opcode.MiscOpcode.RL_A) => try self.output.print("rl a\n"), 297 | @enumToInt(opcode.MiscOpcode.RL_B) => try self.output.print("rl b\n"), 298 | @enumToInt(opcode.MiscOpcode.RL_C) => try self.output.print("rl c\n"), 299 | @enumToInt(opcode.MiscOpcode.RL_D) => try self.output.print("rl d\n"), 300 | @enumToInt(opcode.MiscOpcode.RL_E) => try self.output.print("rl e\n"), 301 | @enumToInt(opcode.MiscOpcode.RL_H) => try self.output.print("rl h\n"), 302 | @enumToInt(opcode.MiscOpcode.RL_L) => try self.output.print("rl l\n"), 303 | @enumToInt(opcode.MiscOpcode.RL_HL) => try self.output.print("rl (hl)\n"), 304 | @enumToInt(opcode.MiscOpcode.RRC_A) => try self.output.print("rrc a\n"), 305 | @enumToInt(opcode.MiscOpcode.RRC_B) => try self.output.print("rrc b\n"), 306 | @enumToInt(opcode.MiscOpcode.RRC_C) => try self.output.print("rrc c\n"), 307 | @enumToInt(opcode.MiscOpcode.RRC_D) => try self.output.print("rrc d\n"), 308 | @enumToInt(opcode.MiscOpcode.RRC_E) => try self.output.print("rrc e\n"), 309 | @enumToInt(opcode.MiscOpcode.RRC_H) => try self.output.print("rrc h\n"), 310 | @enumToInt(opcode.MiscOpcode.RRC_L) => try self.output.print("rrc l\n"), 311 | @enumToInt(opcode.MiscOpcode.RRC_HL) => try self.output.print("rrc (hl)\n"), 312 | @enumToInt(opcode.MiscOpcode.RR_A) => try self.output.print("rr a\n"), 313 | @enumToInt(opcode.MiscOpcode.RR_B) => try self.output.print("rr b\n"), 314 | @enumToInt(opcode.MiscOpcode.RR_C) => try self.output.print("rr c\n"), 315 | @enumToInt(opcode.MiscOpcode.RR_D) => try self.output.print("rr d\n"), 316 | @enumToInt(opcode.MiscOpcode.RR_E) => try self.output.print("rr e\n"), 317 | @enumToInt(opcode.MiscOpcode.RR_H) => try self.output.print("rr h\n"), 318 | @enumToInt(opcode.MiscOpcode.RR_L) => try self.output.print("rr l\n"), 319 | @enumToInt(opcode.MiscOpcode.RR_HL) => try self.output.print("rr (hl)\n"), 320 | @enumToInt(opcode.MiscOpcode.SLA_A) => try self.output.print("sla a\n"), 321 | @enumToInt(opcode.MiscOpcode.SLA_B) => try self.output.print("sla b\n"), 322 | @enumToInt(opcode.MiscOpcode.SLA_C) => try self.output.print("sla c\n"), 323 | @enumToInt(opcode.MiscOpcode.SLA_D) => try self.output.print("sla d\n"), 324 | @enumToInt(opcode.MiscOpcode.SLA_E) => try self.output.print("sla e\n"), 325 | @enumToInt(opcode.MiscOpcode.SLA_H) => try self.output.print("sla h\n"), 326 | @enumToInt(opcode.MiscOpcode.SLA_L) => try self.output.print("sla l\n"), 327 | @enumToInt(opcode.MiscOpcode.SLA_HL) => try self.output.print("sla (hl)\n"), 328 | @enumToInt(opcode.MiscOpcode.SRA_A) => try self.output.print("sra a\n"), 329 | @enumToInt(opcode.MiscOpcode.SRA_B) => try self.output.print("sra b\n"), 330 | @enumToInt(opcode.MiscOpcode.SRA_C) => try self.output.print("sra c\n"), 331 | @enumToInt(opcode.MiscOpcode.SRA_D) => try self.output.print("sra d\n"), 332 | @enumToInt(opcode.MiscOpcode.SRA_E) => try self.output.print("sra e\n"), 333 | @enumToInt(opcode.MiscOpcode.SRA_H) => try self.output.print("sra h\n"), 334 | @enumToInt(opcode.MiscOpcode.SRA_L) => try self.output.print("sra l\n"), 335 | @enumToInt(opcode.MiscOpcode.SRA_HL) => try self.output.print("sra (hl)\n"), 336 | @enumToInt(opcode.MiscOpcode.SRL_A) => try self.output.print("srl a\n"), 337 | @enumToInt(opcode.MiscOpcode.SRL_B) => try self.output.print("srl b\n"), 338 | @enumToInt(opcode.MiscOpcode.SRL_C) => try self.output.print("srl c\n"), 339 | @enumToInt(opcode.MiscOpcode.SRL_D) => try self.output.print("srl d\n"), 340 | @enumToInt(opcode.MiscOpcode.SRL_E) => try self.output.print("srl e\n"), 341 | @enumToInt(opcode.MiscOpcode.SRL_H) => try self.output.print("srl h\n"), 342 | @enumToInt(opcode.MiscOpcode.SRL_L) => try self.output.print("srl l\n"), 343 | @enumToInt(opcode.MiscOpcode.SRL_HL) => try self.output.print("srl (hl)\n"), 344 | @enumToInt(opcode.MiscOpcode.BIT_A) => try self.output.print("bit ${x},a\n", try self.input.readByte()), 345 | @enumToInt(opcode.MiscOpcode.BIT_B) => try self.output.print("bit ${x},b\n", try self.input.readByte()), 346 | @enumToInt(opcode.MiscOpcode.BIT_C) => try self.output.print("bit ${x},c\n", try self.input.readByte()), 347 | @enumToInt(opcode.MiscOpcode.BIT_D) => try self.output.print("bit ${x},d\n", try self.input.readByte()), 348 | @enumToInt(opcode.MiscOpcode.BIT_E) => try self.output.print("bit ${x},e\n", try self.input.readByte()), 349 | @enumToInt(opcode.MiscOpcode.BIT_H) => try self.output.print("bit ${x},h\n", try self.input.readByte()), 350 | @enumToInt(opcode.MiscOpcode.BIT_L) => try self.output.print("bit ${x},l\n", try self.input.readByte()), 351 | @enumToInt(opcode.MiscOpcode.BIT_HL) => try self.output.print("bit ${x},(hl)\n", try self.input.readByte()), 352 | @enumToInt(opcode.MiscOpcode.SET_A) => try self.output.print("set ${x},a\n", try self.input.readByte()), 353 | @enumToInt(opcode.MiscOpcode.SET_B) => try self.output.print("set ${x},b\n", try self.input.readByte()), 354 | @enumToInt(opcode.MiscOpcode.SET_C) => try self.output.print("set ${x},c\n", try self.input.readByte()), 355 | @enumToInt(opcode.MiscOpcode.SET_D) => try self.output.print("set ${x},d\n", try self.input.readByte()), 356 | @enumToInt(opcode.MiscOpcode.SET_E) => try self.output.print("set ${x},e\n", try self.input.readByte()), 357 | @enumToInt(opcode.MiscOpcode.SET_H) => try self.output.print("set ${x},h\n", try self.input.readByte()), 358 | @enumToInt(opcode.MiscOpcode.SET_L) => try self.output.print("set ${x},l\n", try self.input.readByte()), 359 | @enumToInt(opcode.MiscOpcode.SET_HL) => try self.output.print("set ${x},(hl)\n", try self.input.readByte()), 360 | @enumToInt(opcode.MiscOpcode.RES_A) => try self.output.print("res ${x},a\n", try self.input.readByte()), 361 | @enumToInt(opcode.MiscOpcode.RES_B) => try self.output.print("res ${x},b\n", try self.input.readByte()), 362 | @enumToInt(opcode.MiscOpcode.RES_C) => try self.output.print("res ${x},c\n", try self.input.readByte()), 363 | @enumToInt(opcode.MiscOpcode.RES_D) => try self.output.print("res ${x},d\n", try self.input.readByte()), 364 | @enumToInt(opcode.MiscOpcode.RES_E) => try self.output.print("res ${x},e\n", try self.input.readByte()), 365 | @enumToInt(opcode.MiscOpcode.RES_H) => try self.output.print("res ${x},h\n", try self.input.readByte()), 366 | @enumToInt(opcode.MiscOpcode.RES_L) => try self.output.print("res ${x},l\n", try self.input.readByte()), 367 | @enumToInt(opcode.MiscOpcode.RES_HL) => try self.output.print("res ${x},(hl)\n", try self.input.readByte()), 368 | else => try self.output.print("${x}\n", next_byte), 369 | } 370 | }, 371 | else => try self.output.print("${x}\n", byte), 372 | } 373 | } 374 | }; 375 | 376 | test "Disassembler" { 377 | var test_rom_file = try std.os.File.openRead("testdata/sprite_priority.gb"); 378 | defer test_rom_file.close(); 379 | var stdout = try std.io.getStdOut(); 380 | var buffered_in_stream = std.io.BufferedInStream(std.os.File.ReadError).init(&test_rom_file.inStream().stream); 381 | var buffered_out_stream = std.io.BufferedOutStream(std.os.File.WriteError).init(&stdout.outStream().stream); 382 | var disassembler = Disassembler.init(&buffered_in_stream.stream, &buffered_out_stream.stream); 383 | while (true) { 384 | disassembler.disassemble() catch |err| { 385 | if (err == error.EndOfStream) { 386 | break; 387 | } else { 388 | return err; 389 | } 390 | }; 391 | } 392 | } 393 | -------------------------------------------------------------------------------- /src/main.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | const c = @import("c.zig"); 4 | 5 | const ErrorSet = error{SDLError}; 6 | 7 | pub fn main() !void { 8 | if (c.SDL_Init(c.SDL_INIT_VIDEO | c.SDL_INIT_AUDIO) != 0) { 9 | std.debug.warn("Unable to initialize SDL: {s}", c.SDL_GetError()); 10 | return ErrorSet.SDLError; 11 | } 12 | defer c.SDL_Quit(); 13 | 14 | const screen_width = 160; 15 | const screen_height = 144; 16 | const undefined_pos = 0x1FFF0000; 17 | 18 | const window = c.SDL_CreateWindow( 19 | c"gbemu", 20 | undefined_pos, 21 | undefined_pos, 22 | screen_width, 23 | screen_height, 24 | c.SDL_WINDOW_SHOWN, 25 | ); 26 | if (window == null) { 27 | std.debug.warn("Cannot create window: {s}", c.SDL_GetError()); 28 | return ErrorSet.SDLError; 29 | } 30 | defer c.SDL_DestroyWindow(window); 31 | const screen = c.SDL_GetWindowSurface(window); 32 | std.os.nanosleep(5, 0); 33 | } 34 | -------------------------------------------------------------------------------- /src/opcode.zig: -------------------------------------------------------------------------------- 1 | pub const Opcode = enum(u8) { 2 | NOP = 0x00, 3 | LD_B_n = 0x06, 4 | LD_C_n = 0x0E, 5 | LD_D_n = 0x16, 6 | LD_E_n = 0x1E, 7 | LD_H_n = 0x26, 8 | LD_L_n = 0x2E, 9 | LD_A_A = 0x7F, 10 | LD_A_B = 0x78, 11 | LD_A_C = 0x79, 12 | LD_A_D = 0x7A, 13 | LD_A_E = 0x7B, 14 | LD_A_H = 0x7C, 15 | LD_A_L = 0x7D, 16 | LD_A_HL = 0x7E, 17 | LD_B_B = 0x40, 18 | LD_B_C = 0x41, 19 | LD_B_D = 0x42, 20 | LD_B_E = 0x43, 21 | LD_B_H = 0x44, 22 | LD_B_L = 0x45, 23 | LD_B_HL = 0x46, 24 | LD_C_B = 0x48, 25 | LD_C_C = 0x49, 26 | LD_C_D = 0x4A, 27 | LD_C_E = 0x4B, 28 | LD_C_H = 0x4C, 29 | LD_C_L = 0x4D, 30 | LD_C_HL = 0x4E, 31 | LD_D_B = 0x50, 32 | LD_D_C = 0x51, 33 | LD_D_D = 0x52, 34 | LD_D_E = 0x53, 35 | LD_D_H = 0x54, 36 | LD_D_L = 0x55, 37 | LD_D_HL = 0x56, 38 | LD_E_B = 0x58, 39 | LD_E_C = 0x59, 40 | LD_E_D = 0x5A, 41 | LD_E_E = 0x5B, 42 | LD_E_H = 0x5C, 43 | LD_E_L = 0x5D, 44 | LD_E_HL = 0x5E, 45 | LD_H_B = 0x60, 46 | LD_H_C = 0x61, 47 | LD_H_D = 0x62, 48 | LD_H_E = 0x63, 49 | LD_H_H = 0x64, 50 | LD_H_L = 0x65, 51 | LD_H_HL = 0x66, 52 | LD_L_B = 0x68, 53 | LD_L_C = 0x69, 54 | LD_L_D = 0x6A, 55 | LD_L_E = 0x6B, 56 | LD_L_H = 0x6C, 57 | LD_L_L = 0x6D, 58 | LD_L_HL = 0x6E, 59 | LD_HL_B = 0x70, 60 | LD_HL_C = 0x71, 61 | LD_HL_D = 0x72, 62 | LD_HL_E = 0x73, 63 | LD_HL_H = 0x74, 64 | LD_HL_L = 0x75, 65 | LD_HL_n = 0x36, 66 | LD_A_BC = 0x0A, 67 | LD_A_DE = 0x1A, 68 | LD_A_nn = 0xFA, 69 | LD_A_n = 0x3E, 70 | LD_B_A = 0x47, 71 | LD_C_A = 0x4F, 72 | LD_D_A = 0x57, 73 | LD_E_A = 0x5F, 74 | LD_H_A = 0x67, 75 | LD_L_A = 0x6F, 76 | LD_BC_A = 0x02, 77 | LD_DE_A = 0x12, 78 | LD_HL_A = 0x77, 79 | LD_nn_A = 0xEA, 80 | LD_A_mem_C = 0xF2, 81 | LD_mem_C_A = 0xE2, 82 | LDD_A_HL = 0x3A, 83 | LDD_HL_A = 0x32, 84 | LDI_A_HL = 0x2A, 85 | LDI_HL_A = 0x22, 86 | LDH_n_A = 0xE0, 87 | LDH_A_n = 0xF0, 88 | LD_BC_nn = 0x01, 89 | LD_DE_nn = 0x11, 90 | LD_HL_nn = 0x21, 91 | LD_SP_nn = 0x31, 92 | LD_SP_HL = 0xF9, 93 | LDHL_SP_n = 0xF8, 94 | LD_nn_SP = 0x08, 95 | PUSH_AF = 0xF5, 96 | PUSH_BC = 0xC5, 97 | PUSH_DE = 0xD5, 98 | PUSH_HL = 0xE5, 99 | POP_AF = 0xF1, 100 | POP_BC = 0xC1, 101 | POP_DE = 0xD1, 102 | POP_HL = 0xE1, 103 | ADD_A_A = 0x87, 104 | ADD_A_B = 0x80, 105 | ADD_A_C = 0x81, 106 | ADD_A_D = 0x82, 107 | ADD_A_E = 0x83, 108 | ADD_A_H = 0x84, 109 | ADD_A_L = 0x85, 110 | ADD_A_HL = 0x86, 111 | ADD_A_n = 0xCE, 112 | ADC_A_A = 0x8F, 113 | ADC_A_B = 0x88, 114 | ADC_A_C = 0x89, 115 | ADC_A_D = 0x8A, 116 | ADC_A_E = 0x8B, 117 | ADC_A_H = 0x8C, 118 | ADC_A_L = 0x8D, 119 | ADC_A_HL = 0x8E, 120 | ADC_A_n = 0xC6, 121 | SUB_A_A = 0x97, 122 | SUB_A_B = 0x90, 123 | SUB_A_C = 0x91, 124 | SUB_A_D = 0x92, 125 | SUB_A_E = 0x93, 126 | SUB_A_H = 0x94, 127 | SUB_A_L = 0x95, 128 | SUB_A_HL = 0x96, 129 | SUB_A_n = 0xDE, 130 | SBC_A_A = 0x9F, 131 | SBC_A_B = 0x98, 132 | SBC_A_C = 0x99, 133 | SBC_A_D = 0x9A, 134 | SBC_A_E = 0x9B, 135 | SBC_A_H = 0x9C, 136 | SBC_A_L = 0x9D, 137 | SBC_A_HL = 0x9E, 138 | SBC_A_n = 0xD6, 139 | AND_A_A = 0xA7, 140 | AND_A_B = 0xA0, 141 | AND_A_C = 0xA1, 142 | AND_A_D = 0xA2, 143 | AND_A_E = 0xA3, 144 | AND_A_H = 0xA4, 145 | AND_A_L = 0xA5, 146 | AND_A_HL = 0xA6, 147 | AND_A_n = 0xE6, 148 | OR_A_A = 0xB7, 149 | OR_A_B = 0xB0, 150 | OR_A_C = 0xB1, 151 | OR_A_D = 0xB2, 152 | OR_A_E = 0xB3, 153 | OR_A_H = 0xB4, 154 | OR_A_L = 0xB5, 155 | OR_A_HL = 0xB6, 156 | OR_A_n = 0xF6, 157 | XOR_A_A = 0xAF, 158 | XOR_A_B = 0xA8, 159 | XOR_A_C = 0xA9, 160 | XOR_A_D = 0xAA, 161 | XOR_A_E = 0xAB, 162 | XOR_A_H = 0xAC, 163 | XOR_A_L = 0xAD, 164 | XOR_A_HL = 0xAE, 165 | XOR_A_n = 0xEE, 166 | CP_A_A = 0xBF, 167 | CP_A_B = 0xB8, 168 | CP_A_C = 0xB9, 169 | CP_A_D = 0xBA, 170 | CP_A_E = 0xBB, 171 | CP_A_H = 0xBC, 172 | CP_A_L = 0xBD, 173 | CP_A_HL = 0xBE, 174 | CP_A_n = 0xFE, 175 | INC_A = 0x3C, 176 | INC_B = 0x04, 177 | INC_C = 0x0C, 178 | INC_D = 0x14, 179 | INC_E = 0x1C, 180 | INC_H = 0x24, 181 | INC_L = 0x2C, 182 | INC_mem_HL = 0x34, 183 | DEC_A = 0x3D, 184 | DEC_B = 0x05, 185 | DEC_C = 0x0D, 186 | DEC_D = 0x15, 187 | DEC_E = 0x1D, 188 | DEC_H = 0x25, 189 | DEC_L = 0x2D, 190 | DEC_mem_HL = 0x35, 191 | ADD_HL_BC = 0x09, 192 | ADD_HL_DE = 0x19, 193 | ADD_HL_HL = 0x29, 194 | ADD_HL_SP = 0x39, 195 | ADD_SP_n = 0xE8, 196 | INC_BC = 0x03, 197 | INC_DE = 0x13, 198 | INC_HL = 0x23, 199 | INC_SP = 0x33, 200 | DEC_BC = 0x0B, 201 | DEC_DE = 0x1B, 202 | DEC_HL = 0x2B, 203 | DEC_SP = 0x3B, 204 | MISC = 0xCB, 205 | DAA = 0x27, 206 | CPL = 0x2F, 207 | CCF = 0x3F, 208 | SCF = 0x37, 209 | HALT = 0x76, 210 | STOP_FIRST_BYTE = 0x10, 211 | DI = 0xF3, 212 | EI = 0xFB, 213 | RLCA = 0x07, 214 | RLA = 0x17, 215 | RRCA = 0x0F, 216 | RRA = 0x1F, 217 | JP_nn = 0xC3, 218 | JP_NZ_nn = 0xC2, 219 | JP_Z_nn = 0xCA, 220 | JP_NC_nn = 0xD2, 221 | JP_C_nn = 0xDA, 222 | JP_HL = 0xE9, 223 | JR_n = 0x18, 224 | JR_NZ_n = 0x20, 225 | JR_Z_n = 0x28, 226 | JR_NC_n = 0x30, 227 | JR_C_n = 0x38, 228 | CALL_nn = 0xCD, 229 | CALL_NZ_nn = 0xC4, 230 | CALL_Z_nn = 0xCC, 231 | CALL_NC_nn = 0xD4, 232 | CALL_C_nn = 0xDC, 233 | RST_00 = 0xC7, 234 | RST_08 = 0xCF, 235 | RST_10 = 0xD7, 236 | RST_18 = 0xDF, 237 | RST_20 = 0xE7, 238 | RST_28 = 0xEF, 239 | RST_30 = 0xF7, 240 | RST_38 = 0xFF, 241 | RET = 0xC9, 242 | RET_NZ = 0xC0, 243 | RET_Z = 0xC8, 244 | RET_NC = 0xD0, 245 | RET_C = 0xD8, 246 | RETI = 0xD9, 247 | }; 248 | 249 | pub const MiscOpcode = enum(u8) { 250 | SWAP_A = 0x37, 251 | SWAP_B = 0x30, 252 | SWAP_C = 0x31, 253 | SWAP_D = 0x32, 254 | SWAP_E = 0x33, 255 | SWAP_H = 0x34, 256 | SWAP_L = 0x35, 257 | SWAP_HL = 0x36, 258 | RLC_A = 0x07, 259 | RLC_B = 0x00, 260 | RLC_C = 0x01, 261 | RLC_D = 0x02, 262 | RLC_E = 0x03, 263 | RLC_H = 0x04, 264 | RLC_L = 0x05, 265 | RLC_HL = 0x06, 266 | RL_A = 0x17, 267 | RL_B = 0x10, 268 | RL_C = 0x11, 269 | RL_D = 0x12, 270 | RL_E = 0x13, 271 | RL_H = 0x14, 272 | RL_L = 0x15, 273 | RL_HL = 0x16, 274 | RRC_A = 0x0F, 275 | RRC_B = 0x08, 276 | RRC_C = 0x09, 277 | RRC_D = 0x0A, 278 | RRC_E = 0x0B, 279 | RRC_H = 0x0C, 280 | RRC_L = 0x0D, 281 | RRC_HL = 0x0E, 282 | RR_A = 0x1F, 283 | RR_B = 0x18, 284 | RR_C = 0x19, 285 | RR_D = 0x1A, 286 | RR_E = 0x1B, 287 | RR_H = 0x1C, 288 | RR_L = 0x1D, 289 | RR_HL = 0x1E, 290 | SLA_A = 0x27, 291 | SLA_B = 0x20, 292 | SLA_C = 0x21, 293 | SLA_D = 0x22, 294 | SLA_E = 0x23, 295 | SLA_H = 0x24, 296 | SLA_L = 0x25, 297 | SLA_HL = 0x26, 298 | SRA_A = 0x2F, 299 | SRA_B = 0x28, 300 | SRA_C = 0x29, 301 | SRA_D = 0x2A, 302 | SRA_E = 0x2B, 303 | SRA_H = 0x2C, 304 | SRA_L = 0x2D, 305 | SRA_HL = 0x2E, 306 | SRL_A = 0x3F, 307 | SRL_B = 0x38, 308 | SRL_C = 0x39, 309 | SRL_D = 0x3A, 310 | SRL_E = 0x3B, 311 | SRL_H = 0x3C, 312 | SRL_L = 0x3D, 313 | SRL_HL = 0x3E, 314 | BIT_A = 0x47, 315 | BIT_B = 0x40, 316 | BIT_C = 0x41, 317 | BIT_D = 0x42, 318 | BIT_E = 0x43, 319 | BIT_H = 0x44, 320 | BIT_L = 0x45, 321 | BIT_HL = 0x46, 322 | SET_A = 0xC7, 323 | SET_B = 0xC0, 324 | SET_C = 0xC1, 325 | SET_D = 0xC2, 326 | SET_E = 0xC3, 327 | SET_H = 0xC4, 328 | SET_L = 0xC5, 329 | SET_HL = 0xC6, 330 | RES_A = 0x87, 331 | RES_B = 0x80, 332 | RES_C = 0x81, 333 | RES_D = 0x82, 334 | RES_E = 0x83, 335 | RES_H = 0x84, 336 | RES_L = 0x85, 337 | RES_HL = 0x86, 338 | }; 339 | -------------------------------------------------------------------------------- /testdata/sprite_priority.gb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaachier/gbemu/c4bd0e3f7c5aa6f55a265f9b1bcf5a0105d7ffc1/testdata/sprite_priority.gb -------------------------------------------------------------------------------- /testdata/test.s: -------------------------------------------------------------------------------- 1 | lb: MACRO ; r, hi, lo 2 | ld \1, ((\2) & $ff) << 8 | ((\3) & $ff) 3 | ENDM 4 | --------------------------------------------------------------------------------