├── library.properties ├── LICENSE ├── examples └── Simple_Emulator │ └── Simple_Emulator.ino ├── README.md ├── ArduZ80.h └── ArduZ80.cpp /library.properties: -------------------------------------------------------------------------------- 1 | name = ArduZ80 2 | version = 1.0.1 3 | author = Mohamed Rashad 4 | maintainer = Mohamed Rashad 5 | sentence = The first Z80 emulation library for Arduino. 6 | paragraph = Near-to-complete emulation of software and hardware functions, capable of running z80 assembly, main and extended sets. 7 | category = Other 8 | url = https://github.com/MohammedRashad/ArduZ80 9 | architectures = * 10 | 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Mohamed Rashad 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/Simple_Emulator/Simple_Emulator.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * ArduZ80 - Simple Emulator Example 3 | * 4 | * This sketch runs a program that multiply 2 numbers togther 5 | * and XORs the result with 255 6 | * 7 | * Also implements the write_io & read_io functions 8 | * 9 | */ 10 | 11 | #include "ArduZ80.h" 12 | 13 | 14 | /* 15 | * This function runs whenever OUT instruction is executed 16 | * Emulates the data and address buses 17 | * Can be used to output data to pins as real Z80 or to LCD, Serial, TV..etc 18 | * 19 | */ 20 | void ArduZ80::write_io(uint16_t addr, uint8_t val){ 21 | 22 | Serial.print("Address = "); 23 | Serial.println(addr); 24 | Serial.print("Value = "); 25 | Serial.println(val); 26 | 27 | } 28 | 29 | /* 30 | * This function runs whenever IN instruction is executed 31 | * Emulates the data and address buses 32 | * Can be used to output data to pins as real Z80 or to LCD, Serial, TV..etc 33 | * 34 | */ 35 | uint8_t ArduZ80::read_io(uint16_t addr){ 36 | 37 | int data = 0; 38 | 39 | if (Serial.available() > 0) { 40 | 41 | int data = Serial.read(); 42 | Serial.print("I received: "); 43 | Serial.println(data); 44 | 45 | } 46 | 47 | return data; 48 | } 49 | 50 | 51 | 52 | void setup() { 53 | 54 | Serial.begin(9600); 55 | 56 | } 57 | 58 | 59 | void loop() { 60 | 61 | ArduZ80 cpu; 62 | 63 | /* 64 | * Simple Z80 Program 65 | * Loads 0x00 to accumlator 66 | * Loads 0x05 to Register B 67 | * Loads 0x03 to Register C 68 | * Performs repeated addition by ADD and DJNZ Instructions 69 | * XORs the result with 0xFF 70 | * 71 | */ 72 | uint8_t t[30] = { 73 | 74 | EXT_FD, FD_LD_A_imm, 0x00, 75 | EXT_DD, DD_LD_B_imm, 0x05, 76 | EXT_DD, DD_LD_C_imm, 0x03, 77 | ADD_A_C, 78 | DJNZ, 0x09, 79 | 80 | XOR_A_imm, 0xFF, 81 | 82 | NOP 83 | }; 84 | 85 | 86 | 87 | //Copies data from ROM to RAM 88 | for (int i = 0; i < 30; i++) { 89 | 90 | cpu.ram_[i] = t[i]; 91 | 92 | 93 | } 94 | 95 | //Runs the CPU 96 | cpu.run_to_nop(true); 97 | 98 | } 99 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ArduZ80 2 | 3 | The first Z80 emulation library for Arduino, bringing back the old Z80 to life. 4 | 5 | **Now Available on the Arduino LibraryManager & [Arduino Playground](http://playground.arduino.cc/Code/ArduZ80)** 6 | 7 | # Introduction 8 | 9 | Studying microprocessors for a semester project, I had to write an emulator, and I chose Z80 to be my study case. my project had to be in arduino, so the emulator itself must run on arduino, I searched the internet and no working project or library where found for Z80 to emulate it on arduino, I decided to write my own library and emulator system and revive the Z80 through Arduino, it was a great processor for hobbyists and students and very good to study computer architeture on it. 10 | 11 | # Zilog Z80 12 | The Z80 microprocessor is an 8 bit CPU with a 16 bit address bus.
13 | It has a language of 252 root instructions and an additional 308 14 | instructions.
15 | The Z80 was modeled after the 8080 and contains the 78 opcodes of 16 | 8080 opcodes as a subset to it's language.
17 | Programming features include an accumulator and six eight bit 18 | registers that can be paired as Three 16 bit registers.
19 | In addition to the general registers, a stack-pointer, program-counter, and two 20 | index (memory pointers) registers are provided.
21 | 22 | # Features 23 | - Interpretation-Based. 24 | - Written and optimized for Arduino.
25 | - Tested on Arduino Nano, Uno, Mega.
26 | - ALU, Buses, Registers, Control Unit emulated.
27 | - Emulates 260 Instructions (177 Basic Instructions, 83 Extended Instructions).
28 | - Implementation of IN and OUT instruction left for developer to customize his system.
29 | - built with customization and extensibility in mind, adding a new instruction takes 3 lines only.
30 | 31 | # Usage 32 | 33 | Step 1: 34 | 35 | //Make an array to hold the program 36 | uint8_t t[30] = { 37 | 38 | EXT_FD, FD_LD_A_imm, 0x00, 39 | EXT_DD, DD_LD_B_imm, 0x09, 40 | EXT_DD, DD_LD_C_imm, 0x03, 41 | XOR_A_B, 42 | XOR_A_C, 43 | XOR_A_imm, 0xFF, 44 | NOP 45 | 46 | }; 47 | 48 | Step 2 : 49 | 50 | //Copy the program to RAM 51 | for (int i = 0; i < 30; i++) { 52 | 53 | cpu.ram_[i] = t[i]; 54 | 55 | } 56 | 57 | Step 3 : 58 | 59 | //Run the CPU 60 | cpu.run_to_nop(true); 61 | 62 | Step 4 (Optional) : 63 | 64 | //Implement write_io and read_io 65 | 66 | void ArduZ80::write_io(uint16_t addr, uint8_t val){ } 67 | 68 | uint8_t ArduZ80::read_io(uint16_t addr){ return data; } 69 | 70 | 71 | # Credits 72 | - Sijmen Smulder for his C++ emulator, helped as a base for my Arduino version.
73 | - Gabriel Gambetta for his C library, helped to understand some instructions and tweak emulator.
74 | 75 | # License 76 | 77 | This library is signed under MIT License, Reproduce under it's terms. 78 | -------------------------------------------------------------------------------- /ArduZ80.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * ArduZ80 , Z80 Core Emulation Library for arduino 4 | * 5 | * Author : Mohamed Rashad 6 | * 7 | */ 8 | 9 | #ifndef ArduZ80_h 10 | #define ArduZ80_h 11 | 12 | #if ARDUINO >= 100 13 | #include "Arduino.h" 14 | #else 15 | #include "WProgram.h" 16 | #include "pins_arduino.h" 17 | #include "WConstants.h" 18 | #endif 19 | 20 | /* 21 | * emum : Op 22 | * 23 | * This enumeration contains the 175 main instructions 24 | * 25 | */ 26 | enum Op : uint8_t { 27 | NOP = 0x00, 28 | LD_ind_BC_A = 0x02, 29 | INC_B = 0x04, 30 | DEC_B = 0x05, 31 | LD_A_ind_BC = 0x0A, 32 | INC_C = 0x0C, 33 | DEC_C = 0x0D, 34 | DJNZ = 0x10, 35 | LD_ind_DE_A = 0x12, 36 | INC_D = 0x14, 37 | DEC_D = 0x15, 38 | JR = 0x18, 39 | LD_A_ind_DE = 0x1A, 40 | INC_E = 0x1C, 41 | DEC_E = 0x1D, 42 | JR_NZ = 0x20, 43 | INC_F = 0x24, 44 | DEC_F = 0x25, 45 | JR_Z = 0x28, 46 | INC_L = 0x2C, 47 | DEC_L = 0x2D, 48 | JR_NC = 0x30, 49 | LD_ext_A = 0x32, 50 | INC_ind_HL = 0x34, 51 | DEC_ind_HL = 0x35, 52 | JR_C = 0x38, 53 | INC_A = 0x3C, 54 | DEC_A = 0x3D, 55 | LD_B_B = 0x40, 56 | LD_B_C, 57 | LD_B_D, 58 | LD_B_E, 59 | LD_B_F, 60 | LD_B_L, 61 | LD_B_ind_HL, 62 | LD_B_A, 63 | LD_C_B, 64 | LD_C_C, 65 | LD_C_D, 66 | LD_C_E, 67 | LD_C_F, 68 | LD_C_L, 69 | LD_C_ind_HL, 70 | LD_C_A, 71 | LD_D_B, 72 | LD_D_C, 73 | LD_D_D, 74 | LD_D_E, 75 | LD_D_F, 76 | LD_D_L, 77 | LD_D_ind_HL, 78 | LD_D_A, 79 | LD_E_B, 80 | LD_E_C, 81 | LD_E_D, 82 | LD_E_E, 83 | LD_E_F, 84 | LD_E_L, 85 | LD_E_ind_HL, 86 | LD_E_A, 87 | LD_H_B, 88 | LD_H_C, 89 | LD_H_D, 90 | LD_H_E, 91 | LD_H_F, 92 | LD_H_L, 93 | LD_H_ind_HL, 94 | LD_H_A, 95 | LD_L_B, 96 | LD_L_C, 97 | LD_L_D, 98 | LD_L_E, 99 | LD_L_F, 100 | LD_L_L, 101 | LD_L_ind_HL, 102 | LD_L_A, 103 | LD_ind_HL_B, 104 | LD_ind_HL_C, 105 | LD_ind_HL_D, 106 | LD_ind_HL_E, 107 | LD_ind_HL_F, 108 | LD_ind_HL_L = 0x75, 109 | LD_ind_HL_A = 0x77, 110 | LD_A_B, 111 | LD_A_C, 112 | LD_A_D, 113 | LD_A_E, 114 | LD_A_F, 115 | LD_A_L, 116 | LD_A_ind_HL, 117 | LD_A_A, 118 | ADD_A_B, 119 | ADD_A_C, 120 | ADD_A_D, 121 | ADD_A_E, 122 | ADD_A_F, 123 | ADD_A_L, 124 | ADD_A_ind_HL, 125 | ADD_A_A, 126 | ADC_A_B, 127 | ADC_A_C, 128 | ADC_A_D, 129 | ADC_A_E, 130 | ADC_A_F, 131 | ADC_A_L, 132 | ADC_A_ind_HL, 133 | ADC_A_A, 134 | SUB_A_B, 135 | SUB_A_C, 136 | SUB_A_D, 137 | SUB_A_E, 138 | SUB_A_F, 139 | SUB_A_L, 140 | SUB_A_ind_HL, 141 | SUB_A_A, 142 | SBC_A_B, 143 | SBC_A_C, 144 | SBC_A_D, 145 | SBC_A_E, 146 | SBC_A_F, 147 | SBC_A_L, 148 | SBC_A_ind_HL, 149 | SBC_A_A, 150 | AND_A_B, 151 | AND_A_C, 152 | AND_A_D, 153 | AND_A_E, 154 | AND_A_F, 155 | AND_A_L, 156 | AND_A_ind_HL, 157 | AND_A_A, 158 | XOR_A_B, 159 | XOR_A_C, 160 | XOR_A_D, 161 | XOR_A_E, 162 | XOR_A_F, 163 | XOR_A_L, 164 | XOR_A_ind_HL, 165 | XOR_A_A, 166 | OR_A_B, 167 | OR_A_C, 168 | OR_A_D, 169 | OR_A_E, 170 | OR_A_F, 171 | OR_A_L, 172 | OR_A_ind_HL, 173 | OR_A_A, 174 | CP_B, 175 | CP_C, 176 | CP_D, 177 | CP_E, 178 | CP_F, 179 | CP_L, 180 | CP_ind_HL, 181 | CP_A = 0xBF, 182 | JP_NZ = 0xC2, 183 | JP = 0xC3, 184 | ADD_A_imm = 0xC6, 185 | JP_Z = 0xCA, 186 | ADC_A_imm = 0xCE, 187 | JP_NC = 0xD2, 188 | SUB_A_imm = 0xD6, 189 | JP_C = 0xD8, 190 | EXT_DD = 0xDD, 191 | SBC_A_imm = 0xDE, 192 | JP_PO = 0xE2, 193 | AND_A_imm = 0xE6, 194 | JP_PE = 0xEA, 195 | JP_ind_HL = 0xEB, 196 | EXT_ED = 0xED, 197 | XOR_A_imm = 0xEE, 198 | JP_P = 0xF2, 199 | OR_A_imm = 0xF6, 200 | JP_M = 0xFA, 201 | EXT_FD = 0xFD, 202 | CP_imm = 0xFE, 203 | OUT_nn_A = 0xD3, 204 | IN_A_nn = 0xDB, 205 | }; 206 | 207 | /* 208 | * emum : DDop 209 | * 210 | * This enumeration contains the 31 instructions from DD Extended instruction 211 | * 212 | */ 213 | enum DDOp : uint8_t { 214 | DD_LD_D_imm = 0x1B, 215 | DD_LD_E_imm = 0x1E, 216 | DD_LD_H_imm = 0x2B, 217 | DD_INC_idx_IX = 0x34, 218 | DD_DEC_idx_IX = 0x35, 219 | DD_LD_idx_IX_imm = 0x36, 220 | DD_LD_B_idx_IX = 0x46, 221 | DD_LD_C_idx_IX = 0x4E, 222 | DD_LD_D_idx_IX = 0x56, 223 | DD_LD_E_idx_IX = 0x5E, 224 | DD_LD_H_idx_IX = 0x66, 225 | DD_LD_L_idx_IX = 0x6E, 226 | DD_LD_idx_IX_B = 0x70, 227 | DD_LD_idx_IX_C, 228 | DD_LD_idx_IX_D, 229 | DD_LD_idx_IX_E, 230 | DD_LD_idx_IX_F, 231 | DD_LD_idx_IX_L, 232 | DD_LD_idx_IX_A, 233 | DD_LD_ind_HL_imm = 0x78, 234 | DD_LD_A_idx_IY = 0x7E, 235 | DD_ADD_A_idx_IX = 0x86, 236 | DD_ADC_A_idx_IX = 0x8E, 237 | DD_SUB_A_idx_IX = 0x96, 238 | DD_SBC_A_idx_IX = 0x9E, 239 | DD_AND_A_idx_IX = 0xA6, 240 | DD_XOR_A_idx_IX = 0xAE, 241 | DD_OR_A_idx_IX = 0xB6, 242 | DD_CP_idx_IX = 0xBE, 243 | DD_LD_B_imm = 0xD5, 244 | DD_LD_C_imm = 0xDE, 245 | DD_JP_ind_IX = 0xE9 246 | }; 247 | 248 | /* 249 | * emum : EDop 250 | * 251 | * This enumeration contains the 2 instructions from ED Extended instruction 252 | * 253 | */ 254 | enum EDOp : uint8_t { 255 | ED_LD_imp_I_A = 0x47, 256 | ED_LD_imp_R_A = 0x4F 257 | }; 258 | 259 | /* 260 | * emum : FDop 261 | * 262 | * This enumeration contains the 27 instructions from FD Extended instruction 263 | * 264 | */ 265 | enum FDOp : uint8_t { 266 | FD_LD_A_imm = 0x2E, 267 | FD_LD_idx_IY_imm = 0x36, 268 | FD_LD_A_ext = 0x3A, 269 | FD_INC_idx_IY = 0x34, 270 | FD_DEC_idx_IY = 0x35, 271 | FD_LD_B_idx_IY = 0x46, 272 | FD_LD_C_idx_IY = 0x4E, 273 | FD_LD_D_idx_IY = 0x56, 274 | FD_LD_E_idx_IY = 0x5E, 275 | FD_LD_H_idx_IY = 0x66, 276 | FD_LD_idx_IY_B = 0x70, 277 | FD_LD_idx_IY_C, 278 | FD_LD_idx_IY_D, 279 | FD_LD_idx_IY_E, 280 | FD_LD_idx_IY_F, 281 | FD_LD_idx_IY_L, 282 | FD_LD_idx_IY_A = 0x77, 283 | FD_LD_A_idx_IX = 0x7E, 284 | FD_ADD_A_idx_IY = 0x86, 285 | FD_ADC_A_idx_IY = 0x8E, 286 | FD_SUB_A_idx_IY = 0x96, 287 | FD_SBC_A_idx_IY = 0x9E, 288 | FD_AND_A_idx_IY = 0xA6, 289 | FD_XOR_A_idx_IY = 0xAE, 290 | FD_OR_A_idx_IY = 0xB6, 291 | FD_CP_idx_IY = 0xBE, 292 | FD_JP_ind_IY = 0xE9 293 | }; 294 | 295 | ////////////////////////////////////////////////////////////////////////////////////////////////// 296 | 297 | /* 298 | * Class : ArduZ80 299 | * 300 | * This class contains all the logic related to the emulation, and registers. 301 | * 302 | * Functions number : 50 303 | * 304 | */ 305 | 306 | class ArduZ80 { 307 | 308 | // Flag register , 6 flip flops (Carry, Sign, Parity, Overflow, Zero, HALT) 309 | const uint8_t FLAG_C = 0x01; 310 | const uint8_t FLAG_N = 0x02; 311 | const uint8_t FLAG_PV = 0x04; 312 | const uint8_t FLAG_H = 0x08; 313 | const uint8_t FLAG_Z = 0x40; 314 | const uint8_t FLAG_S = 0x80; 315 | 316 | //Accumulator & Alternate Accumlator 317 | uint8_t ra_ = 0; 318 | uint8_t ra2_ = 0; 319 | 320 | // General purpose registers (BC, DE, HL) 321 | uint8_t rb_ = 0; 322 | uint8_t rd_ = 0; 323 | uint8_t rh_ = 0; 324 | uint8_t rf_ = 0; 325 | uint8_t rc_ = 0; 326 | uint8_t re_ = 0; 327 | uint8_t rl_ = 0; 328 | 329 | // Alternate General purpose registers (BC' , DE' , HL' ) 330 | 331 | uint8_t rb2_ = 0; 332 | uint8_t rd2_ = 0; 333 | uint8_t rh2_ = 0; 334 | uint8_t rf2_ = 0; 335 | uint8_t rc2_ = 0; 336 | uint8_t re2_ = 0; 337 | uint8_t rl2_ = 0; 338 | 339 | //Special Registers (I , R, IX , IY , PC , SP) 340 | uint8_t ri_ = 0; 341 | uint8_t rr_ = 0; 342 | uint16_t rix_ = 0; 343 | uint16_t riy_ = 0; 344 | uint16_t rsp_ = 0; 345 | uint16_t rpc_ = 0; 346 | 347 | //Functions w_calc_flags & w_logic_flags used to calculate and assign flags 348 | uint8_t w_calc_flags(uint16_t result, bool is_sub); 349 | uint8_t w_logic_flags(uint8_t result); 350 | 351 | 352 | //Rotate bits 353 | uint16_t rhl() const { 354 | return (uint16_t)rh_ + 8 & rl_; 355 | } 356 | uint16_t rbc() const { 357 | return (uint16_t)rb_ + 8 & rc_; 358 | } 359 | uint16_t rde() const { 360 | return (uint16_t)rd_ + 8 & re_; 361 | } 362 | 363 | //Assign Flags 364 | bool fc() const { 365 | return (rf_ & FLAG_C) > 0; 366 | } 367 | bool fn() const { 368 | return (rf_ & FLAG_N) > 0; 369 | } 370 | bool fpv() const { 371 | return (rf_ & FLAG_PV) > 0; 372 | } 373 | bool fh() const { 374 | return (rf_ & FLAG_H) > 0; 375 | } 376 | bool fz() const { 377 | return (rf_ & FLAG_Z) > 0; 378 | } 379 | bool fs() const { 380 | return (rf_ & FLAG_S) > 0; 381 | } 382 | 383 | ////////////////////// ALU Functions ///////////////////////////// 384 | 385 | uint8_t op_add(uint8_t a, uint8_t b) { 386 | return w_calc_flags(a + b, false); 387 | } 388 | uint8_t op_adc(uint8_t a, uint8_t b) { 389 | return w_calc_flags(a + b + (rf_ & 0x01), false); 390 | } 391 | uint8_t op_sub(uint8_t a, uint8_t b) { 392 | return w_calc_flags(a - b, true); 393 | } 394 | uint8_t op_sbc(uint8_t a, uint8_t b) { 395 | return w_calc_flags(a - b - (rf_ & 0x01), true); 396 | } 397 | uint8_t op_and(uint8_t a, uint8_t b) { 398 | return w_logic_flags(a & b); 399 | } 400 | uint8_t op_xor(uint8_t a, uint8_t b) { 401 | return w_logic_flags(a ^ b); 402 | } 403 | uint8_t op_or(uint8_t a, uint8_t b) { 404 | return w_logic_flags(a | b); 405 | } 406 | void op_cp(uint8_t a) { 407 | w_calc_flags(ra_ - a, true); 408 | } 409 | uint8_t op_inc(uint8_t a) { 410 | return w_calc_flags(a + 1, false); 411 | } 412 | uint8_t op_dec(uint8_t a) { 413 | return w_calc_flags(a - 1, false); 414 | } 415 | 416 | 417 | //////////////////////Program Counter & Program Memory ///////////////////////////// 418 | 419 | uint8_t next() { 420 | return read(rpc_++); 421 | } 422 | uint16_t next16() { 423 | return ((uint16_t)next() + 8) | next(); 424 | } 425 | uint8_t read(uint16_t addr) const { 426 | return ram_[addr]; 427 | } 428 | void write(uint16_t addr, uint8_t val) { 429 | ram_[addr] = val; 430 | } 431 | 432 | 433 | //Debugging Function, prints the current instruction 434 | String pc_str(); 435 | 436 | //Debugging Function, dumps the registers before each instruction 437 | void dump_regs(); 438 | 439 | public: 440 | 441 | //Performs Next Instruction 442 | void step(); 443 | 444 | //Reads a byte from device at specified address 445 | uint8_t read_io(uint16_t addr); 446 | 447 | //This function runs the microproccessor itself till NOP instruction 448 | void run_to_nop(bool print = false); 449 | 450 | //Writes a byte to device at specified address 451 | void write_io(uint16_t addr, uint8_t val); 452 | 453 | 454 | //Dummy Program, replaced by user 455 | 456 | uint8_t ram_[30] = { 457 | 458 | JR, 0x0C, // -+ 459 | 'H', 'e', 'l', 'l', 'o', ' ', // | 460 | 'W', 'o', 'r', 'l', 'd', '!', // | 461 | // | 462 | // calculate 3 * 4 // | 463 | EXT_FD, FD_LD_A_imm, 0x00, // <-+ 464 | EXT_DD, DD_LD_B_imm, 0x04, 465 | EXT_DD, DD_LD_C_imm, 0x03, 466 | ADD_A_C, // <-+ 467 | DJNZ, 0x17, // -+ 468 | 469 | XOR_A_imm, 0xFF, 470 | 471 | NOP 472 | }; 473 | 474 | 475 | //////////////////////////////////////// Registers Functions ////////////////////////////////////////// 476 | 477 | 478 | uint8_t reg_a() const { 479 | return ra_; 480 | } 481 | uint8_t reg_b() const { 482 | return rb_; 483 | } 484 | uint8_t reg_d() const { 485 | return rd_; 486 | } 487 | uint8_t reg_h() const { 488 | return rh_; 489 | } 490 | uint8_t reg_f() const { 491 | return rf_; 492 | } 493 | uint8_t reg_c() const { 494 | return rc_; 495 | } 496 | uint8_t reg_e() const { 497 | return re_; 498 | } 499 | uint8_t reg_l() const { 500 | return rl_; 501 | } 502 | uint8_t reg_a2() const { 503 | return ra2_; 504 | } 505 | uint8_t reg_b2() const { 506 | return rb2_; 507 | } 508 | uint8_t reg_d2() const { 509 | return rd2_; 510 | } 511 | uint8_t reg_h2() const { 512 | return rh2_; 513 | } 514 | uint8_t reg_f2() const { 515 | return rf2_; 516 | } 517 | uint8_t reg_c2() const { 518 | return rc2_; 519 | } 520 | uint8_t reg_e2() const { 521 | return re2_; 522 | } 523 | uint8_t reg_l2() const { 524 | return rl2_; 525 | } 526 | uint8_t reg_i() const { 527 | return ri_; 528 | } 529 | uint8_t reg_r() const { 530 | return rr_; 531 | } 532 | uint16_t reg_ix() const { 533 | return rix_; 534 | } 535 | uint16_t reg_iy() const { 536 | return riy_; 537 | } 538 | uint16_t reg_sp() const { 539 | return rsp_; 540 | } 541 | uint16_t reg_pc() const { 542 | return rpc_; 543 | } 544 | }; 545 | 546 | #endif 547 | -------------------------------------------------------------------------------- /ArduZ80.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | */ 19 | 20 | #include "ArduZ80.h" 21 | 22 | /* 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | */ 32 | uint8_t ArduZ80::w_calc_flags(uint16_t result, bool is_sub) { 33 | rf_ = 0; 34 | 35 | if (result & 0x0100) rf_ |= FLAG_C; 36 | if (is_sub) rf_ |= FLAG_N; 37 | if (result > 0xFF) rf_ |= FLAG_PV; 38 | if (result & 0x08) rf_ |= FLAG_H; 39 | if (!result) rf_ |= FLAG_Z; 40 | if (result & 0x80) rf_ |= FLAG_S; 41 | 42 | return (uint8_t)result; 43 | 44 | } 45 | 46 | /* 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | */ 56 | uint8_t ArduZ80::w_logic_flags(uint8_t result) { 57 | 58 | rf_ = 0; 59 | 60 | uint8_t x = result; 61 | 62 | x ^= x >> 4; 63 | x ^= x >> 2; 64 | x ^= x >> 1; 65 | 66 | bool parity = (~x) & 0x01; 67 | 68 | if (parity) rf_ |= FLAG_PV; 69 | if (!result) rf_ |= FLAG_Z; 70 | if (result & 0x80) rf_ |= FLAG_S; 71 | 72 | return result; 73 | 74 | } 75 | 76 | 77 | /* 78 | * 79 | * 80 | * 81 | * 82 | * 83 | * 84 | * 85 | * 86 | */ 87 | String ArduZ80::pc_str() { 88 | 89 | uint8_t old_pc = rpc_; 90 | uint8_t code; 91 | String str; 92 | 93 | switch (code = next()) { 94 | case NOP: str = "nop"; break; 95 | case LD_A_A: str = "ld a, a"; break; 96 | case LD_A_B: str = "ld a, b"; break; 97 | case LD_A_C: str = "ld a, c"; break; 98 | case LD_A_D: str = "ld a, d"; break; 99 | case LD_A_E: str = "ld a, e"; break; 100 | case LD_A_F: str = "ld a, f"; break; 101 | case LD_A_L: str = "ld a, l"; break; 102 | case LD_B_A: str = "ld b, a"; break; 103 | case LD_B_B: str = "ld b, b"; break; 104 | case LD_B_C: str = "ld b, c"; break; 105 | case LD_B_D: str = "ld b, d"; break; 106 | case LD_B_E: str = "ld b, e"; break; 107 | case LD_B_F: str = "ld b, f"; break; 108 | case LD_B_L: str = "ld b, l"; break; 109 | case LD_C_A: str = "ld c, a"; break; 110 | case LD_C_B: str = "ld c, b"; break; 111 | case LD_C_C: str = "ld c, c"; break; 112 | case LD_C_D: str = "ld c, d"; break; 113 | case LD_C_E: str = "ld c, e"; break; 114 | case LD_C_F: str = "ld c, f"; break; 115 | case LD_C_L: str = "ld c, l"; break; 116 | case LD_D_A: str = "ld d, a"; break; 117 | case LD_D_B: str = "ld d, b"; break; 118 | case LD_D_C: str = "ld d, c"; break; 119 | case LD_D_D: str = "ld d, d"; break; 120 | case LD_D_E: str = "ld d, e"; break; 121 | case LD_D_F: str = "ld d, f"; break; 122 | case LD_D_L: str = "ld d, l"; break; 123 | case LD_E_A: str = "ld e, a"; break; 124 | case LD_E_B: str = "ld e, b"; break; 125 | case LD_E_C: str = "ld e, c"; break; 126 | case LD_E_D: str = "ld e, d"; break; 127 | case LD_E_E: str = "ld e, e"; break; 128 | case LD_E_F: str = "ld e, f"; break; 129 | case LD_E_L: str = "ld e, l"; break; 130 | case LD_H_A: str = "ld h, a"; break; 131 | case LD_H_B: str = "ld h, b"; break; 132 | case LD_H_C: str = "ld h, c"; break; 133 | case LD_H_D: str = "ld h, d"; break; 134 | case LD_H_E: str = "ld h, e"; break; 135 | case LD_H_F: str = "ld h, f"; break; 136 | case LD_H_L: str = "ld h, l"; break; 137 | case LD_L_A: str = "ld l, a"; break; 138 | case LD_L_B: str = "ld l, b"; break; 139 | case LD_L_C: str = "ld l, c"; break; 140 | case LD_L_D: str = "ld l, d"; break; 141 | case LD_L_E: str = "ld l, e"; break; 142 | case LD_L_F: str = "ld l, f"; break; 143 | case LD_L_L: str = "ld l, l"; break; 144 | case LD_A_ind_HL: str = "ld a, (hl)"; break; 145 | case LD_A_ind_BC: str = "ld a, (bc)"; break; 146 | case LD_A_ind_DE: str = "ld a, (de)"; break; 147 | case LD_B_ind_HL: str = "ld b, (hl)"; break; 148 | case LD_C_ind_HL: str = "ld c, (hl)"; break; 149 | case LD_D_ind_HL: str = "ld d, (hl)"; break; 150 | case LD_E_ind_HL: str = "ld e, (hl)"; break; 151 | case LD_H_ind_HL: str = "ld h, (hl)"; break; 152 | case LD_L_ind_HL: str = "ld l, (hl)"; break; 153 | case LD_ind_HL_A: str = "ld (hl), a"; break; 154 | case LD_ind_HL_B: str = "ld (hl), b"; break; 155 | case LD_ind_HL_C: str = "ld (hl), c"; break; 156 | case LD_ind_HL_D: str = "ld (hl), d"; break; 157 | case LD_ind_HL_E: str = "ld (hl), e"; break; 158 | case LD_ind_HL_F: str = "ld (hl), f"; break; 159 | case LD_ind_HL_L: str = "ld (hl), l"; break; 160 | case LD_ind_BC_A: str = "ld (bc), a"; break; 161 | case LD_ind_DE_A: str = "ld (de), a"; break; 162 | case LD_ext_A: str = "ld (0x" + (String) next16() + "), a"; break; 163 | case ADD_A_A: str = "add a, a"; break; 164 | case ADD_A_B: str = "add a, b"; break; 165 | case ADD_A_C: str = "add a, c"; break; 166 | case ADD_A_D: str = "add a, d"; break; 167 | case ADD_A_E: str = "add a, e"; break; 168 | case ADD_A_F: str = "add a, f"; break; 169 | case ADD_A_L: str = "add a, l"; break; 170 | case ADD_A_ind_HL: str = "add a, (hl)"; break; 171 | case ADD_A_imm: str = "add a, 0x" + (String)next(); break; 172 | case ADC_A_A: str = "adc a, a"; break; 173 | case ADC_A_B: str = "adc a, b"; break; 174 | case ADC_A_C: str = "adc a, c"; break; 175 | case ADC_A_D: str = "adc a, d"; break; 176 | case ADC_A_E: str = "adc a, e"; break; 177 | case ADC_A_F: str = "adc a, f"; break; 178 | case ADC_A_L: str = "adc a, l"; break; 179 | case ADC_A_ind_HL: str = "adc a, (hl)"; break; 180 | case ADC_A_imm: str = "adc a, 0x" + (String)next(); break; 181 | case SUB_A_A: str = "sub a, a"; break; 182 | case SUB_A_B: str = "sub a, b"; break; 183 | case SUB_A_C: str = "sub a, c"; break; 184 | case SUB_A_D: str = "sub a, d"; break; 185 | case SUB_A_E: str = "sub a, e"; break; 186 | case SUB_A_F: str = "sub a, f"; break; 187 | case SUB_A_L: str = "sub a, l"; break; 188 | case SUB_A_ind_HL: str = "sub a, (hl)"; break; 189 | case SUB_A_imm: str = "sub a, 0x" + (String)next(); break; 190 | case SBC_A_A: str = "sbc a, a"; break; 191 | case SBC_A_B: str = "sbc a, b"; break; 192 | case SBC_A_C: str = "sbc a, c"; break; 193 | case SBC_A_D: str = "sbc a, d"; break; 194 | case SBC_A_E: str = "sbc a, e"; break; 195 | case SBC_A_F: str = "sbc a, f"; break; 196 | case SBC_A_L: str = "sbc a, l"; break; 197 | case SBC_A_ind_HL: str = "sbc a, (hl)"; break; 198 | case SBC_A_imm: str = "sbc a, 0x" + (String)next(); break; 199 | case AND_A_A: str = "and a, a"; break; 200 | case AND_A_B: str = "and a, b"; break; 201 | case AND_A_C: str = "and a, c"; break; 202 | case AND_A_D: str = "and a, d"; break; 203 | case AND_A_E: str = "and a, e"; break; 204 | case AND_A_F: str = "and a, f"; break; 205 | case AND_A_L: str = "and a, l"; break; 206 | case AND_A_ind_HL: str = "and a, (hl)"; break; 207 | case AND_A_imm: str = "and a, 0x" + (String)next(); break; 208 | case XOR_A_A: str = "xor a, a"; break; 209 | case XOR_A_B: str = "xor a, b"; break; 210 | case XOR_A_C: str = "xor a, c"; break; 211 | case XOR_A_D: str = "xor a, d"; break; 212 | case XOR_A_E: str = "xor a, e"; break; 213 | case XOR_A_F: str = "xor a, f"; break; 214 | case XOR_A_L: str = "xor a, l"; break; 215 | case XOR_A_ind_HL: str = "xor a, (hl)"; break; 216 | case XOR_A_imm: str = "xor a, 0x" + (String)next(); break; 217 | case OR_A_A: str = "or a, a"; break; 218 | case OR_A_B: str = "or a, b"; break; 219 | case OR_A_C: str = "or a, c"; break; 220 | case OR_A_D: str = "or a, d"; break; 221 | case OR_A_E: str = "or a, e"; break; 222 | case OR_A_F: str = "or a, f"; break; 223 | case OR_A_L: str = "or a, l"; break; 224 | case OR_A_ind_HL: str = "or a, (hl)"; break; 225 | case OR_A_imm: str = "or a, 0x" + (String)next(); break; 226 | case CP_A: str = "cp a"; break; 227 | case CP_B: str = "cp b"; break; 228 | case CP_C: str = "cp c"; break; 229 | case CP_D: str = "cp d"; break; 230 | case CP_E: str = "cp e"; break; 231 | case CP_F: str = "cp f"; break; 232 | case CP_L: str = "cp l"; break; 233 | case CP_ind_HL: str = "cp (hl)"; break; 234 | case CP_imm: str = "cp 0x" + (String)next(); break; 235 | case INC_A: str = "inc a"; break; 236 | case INC_B: str = "inc b"; break; 237 | case INC_C: str = "inc c"; break; 238 | case INC_D: str = "inc d"; break; 239 | case INC_E: str = "inc e"; break; 240 | case INC_F: str = "inc f"; break; 241 | case INC_L: str = "inc l"; break; 242 | case INC_ind_HL: str = "inc (hl)"; break; 243 | case DEC_A: str = "dec a"; break; 244 | case DEC_B: str = "dec b"; break; 245 | case DEC_C: str = "dec c"; break; 246 | case DEC_D: str = "dec d"; break; 247 | case DEC_E: str = "dec e"; break; 248 | case DEC_F: str = "dec f"; break; 249 | case DEC_L: str = "dec l"; break; 250 | case DEC_ind_HL: str = "dec (hl)"; break; 251 | case JP: str = "jp 0x" + next16(); break; 252 | case JP_C: str = "jp c, 0x" + next16(); break; 253 | case JP_NC: str = "jp nc, 0x" + next16(); break; 254 | case JP_Z: str = "jp z, 0x" + next16(); break; 255 | case JP_NZ: str = "jp nz, 0x" + next16(); break; 256 | case JP_PO: str = "jp po, 0x" + next16(); break; 257 | case JP_PE: str = "jp pe, 0x" + next16(); break; 258 | case JP_M: str = "jp m, 0x" + next16(); break; 259 | case JP_P: str = "jp p, 0x" + next16(); break; 260 | case JP_ind_HL: str = "jp (hl)"; break; 261 | case JR: str = "jr 0x" + (String)next(); break; 262 | case JR_C: str = "jr c, 0x" + (String)next(); break; 263 | case JR_NC: str = "jr nc, 0x" + (String)next(); break; 264 | case JR_Z: str = "jr z, 0x" + (String)next(); break; 265 | case JR_NZ: str = "jr nz, 0x" + (String)next(); break; 266 | case OUT_nn_A: str = "OUT nn,A -> 0x" + (String)next(); break; 267 | case IN_A_nn: str = "IN A,nn -> 0x" + (String)next(); break; 268 | 269 | case EXT_DD: 270 | switch (code = next()) { 271 | case DD_LD_B_imm: str = "ld b, 0x" + (String)next(); break; 272 | case DD_LD_C_imm: str = "ld c, 0x" + (String)next(); break; 273 | case DD_LD_D_imm: str = "ld d, 0x" + (String)next(); break; 274 | case DD_LD_E_imm: str = "ld e, 0x" + (String)next(); break; 275 | case DD_LD_H_imm: str = "ld h, 0x" + (String)next(); break; 276 | case DD_LD_A_idx_IY: str = "ld a, (iy + 0x" + (String)next() + ")"; break; 277 | case DD_LD_B_idx_IX: str = "ld b, (ix + 0x" + (String)next() + ")"; break; 278 | case DD_LD_C_idx_IX: str = "ld c, (ix + 0x" + (String)next() + ")"; break; 279 | case DD_LD_D_idx_IX: str = "ld d, (ix + 0x" + (String)next() + ")"; break; 280 | case DD_LD_E_idx_IX: str = "ld e, (ix + 0x" + (String)next() + ")"; break; 281 | case DD_LD_H_idx_IX: str = "ld h, (ix + 0x" + (String)next() + ")"; break; 282 | case DD_LD_L_idx_IX: str = "ld l, (ix + 0x" + (String)next() + ")"; break; 283 | case DD_LD_idx_IX_A: str = "ld (ix + 0x" + (String)next() + "), a"; break; 284 | case DD_LD_idx_IX_B: str = "ld (ix + 0x" + (String)next() + "), b"; break; 285 | case DD_LD_idx_IX_C: str = "ld (ix + 0x" + (String)next() + "), c"; break; 286 | case DD_LD_idx_IX_D: str = "ld (ix + 0x" + (String)next() + "), d"; break; 287 | case DD_LD_idx_IX_E: str = "ld (ix + 0x" + (String)next() + "), e"; break; 288 | case DD_LD_idx_IX_F: str = "ld (ix + 0x" + (String)next() + "), f"; break; 289 | case DD_LD_idx_IX_L: str = "ld (ix + 0x" + (String)next() + "), l"; break; 290 | case DD_LD_idx_IX_imm: str = "ld (ix + 0x" + (String)next() + "), 0x" + (String)next(); break; 291 | case DD_LD_ind_HL_imm: str = "ld (hl), 0x" + (String)next(); break; 292 | case DD_ADD_A_idx_IX: str = "add a, (ix + 0x" + (String)next() + ")"; break; 293 | case DD_ADC_A_idx_IX: str = "adc a, (ix + 0x" + (String)next() + ")"; break; 294 | case DD_SUB_A_idx_IX: str = "sub a, (ix + 0x" + (String)next() + ")"; break; 295 | case DD_SBC_A_idx_IX: str = "sbc a, (ix + 0x" + (String)next() + ")"; break; 296 | case DD_AND_A_idx_IX: str = "and a, (ix + 0x" + (String)next() + ")"; break; 297 | case DD_XOR_A_idx_IX: str = "xor a, (ix + 0x" + (String)next() + ")"; break; 298 | case DD_OR_A_idx_IX: str = "or a, (ix + 0x" + (String)next() + ")"; break; 299 | case DD_CP_idx_IX: str = "cp (ix + 0x" + (String)next() + ")"; break; 300 | case DD_JP_ind_IX: str = "jp (ix)"; break; 301 | default: str = "0x" + (0xDD00 & code); break; 302 | } 303 | break; 304 | 305 | case EXT_ED: 306 | switch (next()) { 307 | case ED_LD_imp_I_A: str = "ld i, a"; break; 308 | case ED_LD_imp_R_A: str = "ld r, a"; break; 309 | default: str = "0x" + (0xED00 & code); break; 310 | } 311 | break; 312 | 313 | case EXT_FD: 314 | switch (code = next()) { 315 | case FD_LD_A_imm: str = "ld a, 0x" + (String)next(); break; 316 | case FD_LD_A_ext: str = "ld a, (0x" + (String)next16() + ")"; break; 317 | case FD_LD_A_idx_IX: str = "ld a, (ix + 0x" + (String)next() + ")"; break; 318 | case FD_LD_B_idx_IY: str = "ld b, (iy + 0x" + (String)next() + ")"; break; 319 | case FD_LD_C_idx_IY: str = "ld c, (iy + 0x" + (String)next() + ")"; break; 320 | case FD_LD_D_idx_IY: str = "ld d, (iy + 0x" + (String)next() + ")"; break; 321 | case FD_LD_E_idx_IY: str = "ld e, (iy + 0x" + (String)next() + ")"; break; 322 | case FD_LD_H_idx_IY: str = "ld h, (iy + 0x" + (String)next() + ")"; break; 323 | case FD_LD_idx_IY_A: str = "ld (iy + 0x" + (String)next() + "), a"; break; 324 | case FD_LD_idx_IY_B: str = "ld (iy + 0x" + (String)next() + "), b"; break; 325 | case FD_LD_idx_IY_C: str = "ld (iy + 0x" + (String)next() + "), c"; break; 326 | case FD_LD_idx_IY_D: str = "ld (iy + 0x" + (String)next() + "), d"; break; 327 | case FD_LD_idx_IY_E: str = "ld (iy + 0x" + (String)next() + "), e"; break; 328 | case FD_LD_idx_IY_F: str = "ld (iy + 0x" + (String)next() + "), f"; break; 329 | case FD_LD_idx_IY_L: str = "ld (iy + 0x" + (String)next() + "), l"; break; 330 | case FD_LD_idx_IY_imm: str = "ld (iy + 0x" + (String)next() + "), 0x" + (String)next(); break; 331 | case FD_ADD_A_idx_IY: str = "add a, (iy + 0x" + (String)next() + ")"; break; 332 | case FD_ADC_A_idx_IY: str = "adc a, (iy + 0x" + (String)next() + ")"; break; 333 | case FD_SUB_A_idx_IY: str = "sub a, (iy + 0x" + (String)next() + ")"; break; 334 | case FD_SBC_A_idx_IY: str = "sbc a, (iy + 0x" + (String)next() + ")"; break; 335 | case FD_AND_A_idx_IY: str = "and a, (iy + 0x" + (String)next() + ")"; break; 336 | case FD_XOR_A_idx_IY: str = "xor a, (iy + 0x" + (String)next() + ")"; break; 337 | case FD_OR_A_idx_IY: str = "or a, (iy + 0x" + (String)next() + ")"; break; 338 | case FD_CP_idx_IY: str = "cp (iy + 0x" + (String)next() + ")"; break; 339 | case FD_JP_ind_IY: str = "jp (iy)"; break; 340 | default: str = "0x" + (0xFD00 & code); break; 341 | } 342 | break; 343 | 344 | default: 345 | str = "0x" + (String)code;; 346 | break; 347 | } 348 | 349 | rpc_ = old_pc; 350 | return str; 351 | } 352 | 353 | void ArduZ80::dump_regs() 354 | { 355 | Serial.println("\n "); 356 | Serial.print("\n\nA: 0x"); Serial.print(ra_ ); 357 | Serial.print(" F: 0x"); Serial.println(rf_); 358 | Serial.print("A': 0x"); Serial.print(ra2_ ); 359 | Serial.print(" F': 0x"); Serial.println(rf2_ ); 360 | Serial.println("\n"); 361 | Serial.print("B: 0x"); Serial.print (rb_); 362 | Serial.print(" C: 0x"); Serial.println(rc_); 363 | Serial.print("B': 0x"); Serial.print(rb2_); 364 | Serial.print(" C': 0x"); Serial.println(rc2_ ); 365 | Serial.println("\n"); 366 | Serial.print("D: 0x"); Serial.print(rd_ ); 367 | Serial.print(" E: 0x"); Serial.println(re_); 368 | Serial.print("D': 0x"); Serial.print(rd2_); 369 | Serial.print(" E': 0x"); Serial.println(re2_ ); 370 | Serial.println("\n"); 371 | Serial.print("H: 0x"); Serial.print(rh_); 372 | Serial.print(" L: 0x"); Serial.println(rl_); 373 | Serial.print("H': 0x"); Serial.print(rh2_); 374 | Serial.print(" L': 0x"); Serial.println(rl2_); 375 | Serial.println("\n"); 376 | Serial.print( "I: 0x"); Serial.println(ri_); 377 | Serial.print("R: 0x" ); Serial.println(rr_); 378 | Serial.print("IX: 0x"); Serial.println(rix_); 379 | Serial.print("IY: 0x"); Serial.println(riy_); 380 | Serial.print("IY: 0x"); Serial.println(riy_); 381 | Serial.println("\n"); 382 | Serial.print("SP: 0x"); Serial.println(rsp_); 383 | Serial.print("PC: 0x"); Serial.println(rpc_); 384 | Serial.println("\n"); 385 | Serial.print("S: "); Serial.println(fs()); 386 | Serial.print( "Z: "); Serial.println(fz()); 387 | Serial.print("H: "); Serial.println(fh()); 388 | Serial.print("PV: "); Serial.println(fpv()); 389 | Serial.print("N: "); Serial.println(fn()); 390 | Serial.print("C: "); Serial.println( fc()); 391 | 392 | 393 | } 394 | 395 | 396 | /* 397 | * 398 | * 399 | * 400 | * 401 | * 402 | * 403 | * 404 | * 405 | */ 406 | 407 | void ArduZ80::step() { 408 | uint8_t tmp; 409 | uint16_t tmp16; 410 | String cerr = "Error :\n"; 411 | 412 | uint8_t code; 413 | switch (code = next()) { 414 | case LD_A_A: break; 415 | case LD_A_B: ra_ = rb_; break;; 416 | case LD_A_C: ra_ = rc_; break; 417 | case LD_A_D: ra_ = rd_; break; 418 | case LD_A_E: ra_ = re_; break; 419 | case LD_A_F: ra_ = rf_; break; 420 | case LD_A_L: ra_ = rl_; break; 421 | case LD_B_A: rb_ = ra_; break; 422 | case LD_B_B: break; 423 | case LD_B_C: rb_ = rc_; break; 424 | case LD_B_D: rb_ = rd_; break; 425 | case LD_B_E: rb_ = re_; break; 426 | case LD_B_F: rb_ = rf_; break; 427 | case LD_B_L: rb_ = rl_; break; 428 | case LD_C_A: rc_ = ra_; break; 429 | case LD_C_B: rc_ = rb_; break; 430 | case LD_C_C: break; 431 | case LD_C_D: rc_ = rd_; break; 432 | case LD_C_E: rc_ = re_; break; 433 | case LD_C_F: rc_ = rf_; break; 434 | case LD_C_L: rc_ = rl_; break; 435 | case LD_D_A: rd_ = ra_; break; 436 | case LD_D_B: rd_ = rb_; break; 437 | case LD_D_C: rd_ = rc_; break; 438 | case LD_D_D: break; 439 | case LD_D_E: rd_ = re_; break; 440 | case LD_D_F: rd_ = rf_; break; 441 | case LD_D_L: rd_ = rl_; break; 442 | case LD_E_A: re_ = ra_; break; 443 | case LD_E_B: re_ = rb_; break; 444 | case LD_E_C: re_ = rc_; break; 445 | case LD_E_D: re_ = rd_; break; 446 | case LD_E_E: break; 447 | case LD_E_F: re_ = rf_; break; 448 | case LD_E_L: re_ = rl_; break; 449 | case LD_H_A: rh_ = ra_; break; 450 | case LD_H_B: rh_ = rb_; break; 451 | case LD_H_C: rh_ = rc_; break; 452 | case LD_H_D: rh_ = rd_; break; 453 | case LD_H_E: rh_ = re_; break; 454 | case LD_H_F: rh_ = rf_; break; 455 | case LD_H_L: rf_ = rl_; break; 456 | case LD_L_A: rl_ = ra_; break; 457 | case LD_L_B: rl_ = rb_; break; 458 | case LD_L_C: rl_ = rc_; break; 459 | case LD_L_D: rl_ = rd_; break; 460 | case LD_L_E: rl_ = re_; break; 461 | case LD_L_F: rl_ = rf_; break; 462 | case LD_L_L: break; 463 | case LD_A_ind_HL: ra_ = read(rhl()); break; 464 | case LD_A_ind_BC: ra_ = read(rbc()); break; 465 | case LD_A_ind_DE: ra_ = read(rde()); break; 466 | case LD_B_ind_HL: rb_ = read(rhl()); break; 467 | case LD_C_ind_HL: rc_ = read(rhl()); break; 468 | case LD_D_ind_HL: rd_ = read(rhl()); break; 469 | case LD_E_ind_HL: re_ = read(rhl()); break; 470 | case LD_H_ind_HL: rh_ = read(rhl()); break; 471 | case LD_L_ind_HL: rl_ = read(rhl()); break; 472 | case LD_ind_HL_A: write(rhl(), ra_); break; 473 | case LD_ind_HL_B: write(rhl(), rb_); break; 474 | case LD_ind_HL_C: write(rhl(), rc_); break; 475 | case LD_ind_HL_D: write(rhl(), rd_); break; 476 | case LD_ind_HL_E: write(rhl(), re_); break; 477 | case LD_ind_HL_F: write(rhl(), rf_); break; 478 | case LD_ind_HL_L: write(rhl(), rl_); break; 479 | case LD_ind_BC_A: write(rbc(), ra_); break; 480 | case LD_ind_DE_A: write(rde(), ra_); break; 481 | case LD_ext_A: write(next16(), ra_); break; 482 | case ADD_A_A: ra_ = op_add(ra_, ra_); break; 483 | case ADD_A_B: ra_ = op_add(ra_, rb_); break; 484 | case ADD_A_C: ra_ = op_add(ra_, rc_); break; 485 | case ADD_A_D: ra_ = op_add(ra_, rd_); break; 486 | case ADD_A_E: ra_ = op_add(ra_, re_); break; 487 | case ADD_A_F: ra_ = op_add(ra_, rf_); break; 488 | case ADD_A_L: ra_ = op_add(ra_, rl_); break; 489 | case ADD_A_ind_HL: ra_ = op_add(ra_, read(rhl())); break; 490 | case ADD_A_imm: ra_ = op_add(ra_, next()); break; 491 | case ADC_A_A: ra_ = op_adc(ra_, ra_); break; 492 | case ADC_A_B: ra_ = op_adc(ra_, rb_); break; 493 | case ADC_A_C: ra_ = op_adc(ra_, rc_); break; 494 | case ADC_A_D: ra_ = op_adc(ra_, rd_); break; 495 | case ADC_A_E: ra_ = op_adc(ra_, re_); break; 496 | case ADC_A_F: ra_ = op_adc(ra_, rf_); break; 497 | case ADC_A_L: ra_ = op_adc(ra_, rl_); break; 498 | case ADC_A_ind_HL: ra_ = op_adc(ra_, read(rhl())); break; 499 | case ADC_A_imm: ra_ = op_adc(ra_, next()); break; 500 | case SUB_A_A: ra_ = op_sub(ra_, ra_); break; 501 | case SUB_A_B: ra_ = op_sub(ra_, rb_); break; 502 | case SUB_A_C: ra_ = op_sub(ra_, rc_); break; 503 | case SUB_A_D: ra_ = op_sub(ra_, rd_); break; 504 | case SUB_A_E: ra_ = op_sub(ra_, re_); break; 505 | case SUB_A_F: ra_ = op_sub(ra_, rf_); break; 506 | case SUB_A_L: ra_ = op_sub(ra_, rl_); break; 507 | case SUB_A_ind_HL: ra_ = op_sub(ra_, read(rhl())); break; 508 | case SUB_A_imm: ra_ = op_sub(ra_, next()); break; 509 | case SBC_A_A: ra_ = op_sbc(ra_, ra_); break; 510 | case SBC_A_B: ra_ = op_sbc(ra_, rb_); break; 511 | case SBC_A_C: ra_ = op_sbc(ra_, rc_); break; 512 | case SBC_A_D: ra_ = op_sbc(ra_, rd_); break; 513 | case SBC_A_E: ra_ = op_sbc(ra_, re_); break; 514 | case SBC_A_F: ra_ = op_sbc(ra_, rf_); break; 515 | case SBC_A_L: ra_ = op_sbc(ra_, rl_); break; 516 | case SBC_A_ind_HL: ra_ = op_sbc(ra_, read(rhl())); break; 517 | case SBC_A_imm: ra_ = op_sbc(ra_, next()); break; 518 | case AND_A_A: ra_ = op_and(ra_, ra_); break; 519 | case AND_A_B: ra_ = op_and(ra_, rb_); break; 520 | case AND_A_C: ra_ = op_and(ra_, rc_); break; 521 | case AND_A_D: ra_ = op_and(ra_, rd_); break; 522 | case AND_A_E: ra_ = op_and(ra_, re_); break; 523 | case AND_A_F: ra_ = op_and(ra_, rf_); break; 524 | case AND_A_L: ra_ = op_and(ra_, rl_); break; 525 | case AND_A_ind_HL: ra_ = op_and(ra_, read(rhl())); break; 526 | case AND_A_imm: ra_ = op_and(ra_, next()); break; 527 | case XOR_A_A: ra_ = op_xor(ra_, ra_); break; 528 | case XOR_A_B: ra_ = op_xor(ra_, rb_); break; 529 | case XOR_A_C: ra_ = op_xor(ra_, rc_); break; 530 | case XOR_A_D: ra_ = op_xor(ra_, rd_); break; 531 | case XOR_A_E: ra_ = op_xor(ra_, re_); break; 532 | case XOR_A_F: ra_ = op_xor(ra_, rf_); break; 533 | case XOR_A_L: ra_ = op_xor(ra_, rl_); break; 534 | case XOR_A_ind_HL: ra_ = op_xor(ra_, read(rhl())); break; 535 | case XOR_A_imm: ra_ = op_xor(ra_, next()); break; 536 | case OR_A_A: ra_ = op_or(ra_, ra_); break; 537 | case OR_A_B: ra_ = op_or(ra_, rb_); break; 538 | case OR_A_C: ra_ = op_or(ra_, rc_); break; 539 | case OR_A_D: ra_ = op_or(ra_, rd_); break; 540 | case OR_A_E: ra_ = op_or(ra_, re_); break; 541 | case OR_A_F: ra_ = op_or(ra_, rf_); break; 542 | case OR_A_L: ra_ = op_or(ra_, rl_); break; 543 | case OR_A_ind_HL: ra_ = op_or(ra_, read(rhl())); break; 544 | case OR_A_imm: ra_ = op_or(ra_, next()); break; 545 | case CP_A: op_cp(ra_); break; 546 | case CP_B: op_cp(rb_); break; 547 | case CP_C: op_cp(rc_); break; 548 | case CP_D: op_cp(rd_); break; 549 | case CP_E: op_cp(re_); break; 550 | case CP_F: op_cp(rf_); break; 551 | case CP_L: op_cp(rl_); break; 552 | case CP_ind_HL: op_cp(read(rhl())); break; 553 | case CP_imm: op_cp(next()); break; 554 | case INC_A: ra_ = op_inc(ra_); break; 555 | case INC_B: rb_ = op_inc(rb_); break; 556 | case INC_C: rc_ = op_inc(rc_); break; 557 | case INC_D: rd_ = op_inc(rd_); break; 558 | case INC_E: re_ = op_inc(re_); break; 559 | case INC_F: rf_ = op_inc(rf_); break; 560 | case INC_L: rl_ = op_inc(rl_); break; 561 | case INC_ind_HL: tmp = read(rhl()) + next(); write(tmp, op_inc(read(tmp))); break; 562 | case DEC_A: ra_ = op_dec(ra_); break; 563 | case DEC_B: rb_ = op_dec(rb_); break; 564 | case DEC_C: rc_ = op_dec(rc_); break; 565 | case DEC_D: rd_ = op_dec(rd_); break; 566 | case DEC_E: re_ = op_dec(re_); break; 567 | case DEC_F: rf_ = op_dec(rf_); break; 568 | case DEC_L: rl_ = op_dec(rl_); break; 569 | case DEC_ind_HL: tmp = read(rhl()) + next(); write(tmp, op_dec(read(tmp))); break; 570 | case JP: rpc_ = next16(); break; 571 | case JP_C: tmp16 = next16(); if (fc()) rpc_ = tmp16; break; 572 | case JP_NC: tmp16 = next16(); if (!fc()) rpc_ = tmp16; break; 573 | case JP_Z: tmp16 = next16(); if (fz()) rpc_ = tmp16; break; 574 | case JP_NZ: tmp16 = next16(); if (!fz()) rpc_ = tmp16; break; 575 | case JP_PO: tmp16 = next16(); if (!fpv()) rpc_ = tmp16; break; 576 | case JP_PE: tmp16 = next16(); if (fpv()) rpc_ = tmp16; break; 577 | case JP_M: tmp16 = next16(); if (fs()) rpc_ = tmp16; break; 578 | case JP_P: tmp16 = next16(); if (!fs()) rpc_ = tmp16; break; 579 | case JP_ind_HL: rpc_ = read(rhl()); break; 580 | case JR: tmp = next(); rpc_ = *((int8_t*)&tmp); break; 581 | case JR_C: tmp = next(); if (fc()) rpc_ = *((int8_t*)&tmp); break; 582 | case JR_NC: tmp = next(); if (!fc()) rpc_ = *((int8_t*)&tmp); break; 583 | case JR_Z: tmp = next(); if (fz()) rpc_ = *((int8_t*)&tmp); break; 584 | case JR_NZ: tmp = next(); if (!fz()) rpc_ = *((int8_t*)&tmp); break; 585 | case DJNZ: tmp = next(); if (--rb_) rpc_ = *((int8_t*)&tmp); break; 586 | case OUT_nn_A: write_io(next() , ra_); break; 587 | case IN_A_nn: ra_ = read_io(next()); break; 588 | 589 | case EXT_DD: 590 | switch (code = next()) { 591 | case DD_LD_B_imm: rb_ = next(); break; 592 | case DD_LD_C_imm: rc_ = next(); break; 593 | case DD_LD_D_imm: rd_ = next(); break; 594 | case DD_LD_E_imm: re_ = next(); break; 595 | case DD_LD_H_imm: rh_ = next(); break; 596 | case DD_LD_A_idx_IY: ra_ = read(riy_ + next()); break; 597 | case DD_LD_B_idx_IX: rb_ = read(rix_ + next()); break; 598 | case DD_LD_C_idx_IX: rc_ = read(rix_ + next()); break; 599 | case DD_LD_D_idx_IX: rd_ = read(rix_ + next()); break; 600 | case DD_LD_E_idx_IX: re_ = read(rix_ + next()); break; 601 | case DD_LD_H_idx_IX: rh_ = read(rix_ + next()); break; 602 | case DD_LD_L_idx_IX: rl_ = read(rix_ + next()); break; 603 | case DD_LD_idx_IX_A: write(rix_ + next(), ra_); break; 604 | case DD_LD_idx_IX_B: write(rix_ + next(), rb_); break; 605 | case DD_LD_idx_IX_C: write(rix_ + next(), rc_); break; 606 | case DD_LD_idx_IX_D: write(rix_ + next(), rd_); break; 607 | case DD_LD_idx_IX_E: write(rix_ + next(), re_); break; 608 | case DD_LD_idx_IX_F: write(rix_ + next(), rf_); break; 609 | case DD_LD_idx_IX_L: write(rix_ + next(), rl_); break; 610 | case DD_LD_idx_IX_imm: write(rix_ + next(), next()); break; 611 | case DD_LD_ind_HL_imm: write(rhl(), next()); break; 612 | case DD_ADD_A_idx_IX: ra_ = op_add(ra_, read(rix_ + next())); break; 613 | case DD_ADC_A_idx_IX: ra_ = op_adc(ra_, read(rix_ + next())); break; 614 | case DD_SUB_A_idx_IX: ra_ = op_sub(ra_, read(rix_ + next())); break; 615 | case DD_SBC_A_idx_IX: ra_ = op_sbc(ra_, read(rix_ + next())); break; 616 | case DD_AND_A_idx_IX: ra_ = op_and(ra_, read(rix_ + next())); break; 617 | case DD_XOR_A_idx_IX: ra_ = op_xor(ra_, read(rix_ + next())); break; 618 | case DD_OR_A_idx_IX: ra_ = op_or(ra_, read(rix_ + next())); break; 619 | case DD_CP_idx_IX: op_cp(read(rix_ + next())); break; 620 | case DD_JP_ind_IX: rpc_ = read(rix_); break; 621 | 622 | default: 623 | Serial.print(cerr); 624 | Serial.print("unknown opcode: 0x"); 625 | Serial.print((String)code); 626 | break; 627 | } 628 | break; 629 | 630 | case EXT_ED: 631 | switch (next()) { 632 | case ED_LD_imp_I_A: ri_ = ra_; break; 633 | case ED_LD_imp_R_A: rr_ = ra_; break; 634 | 635 | default: 636 | Serial.print(cerr); 637 | Serial.print("unknown opcode: 0x"); 638 | Serial.print((String)code); 639 | break; 640 | } 641 | break; 642 | 643 | case EXT_FD: 644 | switch (code = next()) { 645 | case FD_LD_A_imm: ra_ = next(); break; 646 | case FD_LD_A_ext: ra_ = read(next16()); break; 647 | case FD_LD_A_idx_IX: ra_ = read(rix_ + next()); break; 648 | case FD_LD_B_idx_IY: rb_ = read(riy_ + next()); break; 649 | case FD_LD_C_idx_IY: rc_ = read(riy_ + next()); break; 650 | case FD_LD_D_idx_IY: rd_ = read(riy_ + next()); break; 651 | case FD_LD_E_idx_IY: re_ = read(riy_ + next()); break; 652 | case FD_LD_H_idx_IY: rh_ = read(riy_ + next()); break; 653 | case FD_LD_idx_IY_A: write(riy_ + next(), ra_); break; 654 | case FD_LD_idx_IY_B: write(riy_ + next(), rb_); break; 655 | case FD_LD_idx_IY_C: write(riy_ + next(), rc_); break; 656 | case FD_LD_idx_IY_D: write(riy_ + next(), rd_); break; 657 | case FD_LD_idx_IY_E: write(riy_ + next(), re_); break; 658 | case FD_LD_idx_IY_F: write(riy_ + next(), rf_); break; 659 | case FD_LD_idx_IY_L: write(riy_ + next(), rl_); break; 660 | case FD_LD_idx_IY_imm: write(riy_ + next(), next()); break; 661 | case FD_ADD_A_idx_IY: ra_ = op_add(ra_, read(riy_ + next())); break; 662 | case FD_ADC_A_idx_IY: ra_ = op_adc(ra_, read(riy_ + next())); break; 663 | case FD_SUB_A_idx_IY: ra_ = op_sub(ra_, read(riy_ + next())); break; 664 | case FD_SBC_A_idx_IY: ra_ = op_sbc(ra_, read(riy_ + next())); break; 665 | case FD_AND_A_idx_IY: ra_ = op_and(ra_, read(riy_ + next())); break; 666 | case FD_XOR_A_idx_IY: ra_ = op_xor(ra_, read(riy_ + next())); break; 667 | case FD_OR_A_idx_IY: ra_ = op_or(ra_, read(riy_ + next())); break; 668 | case FD_CP_idx_IY: op_cp(read(riy_ + next())); break; 669 | case FD_JP_ind_IY: rpc_ = read(riy_); break; 670 | 671 | default: 672 | Serial.print(cerr); 673 | Serial.print("unknown opcode: 0x"); 674 | Serial.print((String)code); 675 | break; 676 | } 677 | 678 | break; 679 | 680 | default: 681 | Serial.print(cerr); 682 | Serial.print("unknown opcode: 0x"); 683 | Serial.print((String)code); 684 | break; 685 | } 686 | } 687 | 688 | 689 | 690 | /* 691 | * 692 | * 693 | * 694 | * 695 | * 696 | * 697 | * 698 | * 699 | */ 700 | void ArduZ80::run_to_nop(bool print) { 701 | 702 | Serial.println("\n========= Emulator Log ==========="); 703 | 704 | if (print) { 705 | 706 | dump_regs(); 707 | 708 | } 709 | 710 | while (read(rpc_)) { 711 | 712 | if (print) { 713 | 714 | Serial.print("> " + pc_str()); 715 | 716 | } 717 | 718 | step(); 719 | 720 | if (print) { 721 | 722 | dump_regs(); 723 | Serial.print("\n"); 724 | 725 | } 726 | } 727 | 728 | if (print) { 729 | Serial.print("> nop"); 730 | } 731 | 732 | } 733 | 734 | 735 | --------------------------------------------------------------------------------