libz80 with compilation problems (uses up to much ram)
z80.c@0:b612024f5aee, 2011-03-10 (annotated)
- Committer:
- gertk
- Date:
- Thu Mar 10 20:32:59 2011 +0000
- Revision:
- 0:b612024f5aee
- Child:
- 1:78a39c3a30f6
not yet functional !
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
gertk | 0:b612024f5aee | 1 | /* ========================================================= |
gertk | 0:b612024f5aee | 2 | * libz80 - Z80 emulation library |
gertk | 0:b612024f5aee | 3 | * ========================================================= |
gertk | 0:b612024f5aee | 4 | * |
gertk | 0:b612024f5aee | 5 | * (C) Gabriel Gambetta (ggambett@adinet.com.uy) 2000 - 2002 |
gertk | 0:b612024f5aee | 6 | * |
gertk | 0:b612024f5aee | 7 | * Version 1.99 |
gertk | 0:b612024f5aee | 8 | * |
gertk | 0:b612024f5aee | 9 | * --------------------------------------------------------- |
gertk | 0:b612024f5aee | 10 | * |
gertk | 0:b612024f5aee | 11 | * This program is free software; you can redistribute it and/or modify |
gertk | 0:b612024f5aee | 12 | * it under the terms of the GNU General Public License as published by |
gertk | 0:b612024f5aee | 13 | * the Free Software Foundation; either version 2 of the License, or |
gertk | 0:b612024f5aee | 14 | * (at your option) any later version. |
gertk | 0:b612024f5aee | 15 | * |
gertk | 0:b612024f5aee | 16 | * This program is distributed in the hope that it will be useful, |
gertk | 0:b612024f5aee | 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
gertk | 0:b612024f5aee | 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
gertk | 0:b612024f5aee | 19 | * GNU General Public License for more details. |
gertk | 0:b612024f5aee | 20 | * |
gertk | 0:b612024f5aee | 21 | * You should have received a copy of the GNU General Public License |
gertk | 0:b612024f5aee | 22 | * along with this program; if not, write to the Free Software |
gertk | 0:b612024f5aee | 23 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
gertk | 0:b612024f5aee | 24 | */ |
gertk | 0:b612024f5aee | 25 | |
gertk | 0:b612024f5aee | 26 | #include "z80.h" |
gertk | 0:b612024f5aee | 27 | #include "string.h" |
gertk | 0:b612024f5aee | 28 | |
gertk | 0:b612024f5aee | 29 | |
gertk | 0:b612024f5aee | 30 | #define BR (ctx->R1.br) |
gertk | 0:b612024f5aee | 31 | #define WR (ctx->R1.wr) |
gertk | 0:b612024f5aee | 32 | |
gertk | 0:b612024f5aee | 33 | #define SETFLAG(F) setFlag(ctx, F) |
gertk | 0:b612024f5aee | 34 | #define RESFLAG(F) resFlag(ctx, F) |
gertk | 0:b612024f5aee | 35 | #define GETFLAG(F) getFlag(ctx, F) |
gertk | 0:b612024f5aee | 36 | |
gertk | 0:b612024f5aee | 37 | #define VALFLAG(F,V) valFlag(ctx, F, V) |
gertk | 0:b612024f5aee | 38 | |
gertk | 0:b612024f5aee | 39 | |
gertk | 0:b612024f5aee | 40 | /* --------------------------------------------------------- |
gertk | 0:b612024f5aee | 41 | * Flag tricks |
gertk | 0:b612024f5aee | 42 | * --------------------------------------------------------- |
gertk | 0:b612024f5aee | 43 | * |
gertk | 0:b612024f5aee | 44 | * To avoid repeating entries in the spec files, many operations that look similar are treated as special cases |
gertk | 0:b612024f5aee | 45 | * of a more general operation. |
gertk | 0:b612024f5aee | 46 | * |
gertk | 0:b612024f5aee | 47 | * For example, ADD and ADC are similar in syntax and operation - the difference is that ADC takes the carry flag |
gertk | 0:b612024f5aee | 48 | * into account. |
gertk | 0:b612024f5aee | 49 | * |
gertk | 0:b612024f5aee | 50 | * So we define a general operation doArithmetic(...) which accepts a boolean parameter specifying wheter to do |
gertk | 0:b612024f5aee | 51 | * a Carry-operation or not. Then, when we parse, we can say |
gertk | 0:b612024f5aee | 52 | * |
gertk | 0:b612024f5aee | 53 | * (ADD|ADC) .... |
gertk | 0:b612024f5aee | 54 | * doArithmetic(FLAG_FOR_%1) |
gertk | 0:b612024f5aee | 55 | * |
gertk | 0:b612024f5aee | 56 | * and everything works fine. |
gertk | 0:b612024f5aee | 57 | * |
gertk | 0:b612024f5aee | 58 | */ |
gertk | 0:b612024f5aee | 59 | |
gertk | 0:b612024f5aee | 60 | /* Flags for doIncDec() */ |
gertk | 0:b612024f5aee | 61 | static const int ID_INC = 0; |
gertk | 0:b612024f5aee | 62 | static const int ID_DEC = 1; |
gertk | 0:b612024f5aee | 63 | |
gertk | 0:b612024f5aee | 64 | /* Flags for enable / disable interrupts */ |
gertk | 0:b612024f5aee | 65 | static const int IE_DI = 0; |
gertk | 0:b612024f5aee | 66 | static const int IE_EI = 1; |
gertk | 0:b612024f5aee | 67 | |
gertk | 0:b612024f5aee | 68 | /* Flags for doSetRes() */ |
gertk | 0:b612024f5aee | 69 | static const int SR_RES = 0; |
gertk | 0:b612024f5aee | 70 | static const int SR_SET = 1; |
gertk | 0:b612024f5aee | 71 | |
gertk | 0:b612024f5aee | 72 | /* Flags for logical / arithmetic operations */ |
gertk | 0:b612024f5aee | 73 | static const int IA_L = 0; |
gertk | 0:b612024f5aee | 74 | static const int IA_A = 1; |
gertk | 0:b612024f5aee | 75 | |
gertk | 0:b612024f5aee | 76 | /* Flags for doArithmetic() - F1 = withCarry, F2 = isSub */ |
gertk | 0:b612024f5aee | 77 | static const int F1_ADC = 1; |
gertk | 0:b612024f5aee | 78 | static const int F1_SBC = 1; |
gertk | 0:b612024f5aee | 79 | static const int F1_ADD = 0; |
gertk | 0:b612024f5aee | 80 | static const int F1_SUB = 0; |
gertk | 0:b612024f5aee | 81 | |
gertk | 0:b612024f5aee | 82 | static const int F2_ADC = 0; |
gertk | 0:b612024f5aee | 83 | static const int F2_SBC = 1; |
gertk | 0:b612024f5aee | 84 | static const int F2_ADD = 0; |
gertk | 0:b612024f5aee | 85 | static const int F2_SUB = 1; |
gertk | 0:b612024f5aee | 86 | |
gertk | 0:b612024f5aee | 87 | |
gertk | 0:b612024f5aee | 88 | /* --------------------------------------------------------- |
gertk | 0:b612024f5aee | 89 | * The opcode implementations |
gertk | 0:b612024f5aee | 90 | * --------------------------------------------------------- |
gertk | 0:b612024f5aee | 91 | */ |
gertk | 0:b612024f5aee | 92 | #include "opcodes_decl.h" |
gertk | 0:b612024f5aee | 93 | |
gertk | 0:b612024f5aee | 94 | typedef enum |
gertk | 0:b612024f5aee | 95 | { |
gertk | 0:b612024f5aee | 96 | OP_NONE, |
gertk | 0:b612024f5aee | 97 | OP_BYTE, |
gertk | 0:b612024f5aee | 98 | OP_OFFSET, |
gertk | 0:b612024f5aee | 99 | OP_WORD |
gertk | 0:b612024f5aee | 100 | } Z80OperandType; |
gertk | 0:b612024f5aee | 101 | |
gertk | 0:b612024f5aee | 102 | typedef void (*Z80OpcodeFunc) (Z80Context* ctx); |
gertk | 0:b612024f5aee | 103 | |
gertk | 0:b612024f5aee | 104 | struct Z80OpcodeEntry |
gertk | 0:b612024f5aee | 105 | { |
gertk | 0:b612024f5aee | 106 | Z80OpcodeFunc func; |
gertk | 0:b612024f5aee | 107 | |
gertk | 0:b612024f5aee | 108 | int operand_type; |
gertk | 0:b612024f5aee | 109 | char* format; |
gertk | 0:b612024f5aee | 110 | |
gertk | 0:b612024f5aee | 111 | struct Z80OpcodeTable* table; |
gertk | 0:b612024f5aee | 112 | }; |
gertk | 0:b612024f5aee | 113 | |
gertk | 0:b612024f5aee | 114 | |
gertk | 0:b612024f5aee | 115 | struct Z80OpcodeTable |
gertk | 0:b612024f5aee | 116 | { |
gertk | 0:b612024f5aee | 117 | int opcode_offset; |
gertk | 0:b612024f5aee | 118 | struct Z80OpcodeEntry entries[256]; |
gertk | 0:b612024f5aee | 119 | }; |
gertk | 0:b612024f5aee | 120 | |
gertk | 0:b612024f5aee | 121 | |
gertk | 0:b612024f5aee | 122 | #include "opcodes_table.h" |
gertk | 0:b612024f5aee | 123 | |
gertk | 0:b612024f5aee | 124 | |
gertk | 0:b612024f5aee | 125 | /* --------------------------------------------------------- |
gertk | 0:b612024f5aee | 126 | * Data operations |
gertk | 0:b612024f5aee | 127 | * --------------------------------------------------------- |
gertk | 0:b612024f5aee | 128 | */ |
gertk | 0:b612024f5aee | 129 | static void write8 (Z80Context* ctx, ushort addr, byte val) |
gertk | 0:b612024f5aee | 130 | { |
gertk | 0:b612024f5aee | 131 | ctx->memWrite(ctx->memParam, addr, val); |
gertk | 0:b612024f5aee | 132 | } |
gertk | 0:b612024f5aee | 133 | |
gertk | 0:b612024f5aee | 134 | |
gertk | 0:b612024f5aee | 135 | static void write16 (Z80Context* ctx, ushort addr, ushort val) |
gertk | 0:b612024f5aee | 136 | { |
gertk | 0:b612024f5aee | 137 | ctx->memWrite(ctx->memParam, addr, (byte)(val & 0xFF)); |
gertk | 0:b612024f5aee | 138 | val >>= 8; |
gertk | 0:b612024f5aee | 139 | addr++; |
gertk | 0:b612024f5aee | 140 | ctx->memWrite(ctx->memParam, addr, (byte)(val & 0xFF)); |
gertk | 0:b612024f5aee | 141 | } |
gertk | 0:b612024f5aee | 142 | |
gertk | 0:b612024f5aee | 143 | |
gertk | 0:b612024f5aee | 144 | static byte read8 (Z80Context* ctx, ushort addr) |
gertk | 0:b612024f5aee | 145 | { |
gertk | 0:b612024f5aee | 146 | return ctx->memRead(ctx->memParam, addr); |
gertk | 0:b612024f5aee | 147 | } |
gertk | 0:b612024f5aee | 148 | |
gertk | 0:b612024f5aee | 149 | |
gertk | 0:b612024f5aee | 150 | static ushort read16 (Z80Context* ctx, ushort addr) |
gertk | 0:b612024f5aee | 151 | { |
gertk | 0:b612024f5aee | 152 | return (ctx->memRead(ctx->memParam, addr) | (ctx->memRead(ctx->memParam, ++addr) << 8)); |
gertk | 0:b612024f5aee | 153 | } |
gertk | 0:b612024f5aee | 154 | |
gertk | 0:b612024f5aee | 155 | |
gertk | 0:b612024f5aee | 156 | static byte ioRead (Z80Context* ctx, ushort addr) |
gertk | 0:b612024f5aee | 157 | { |
gertk | 0:b612024f5aee | 158 | return ctx->ioRead(ctx->ioParam, addr); |
gertk | 0:b612024f5aee | 159 | } |
gertk | 0:b612024f5aee | 160 | |
gertk | 0:b612024f5aee | 161 | |
gertk | 0:b612024f5aee | 162 | static void ioWrite (Z80Context* ctx, ushort addr, byte val) |
gertk | 0:b612024f5aee | 163 | { |
gertk | 0:b612024f5aee | 164 | ctx->ioWrite(ctx->ioParam, addr, val); |
gertk | 0:b612024f5aee | 165 | } |
gertk | 0:b612024f5aee | 166 | |
gertk | 0:b612024f5aee | 167 | |
gertk | 0:b612024f5aee | 168 | /* --------------------------------------------------------- |
gertk | 0:b612024f5aee | 169 | * Flag operations |
gertk | 0:b612024f5aee | 170 | * --------------------------------------------------------- |
gertk | 0:b612024f5aee | 171 | */ |
gertk | 0:b612024f5aee | 172 | |
gertk | 0:b612024f5aee | 173 | /** Sets a flag */ |
gertk | 0:b612024f5aee | 174 | static void setFlag(Z80Context* ctx, Z80Flags flag) |
gertk | 0:b612024f5aee | 175 | { |
gertk | 0:b612024f5aee | 176 | BR.F |= flag; |
gertk | 0:b612024f5aee | 177 | } |
gertk | 0:b612024f5aee | 178 | |
gertk | 0:b612024f5aee | 179 | /** Resets a flag */ |
gertk | 0:b612024f5aee | 180 | static void resFlag(Z80Context* ctx, Z80Flags flag) |
gertk | 0:b612024f5aee | 181 | { |
gertk | 0:b612024f5aee | 182 | BR.F &= ~flag; |
gertk | 0:b612024f5aee | 183 | } |
gertk | 0:b612024f5aee | 184 | |
gertk | 0:b612024f5aee | 185 | /** Puts a value in a flag */ |
gertk | 0:b612024f5aee | 186 | static void valFlag(Z80Context* ctx, Z80Flags flag, int val) |
gertk | 0:b612024f5aee | 187 | { |
gertk | 0:b612024f5aee | 188 | if (val) |
gertk | 0:b612024f5aee | 189 | SETFLAG(flag); |
gertk | 0:b612024f5aee | 190 | else |
gertk | 0:b612024f5aee | 191 | RESFLAG(flag); |
gertk | 0:b612024f5aee | 192 | } |
gertk | 0:b612024f5aee | 193 | |
gertk | 0:b612024f5aee | 194 | /** Returns a flag */ |
gertk | 0:b612024f5aee | 195 | static int getFlag(Z80Context* ctx, Z80Flags flag) |
gertk | 0:b612024f5aee | 196 | { |
gertk | 0:b612024f5aee | 197 | return (BR.F & flag) != 0; |
gertk | 0:b612024f5aee | 198 | } |
gertk | 0:b612024f5aee | 199 | |
gertk | 0:b612024f5aee | 200 | |
gertk | 0:b612024f5aee | 201 | /* --------------------------------------------------------- |
gertk | 0:b612024f5aee | 202 | * Flag adjustments |
gertk | 0:b612024f5aee | 203 | * --------------------------------------------------------- |
gertk | 0:b612024f5aee | 204 | */ |
gertk | 0:b612024f5aee | 205 | |
gertk | 0:b612024f5aee | 206 | static int parityBit[256] = { |
gertk | 0:b612024f5aee | 207 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, |
gertk | 0:b612024f5aee | 208 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, |
gertk | 0:b612024f5aee | 209 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, |
gertk | 0:b612024f5aee | 210 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, |
gertk | 0:b612024f5aee | 211 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, |
gertk | 0:b612024f5aee | 212 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, |
gertk | 0:b612024f5aee | 213 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, |
gertk | 0:b612024f5aee | 214 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, |
gertk | 0:b612024f5aee | 215 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, |
gertk | 0:b612024f5aee | 216 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, |
gertk | 0:b612024f5aee | 217 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, |
gertk | 0:b612024f5aee | 218 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, |
gertk | 0:b612024f5aee | 219 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, |
gertk | 0:b612024f5aee | 220 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, |
gertk | 0:b612024f5aee | 221 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, |
gertk | 0:b612024f5aee | 222 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 }; |
gertk | 0:b612024f5aee | 223 | |
gertk | 0:b612024f5aee | 224 | |
gertk | 0:b612024f5aee | 225 | static void adjustFlags (Z80Context* ctx, byte val) |
gertk | 0:b612024f5aee | 226 | { |
gertk | 0:b612024f5aee | 227 | VALFLAG(F_5, (val & F_5) != 0); |
gertk | 0:b612024f5aee | 228 | VALFLAG(F_3, (val & F_3) != 0); |
gertk | 0:b612024f5aee | 229 | } |
gertk | 0:b612024f5aee | 230 | |
gertk | 0:b612024f5aee | 231 | |
gertk | 0:b612024f5aee | 232 | static void adjustFlagSZP (Z80Context* ctx, byte val) |
gertk | 0:b612024f5aee | 233 | { |
gertk | 0:b612024f5aee | 234 | VALFLAG(F_S, (val & 0x80) != 0); |
gertk | 0:b612024f5aee | 235 | VALFLAG(F_Z, (val == 0)); |
gertk | 0:b612024f5aee | 236 | VALFLAG(F_PV, parityBit[val]); |
gertk | 0:b612024f5aee | 237 | } |
gertk | 0:b612024f5aee | 238 | |
gertk | 0:b612024f5aee | 239 | |
gertk | 0:b612024f5aee | 240 | // Adjust flags after AND, OR, XOR |
gertk | 0:b612024f5aee | 241 | static void adjustLogicFlag (Z80Context* ctx, int flagH) |
gertk | 0:b612024f5aee | 242 | { |
gertk | 0:b612024f5aee | 243 | VALFLAG(F_S, (BR.A & 0x80) != 0); |
gertk | 0:b612024f5aee | 244 | VALFLAG(F_Z, (BR.A == 0)); |
gertk | 0:b612024f5aee | 245 | VALFLAG(F_H, flagH); |
gertk | 0:b612024f5aee | 246 | VALFLAG(F_N, 0); |
gertk | 0:b612024f5aee | 247 | VALFLAG(F_C, 0); |
gertk | 0:b612024f5aee | 248 | VALFLAG(F_PV, parityBit[BR.A]); |
gertk | 0:b612024f5aee | 249 | |
gertk | 0:b612024f5aee | 250 | adjustFlags(ctx, BR.A); |
gertk | 0:b612024f5aee | 251 | } |
gertk | 0:b612024f5aee | 252 | |
gertk | 0:b612024f5aee | 253 | |
gertk | 0:b612024f5aee | 254 | /* --------------------------------------------------------- |
gertk | 0:b612024f5aee | 255 | * Condition checks |
gertk | 0:b612024f5aee | 256 | * --------------------------------------------------------- |
gertk | 0:b612024f5aee | 257 | */ |
gertk | 0:b612024f5aee | 258 | |
gertk | 0:b612024f5aee | 259 | typedef enum |
gertk | 0:b612024f5aee | 260 | { |
gertk | 0:b612024f5aee | 261 | C_, |
gertk | 0:b612024f5aee | 262 | C_Z, |
gertk | 0:b612024f5aee | 263 | C_NZ, |
gertk | 0:b612024f5aee | 264 | C_C, |
gertk | 0:b612024f5aee | 265 | C_NC, |
gertk | 0:b612024f5aee | 266 | C_M, |
gertk | 0:b612024f5aee | 267 | C_P, |
gertk | 0:b612024f5aee | 268 | C_PE, |
gertk | 0:b612024f5aee | 269 | C_PO |
gertk | 0:b612024f5aee | 270 | } Z80Condition; |
gertk | 0:b612024f5aee | 271 | |
gertk | 0:b612024f5aee | 272 | static int condition(Z80Context* ctx, Z80Condition cond) |
gertk | 0:b612024f5aee | 273 | { |
gertk | 0:b612024f5aee | 274 | if (cond == C_) |
gertk | 0:b612024f5aee | 275 | return GETFLAG(F_); |
gertk | 0:b612024f5aee | 276 | |
gertk | 0:b612024f5aee | 277 | if (cond == C_Z) |
gertk | 0:b612024f5aee | 278 | return !GETFLAG(F_Z); |
gertk | 0:b612024f5aee | 279 | |
gertk | 0:b612024f5aee | 280 | if (cond == C_NZ) |
gertk | 0:b612024f5aee | 281 | return GETFLAG(F_Z); |
gertk | 0:b612024f5aee | 282 | |
gertk | 0:b612024f5aee | 283 | if (cond == C_C) |
gertk | 0:b612024f5aee | 284 | return GETFLAG(F_C); |
gertk | 0:b612024f5aee | 285 | |
gertk | 0:b612024f5aee | 286 | if (cond == C_NC) |
gertk | 0:b612024f5aee | 287 | return !GETFLAG(F_C); |
gertk | 0:b612024f5aee | 288 | |
gertk | 0:b612024f5aee | 289 | if (cond == C_M) |
gertk | 0:b612024f5aee | 290 | return GETFLAG(F_S); |
gertk | 0:b612024f5aee | 291 | |
gertk | 0:b612024f5aee | 292 | if (cond == C_P) |
gertk | 0:b612024f5aee | 293 | return !(GETFLAG(F_S) | GETFLAG(F_Z)); |
gertk | 0:b612024f5aee | 294 | if (cond == C_PE) |
gertk | 0:b612024f5aee | 295 | return !GETFLAG(F_PV); |
gertk | 0:b612024f5aee | 296 | |
gertk | 0:b612024f5aee | 297 | /* if (cond == C_PO)*/ |
gertk | 0:b612024f5aee | 298 | return GETFLAG(F_PV); |
gertk | 0:b612024f5aee | 299 | } |
gertk | 0:b612024f5aee | 300 | |
gertk | 0:b612024f5aee | 301 | |
gertk | 0:b612024f5aee | 302 | /* --------------------------------------------------------- |
gertk | 0:b612024f5aee | 303 | * Generic operations |
gertk | 0:b612024f5aee | 304 | * --------------------------------------------------------- |
gertk | 0:b612024f5aee | 305 | */ |
gertk | 0:b612024f5aee | 306 | |
gertk | 0:b612024f5aee | 307 | |
gertk | 0:b612024f5aee | 308 | static int doComplement(byte v) |
gertk | 0:b612024f5aee | 309 | { |
gertk | 0:b612024f5aee | 310 | if ((v & 0x80) == 0) |
gertk | 0:b612024f5aee | 311 | return v; |
gertk | 0:b612024f5aee | 312 | |
gertk | 0:b612024f5aee | 313 | v = ~v; |
gertk | 0:b612024f5aee | 314 | v &= 0x7F; |
gertk | 0:b612024f5aee | 315 | v++; |
gertk | 0:b612024f5aee | 316 | |
gertk | 0:b612024f5aee | 317 | return -v; |
gertk | 0:b612024f5aee | 318 | } |
gertk | 0:b612024f5aee | 319 | |
gertk | 0:b612024f5aee | 320 | |
gertk | 0:b612024f5aee | 321 | /** Do an arithmetic operation (ADD, SUB, ADC, SBC y CP) */ |
gertk | 0:b612024f5aee | 322 | static byte doArithmetic (Z80Context* ctx, byte value, int withCarry, int isSub) |
gertk | 0:b612024f5aee | 323 | { |
gertk | 0:b612024f5aee | 324 | ushort res; /* To detect carry */ |
gertk | 0:b612024f5aee | 325 | |
gertk | 0:b612024f5aee | 326 | if (isSub) |
gertk | 0:b612024f5aee | 327 | { |
gertk | 0:b612024f5aee | 328 | SETFLAG(F_N); |
gertk | 0:b612024f5aee | 329 | VALFLAG(F_H, (((BR.A & 0x0F) - (value & 0x0F)) & 0x10) != 0); |
gertk | 0:b612024f5aee | 330 | res = BR.A - value; |
gertk | 0:b612024f5aee | 331 | if (withCarry && GETFLAG(F_C)) |
gertk | 0:b612024f5aee | 332 | res--; |
gertk | 0:b612024f5aee | 333 | } |
gertk | 0:b612024f5aee | 334 | else |
gertk | 0:b612024f5aee | 335 | { |
gertk | 0:b612024f5aee | 336 | RESFLAG(F_N); |
gertk | 0:b612024f5aee | 337 | VALFLAG(F_H, (((BR.A & 0x0F) + (value & 0x0F)) & 0x10) != 0); |
gertk | 0:b612024f5aee | 338 | res = BR.A + value; |
gertk | 0:b612024f5aee | 339 | if (withCarry && GETFLAG(F_C)) |
gertk | 0:b612024f5aee | 340 | res++; |
gertk | 0:b612024f5aee | 341 | } |
gertk | 0:b612024f5aee | 342 | VALFLAG(F_S, ((res & 0x80) != 0)); |
gertk | 0:b612024f5aee | 343 | VALFLAG(F_C, ((res & 0x100) != 0)); |
gertk | 0:b612024f5aee | 344 | VALFLAG(F_Z, (res == 0)); |
gertk | 0:b612024f5aee | 345 | VALFLAG(F_PV, (((BR.A & 0x80) == (value & 0x80)) && ((BR.A & 0x80) != (res & 0x80))) != 0); |
gertk | 0:b612024f5aee | 346 | |
gertk | 0:b612024f5aee | 347 | adjustFlags(ctx, BR.A); |
gertk | 0:b612024f5aee | 348 | |
gertk | 0:b612024f5aee | 349 | return (byte)(res & 0xFF); |
gertk | 0:b612024f5aee | 350 | } |
gertk | 0:b612024f5aee | 351 | |
gertk | 0:b612024f5aee | 352 | |
gertk | 0:b612024f5aee | 353 | static void doAND (Z80Context* ctx, byte value) |
gertk | 0:b612024f5aee | 354 | { |
gertk | 0:b612024f5aee | 355 | BR.A &= value; |
gertk | 0:b612024f5aee | 356 | adjustLogicFlag(ctx, 1); |
gertk | 0:b612024f5aee | 357 | } |
gertk | 0:b612024f5aee | 358 | |
gertk | 0:b612024f5aee | 359 | |
gertk | 0:b612024f5aee | 360 | static void doOR (Z80Context* ctx, byte value) |
gertk | 0:b612024f5aee | 361 | { |
gertk | 0:b612024f5aee | 362 | BR.A |= value; |
gertk | 0:b612024f5aee | 363 | adjustLogicFlag(ctx, 0); |
gertk | 0:b612024f5aee | 364 | } |
gertk | 0:b612024f5aee | 365 | |
gertk | 0:b612024f5aee | 366 | |
gertk | 0:b612024f5aee | 367 | static void doXOR (Z80Context* ctx, byte value) |
gertk | 0:b612024f5aee | 368 | { |
gertk | 0:b612024f5aee | 369 | BR.A ^= value; |
gertk | 0:b612024f5aee | 370 | adjustLogicFlag(ctx, 0); |
gertk | 0:b612024f5aee | 371 | } |
gertk | 0:b612024f5aee | 372 | |
gertk | 0:b612024f5aee | 373 | |
gertk | 0:b612024f5aee | 374 | static void doBIT (Z80Context* ctx, int b, byte val) |
gertk | 0:b612024f5aee | 375 | { |
gertk | 0:b612024f5aee | 376 | if (val & (1 << b)) |
gertk | 0:b612024f5aee | 377 | RESFLAG(F_Z | F_PV); |
gertk | 0:b612024f5aee | 378 | else |
gertk | 0:b612024f5aee | 379 | SETFLAG(F_Z | F_PV); |
gertk | 0:b612024f5aee | 380 | |
gertk | 0:b612024f5aee | 381 | SETFLAG(F_H); |
gertk | 0:b612024f5aee | 382 | RESFLAG(F_N); |
gertk | 0:b612024f5aee | 383 | |
gertk | 0:b612024f5aee | 384 | RESFLAG(F_S); |
gertk | 0:b612024f5aee | 385 | if ((b == 7) && !GETFLAG(F_Z)) |
gertk | 0:b612024f5aee | 386 | SETFLAG(F_S); |
gertk | 0:b612024f5aee | 387 | |
gertk | 0:b612024f5aee | 388 | RESFLAG(F_5); |
gertk | 0:b612024f5aee | 389 | if ((b == 5) && !GETFLAG(F_Z)) |
gertk | 0:b612024f5aee | 390 | SETFLAG(F_5); |
gertk | 0:b612024f5aee | 391 | |
gertk | 0:b612024f5aee | 392 | RESFLAG(F_3); |
gertk | 0:b612024f5aee | 393 | if ((b == 3) && !GETFLAG(F_Z)) |
gertk | 0:b612024f5aee | 394 | SETFLAG(F_3); |
gertk | 0:b612024f5aee | 395 | } |
gertk | 0:b612024f5aee | 396 | |
gertk | 0:b612024f5aee | 397 | |
gertk | 0:b612024f5aee | 398 | byte doSetRes (Z80Context* ctx, int bit, int pos, byte val) |
gertk | 0:b612024f5aee | 399 | { |
gertk | 0:b612024f5aee | 400 | if (bit) |
gertk | 0:b612024f5aee | 401 | val |= (1 << pos); |
gertk | 0:b612024f5aee | 402 | else |
gertk | 0:b612024f5aee | 403 | val &= ~(1 << pos); |
gertk | 0:b612024f5aee | 404 | return val; |
gertk | 0:b612024f5aee | 405 | } |
gertk | 0:b612024f5aee | 406 | |
gertk | 0:b612024f5aee | 407 | |
gertk | 0:b612024f5aee | 408 | |
gertk | 0:b612024f5aee | 409 | static byte doIncDec (Z80Context* ctx, byte val, int isDec) |
gertk | 0:b612024f5aee | 410 | { |
gertk | 0:b612024f5aee | 411 | if (isDec) |
gertk | 0:b612024f5aee | 412 | { |
gertk | 0:b612024f5aee | 413 | VALFLAG(F_PV, (val & 0x80) && !((val - 1) & 0x80)); |
gertk | 0:b612024f5aee | 414 | val--; |
gertk | 0:b612024f5aee | 415 | VALFLAG(F_H, !(val & 0x0F)); |
gertk | 0:b612024f5aee | 416 | } |
gertk | 0:b612024f5aee | 417 | else |
gertk | 0:b612024f5aee | 418 | { |
gertk | 0:b612024f5aee | 419 | VALFLAG(F_PV, !(val & 0x80) && ((val + 1) & 0x80)); |
gertk | 0:b612024f5aee | 420 | val++; |
gertk | 0:b612024f5aee | 421 | VALFLAG(F_H, !(val & 0x0F)); |
gertk | 0:b612024f5aee | 422 | } |
gertk | 0:b612024f5aee | 423 | |
gertk | 0:b612024f5aee | 424 | VALFLAG(F_S, ((val & 0x80) != 0)); |
gertk | 0:b612024f5aee | 425 | VALFLAG(F_Z, (val == 0)); |
gertk | 0:b612024f5aee | 426 | VALFLAG(F_N, isDec); |
gertk | 0:b612024f5aee | 427 | |
gertk | 0:b612024f5aee | 428 | adjustFlags(ctx, BR.A); |
gertk | 0:b612024f5aee | 429 | |
gertk | 0:b612024f5aee | 430 | return val; |
gertk | 0:b612024f5aee | 431 | } |
gertk | 0:b612024f5aee | 432 | |
gertk | 0:b612024f5aee | 433 | |
gertk | 0:b612024f5aee | 434 | static byte doRLC (Z80Context* ctx, int adjFlags, byte val) |
gertk | 0:b612024f5aee | 435 | { |
gertk | 0:b612024f5aee | 436 | VALFLAG(F_C, (val & 0x80) != 0); |
gertk | 0:b612024f5aee | 437 | val <<= 1; |
gertk | 0:b612024f5aee | 438 | val |= (byte)GETFLAG(F_C); |
gertk | 0:b612024f5aee | 439 | |
gertk | 0:b612024f5aee | 440 | adjustFlags(ctx, val); |
gertk | 0:b612024f5aee | 441 | RESFLAG(F_H | F_N); |
gertk | 0:b612024f5aee | 442 | |
gertk | 0:b612024f5aee | 443 | if (adjFlags) |
gertk | 0:b612024f5aee | 444 | adjustFlagSZP(ctx, val); |
gertk | 0:b612024f5aee | 445 | |
gertk | 0:b612024f5aee | 446 | return val; |
gertk | 0:b612024f5aee | 447 | } |
gertk | 0:b612024f5aee | 448 | |
gertk | 0:b612024f5aee | 449 | |
gertk | 0:b612024f5aee | 450 | static byte doRL (Z80Context* ctx, int adjFlags, byte val) |
gertk | 0:b612024f5aee | 451 | { |
gertk | 0:b612024f5aee | 452 | int CY = GETFLAG(F_C); |
gertk | 0:b612024f5aee | 453 | VALFLAG(F_C, (val & 0x80) != 0); |
gertk | 0:b612024f5aee | 454 | val <<= 1; |
gertk | 0:b612024f5aee | 455 | val |= (byte)CY; |
gertk | 0:b612024f5aee | 456 | |
gertk | 0:b612024f5aee | 457 | adjustFlags(ctx, val); |
gertk | 0:b612024f5aee | 458 | RESFLAG(F_H | F_N); |
gertk | 0:b612024f5aee | 459 | |
gertk | 0:b612024f5aee | 460 | if (adjFlags) |
gertk | 0:b612024f5aee | 461 | adjustFlagSZP(ctx, val); |
gertk | 0:b612024f5aee | 462 | |
gertk | 0:b612024f5aee | 463 | return val; |
gertk | 0:b612024f5aee | 464 | } |
gertk | 0:b612024f5aee | 465 | |
gertk | 0:b612024f5aee | 466 | |
gertk | 0:b612024f5aee | 467 | static byte doRRC (Z80Context* ctx, int adjFlags, byte val) |
gertk | 0:b612024f5aee | 468 | { |
gertk | 0:b612024f5aee | 469 | VALFLAG(F_C, (val & 0x01) != 0); |
gertk | 0:b612024f5aee | 470 | val >>= 1; |
gertk | 0:b612024f5aee | 471 | val |= ((byte)GETFLAG(F_C) << 7); |
gertk | 0:b612024f5aee | 472 | |
gertk | 0:b612024f5aee | 473 | adjustFlags(ctx, val); |
gertk | 0:b612024f5aee | 474 | RESFLAG(F_H | F_N); |
gertk | 0:b612024f5aee | 475 | |
gertk | 0:b612024f5aee | 476 | if (adjFlags) |
gertk | 0:b612024f5aee | 477 | adjustFlagSZP(ctx, val); |
gertk | 0:b612024f5aee | 478 | |
gertk | 0:b612024f5aee | 479 | return val; |
gertk | 0:b612024f5aee | 480 | } |
gertk | 0:b612024f5aee | 481 | |
gertk | 0:b612024f5aee | 482 | |
gertk | 0:b612024f5aee | 483 | static byte doRR (Z80Context* ctx, int adjFlags, byte val) |
gertk | 0:b612024f5aee | 484 | { |
gertk | 0:b612024f5aee | 485 | int CY = GETFLAG(F_C); |
gertk | 0:b612024f5aee | 486 | VALFLAG(F_C, (val & 0x01)); |
gertk | 0:b612024f5aee | 487 | val >>= 1; |
gertk | 0:b612024f5aee | 488 | val |= (CY << 7); |
gertk | 0:b612024f5aee | 489 | |
gertk | 0:b612024f5aee | 490 | adjustFlags(ctx, val); |
gertk | 0:b612024f5aee | 491 | RESFLAG(F_H | F_N); |
gertk | 0:b612024f5aee | 492 | |
gertk | 0:b612024f5aee | 493 | if (adjFlags) |
gertk | 0:b612024f5aee | 494 | adjustFlagSZP(ctx, val); |
gertk | 0:b612024f5aee | 495 | |
gertk | 0:b612024f5aee | 496 | return val; |
gertk | 0:b612024f5aee | 497 | } |
gertk | 0:b612024f5aee | 498 | |
gertk | 0:b612024f5aee | 499 | |
gertk | 0:b612024f5aee | 500 | static byte doSL (Z80Context* ctx, byte val, int isArith) |
gertk | 0:b612024f5aee | 501 | { |
gertk | 0:b612024f5aee | 502 | VALFLAG(F_C, (val & 0x80) != 0); |
gertk | 0:b612024f5aee | 503 | val <<= 1; |
gertk | 0:b612024f5aee | 504 | |
gertk | 0:b612024f5aee | 505 | if (!isArith) |
gertk | 0:b612024f5aee | 506 | val |= 1; |
gertk | 0:b612024f5aee | 507 | |
gertk | 0:b612024f5aee | 508 | adjustFlags(ctx, val); |
gertk | 0:b612024f5aee | 509 | RESFLAG(F_H | F_N); |
gertk | 0:b612024f5aee | 510 | adjustFlagSZP(ctx, val); |
gertk | 0:b612024f5aee | 511 | |
gertk | 0:b612024f5aee | 512 | return val; |
gertk | 0:b612024f5aee | 513 | } |
gertk | 0:b612024f5aee | 514 | |
gertk | 0:b612024f5aee | 515 | |
gertk | 0:b612024f5aee | 516 | static byte doSR (Z80Context* ctx, byte val, int isArith) |
gertk | 0:b612024f5aee | 517 | { |
gertk | 0:b612024f5aee | 518 | int b = ((val & 0x80) != 0); |
gertk | 0:b612024f5aee | 519 | |
gertk | 0:b612024f5aee | 520 | VALFLAG(F_C, (val & 0x01) != 0); |
gertk | 0:b612024f5aee | 521 | val >>= 1; |
gertk | 0:b612024f5aee | 522 | |
gertk | 0:b612024f5aee | 523 | if (isArith) |
gertk | 0:b612024f5aee | 524 | val |= (byte)b; |
gertk | 0:b612024f5aee | 525 | |
gertk | 0:b612024f5aee | 526 | adjustFlags(ctx, val); |
gertk | 0:b612024f5aee | 527 | RESFLAG(F_H | F_N); |
gertk | 0:b612024f5aee | 528 | adjustFlagSZP(ctx, val); |
gertk | 0:b612024f5aee | 529 | |
gertk | 0:b612024f5aee | 530 | return val; |
gertk | 0:b612024f5aee | 531 | } |
gertk | 0:b612024f5aee | 532 | |
gertk | 0:b612024f5aee | 533 | |
gertk | 0:b612024f5aee | 534 | static void doPush (Z80Context* ctx, ushort val) |
gertk | 0:b612024f5aee | 535 | { |
gertk | 0:b612024f5aee | 536 | WR.SP--; |
gertk | 0:b612024f5aee | 537 | write16(ctx, WR.SP, val); |
gertk | 0:b612024f5aee | 538 | WR.SP--; |
gertk | 0:b612024f5aee | 539 | } |
gertk | 0:b612024f5aee | 540 | |
gertk | 0:b612024f5aee | 541 | |
gertk | 0:b612024f5aee | 542 | static ushort doPop (Z80Context* ctx) |
gertk | 0:b612024f5aee | 543 | { |
gertk | 0:b612024f5aee | 544 | ushort val; |
gertk | 0:b612024f5aee | 545 | |
gertk | 0:b612024f5aee | 546 | WR.SP++; |
gertk | 0:b612024f5aee | 547 | val = read16(ctx, WR.SP); |
gertk | 0:b612024f5aee | 548 | WR.SP++; |
gertk | 0:b612024f5aee | 549 | |
gertk | 0:b612024f5aee | 550 | return val; |
gertk | 0:b612024f5aee | 551 | } |
gertk | 0:b612024f5aee | 552 | |
gertk | 0:b612024f5aee | 553 | |
gertk | 0:b612024f5aee | 554 | /* The DAA opcode |
gertk | 0:b612024f5aee | 555 | * According to the value in A and the flags set, add a value to A |
gertk | 0:b612024f5aee | 556 | * |
gertk | 0:b612024f5aee | 557 | * Flags set Byte (0..9)(0..9) |
gertk | 0:b612024f5aee | 558 | * -------------------------------------------- |
gertk | 0:b612024f5aee | 559 | * (None) + &00 |
gertk | 0:b612024f5aee | 560 | * Carry:+ &60 |
gertk | 0:b612024f5aee | 561 | * Subtract:+ &00 |
gertk | 0:b612024f5aee | 562 | * Subtract+Carry:+ &A0 |
gertk | 0:b612024f5aee | 563 | * Half-carry:+ &06 |
gertk | 0:b612024f5aee | 564 | * Half-carry+Carry:+ &66 |
gertk | 0:b612024f5aee | 565 | * Half-carry+Subtract:+ &FA |
gertk | 0:b612024f5aee | 566 | * Half-carry+Subtract+Carry:+ &9A |
gertk | 0:b612024f5aee | 567 | * |
gertk | 0:b612024f5aee | 568 | * Flags set Byte (0..9)(A..F) |
gertk | 0:b612024f5aee | 569 | * -------------------------------------------- |
gertk | 0:b612024f5aee | 570 | * (None) + &06 |
gertk | 0:b612024f5aee | 571 | * Carry:+ &66 |
gertk | 0:b612024f5aee | 572 | * Subtract:+ &00 |
gertk | 0:b612024f5aee | 573 | * Subtract+Carry:+ &a0 |
gertk | 0:b612024f5aee | 574 | * Half-carry:+ &06 |
gertk | 0:b612024f5aee | 575 | * Half-carry+Carry:+ &66 |
gertk | 0:b612024f5aee | 576 | * Half-carry+Subtract:+ &fa |
gertk | 0:b612024f5aee | 577 | * Half-carry+Subtract+Carry:+ &9A |
gertk | 0:b612024f5aee | 578 | * |
gertk | 0:b612024f5aee | 579 | * Flags set Byte (A..F)(0..9) |
gertk | 0:b612024f5aee | 580 | * -------------------------------------------- |
gertk | 0:b612024f5aee | 581 | * (None) + &60 |
gertk | 0:b612024f5aee | 582 | * Carry:+ &60 |
gertk | 0:b612024f5aee | 583 | * Subtract:+ &00 |
gertk | 0:b612024f5aee | 584 | * Subtract+Carry:+ &A0 |
gertk | 0:b612024f5aee | 585 | * Half-carry:+ &66 |
gertk | 0:b612024f5aee | 586 | * Half-carry+Carry:+ &66 |
gertk | 0:b612024f5aee | 587 | * Half-carry+Subtract:+ &fa |
gertk | 0:b612024f5aee | 588 | * Half-carry+Subtract+Carry:+ &9A |
gertk | 0:b612024f5aee | 589 | * |
gertk | 0:b612024f5aee | 590 | * Flags set Byte (A..F)(A..F) |
gertk | 0:b612024f5aee | 591 | * -------------------------------------------- |
gertk | 0:b612024f5aee | 592 | * (None) + &66 |
gertk | 0:b612024f5aee | 593 | * Carry:+ &66 |
gertk | 0:b612024f5aee | 594 | * Subtract:+ &00 |
gertk | 0:b612024f5aee | 595 | * Subtract+Carry:+ &a0 |
gertk | 0:b612024f5aee | 596 | * Half-carry:+ &66 |
gertk | 0:b612024f5aee | 597 | * Half-carry+Carry:+ &66 |
gertk | 0:b612024f5aee | 598 | * Half-carry+Subtract:+ &fa |
gertk | 0:b612024f5aee | 599 | * Half-carry+Subtract+Carry:+ &9A |
gertk | 0:b612024f5aee | 600 | */ |
gertk | 0:b612024f5aee | 601 | |
gertk | 0:b612024f5aee | 602 | static int DAA_BYTETYPE[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1 }; |
gertk | 0:b612024f5aee | 603 | |
gertk | 0:b612024f5aee | 604 | static byte DAA_ADJUSTMENT[4][8] = { |
gertk | 0:b612024f5aee | 605 | { 0x00, 0x60, 0x00, 0xA0, 0x06, 0x66, 0xFA, 0x9A }, |
gertk | 0:b612024f5aee | 606 | { 0x06, 0x66, 0x00, 0xA0, 0x06, 0x66, 0xFA, 0x9A }, |
gertk | 0:b612024f5aee | 607 | { 0x60, 0x60, 0x00, 0xA0, 0x66, 0x66, 0xFA, 0x9A }, |
gertk | 0:b612024f5aee | 608 | { 0x66, 0x66, 0x00, 0xA0, 0x66, 0x66, 0xFA, 0x9A } }; |
gertk | 0:b612024f5aee | 609 | |
gertk | 0:b612024f5aee | 610 | static void doDAA (Z80Context* ctx) |
gertk | 0:b612024f5aee | 611 | { |
gertk | 0:b612024f5aee | 612 | /* (0..9)(0..9) = 0 */ |
gertk | 0:b612024f5aee | 613 | /* (0..9)(A..F) = 1 */ |
gertk | 0:b612024f5aee | 614 | /* (A..F)(0..9) = 2 */ |
gertk | 0:b612024f5aee | 615 | /* (A..F)(A..F) = 3 */ |
gertk | 0:b612024f5aee | 616 | int byteType = DAA_BYTETYPE[BR.A] | ((DAA_BYTETYPE[BR.A >> 4]) << 1); |
gertk | 0:b612024f5aee | 617 | |
gertk | 0:b612024f5aee | 618 | int flagMask = 0; |
gertk | 0:b612024f5aee | 619 | if (GETFLAG(F_C)) |
gertk | 0:b612024f5aee | 620 | flagMask |= 1; |
gertk | 0:b612024f5aee | 621 | if (GETFLAG(F_S)) |
gertk | 0:b612024f5aee | 622 | flagMask |= 2; |
gertk | 0:b612024f5aee | 623 | if (GETFLAG(F_H)) |
gertk | 0:b612024f5aee | 624 | flagMask |= 4; |
gertk | 0:b612024f5aee | 625 | |
gertk | 0:b612024f5aee | 626 | BR.A += DAA_ADJUSTMENT[byteType][flagMask]; |
gertk | 0:b612024f5aee | 627 | |
gertk | 0:b612024f5aee | 628 | adjustFlags(ctx, BR.A); |
gertk | 0:b612024f5aee | 629 | } |
gertk | 0:b612024f5aee | 630 | |
gertk | 0:b612024f5aee | 631 | #include "opcodes_impl.c" |
gertk | 0:b612024f5aee | 632 | |
gertk | 0:b612024f5aee | 633 | |
gertk | 0:b612024f5aee | 634 | /* --------------------------------------------------------- |
gertk | 0:b612024f5aee | 635 | * The top-level functions |
gertk | 0:b612024f5aee | 636 | * --------------------------------------------------------- |
gertk | 0:b612024f5aee | 637 | */ |
gertk | 0:b612024f5aee | 638 | void Z80Execute (Z80Context* ctx) |
gertk | 0:b612024f5aee | 639 | { |
gertk | 0:b612024f5aee | 640 | struct Z80OpcodeTable* current = &opcodes_main; |
gertk | 0:b612024f5aee | 641 | struct Z80OpcodeEntry* entries = current->entries; |
gertk | 0:b612024f5aee | 642 | Z80OpcodeFunc func; |
gertk | 0:b612024f5aee | 643 | |
gertk | 0:b612024f5aee | 644 | byte opcode; |
gertk | 0:b612024f5aee | 645 | int offset = 0; |
gertk | 0:b612024f5aee | 646 | do |
gertk | 0:b612024f5aee | 647 | { |
gertk | 0:b612024f5aee | 648 | opcode = read8(ctx, ctx->PC + offset); |
gertk | 0:b612024f5aee | 649 | |
gertk | 0:b612024f5aee | 650 | ctx->PC++; |
gertk | 0:b612024f5aee | 651 | func = entries[opcode].func; |
gertk | 0:b612024f5aee | 652 | if (func != NULL) |
gertk | 0:b612024f5aee | 653 | { |
gertk | 0:b612024f5aee | 654 | ctx->PC -= offset; |
gertk | 0:b612024f5aee | 655 | func(ctx); |
gertk | 0:b612024f5aee | 656 | ctx->PC += offset; |
gertk | 0:b612024f5aee | 657 | break; |
gertk | 0:b612024f5aee | 658 | } |
gertk | 0:b612024f5aee | 659 | else if (entries[opcode].table != NULL) |
gertk | 0:b612024f5aee | 660 | { |
gertk | 0:b612024f5aee | 661 | current = entries[opcode].table; |
gertk | 0:b612024f5aee | 662 | entries = current->entries; |
gertk | 0:b612024f5aee | 663 | offset = current->opcode_offset; |
gertk | 0:b612024f5aee | 664 | } |
gertk | 0:b612024f5aee | 665 | |
gertk | 0:b612024f5aee | 666 | else |
gertk | 0:b612024f5aee | 667 | { |
gertk | 0:b612024f5aee | 668 | /* NOP */ |
gertk | 0:b612024f5aee | 669 | break; |
gertk | 0:b612024f5aee | 670 | } |
gertk | 0:b612024f5aee | 671 | } while(1); |
gertk | 0:b612024f5aee | 672 | } |
gertk | 0:b612024f5aee | 673 | |
gertk | 0:b612024f5aee | 674 | |
gertk | 0:b612024f5aee | 675 | void Z80Debug (Z80Context* ctx, char* dump, char* decode) |
gertk | 0:b612024f5aee | 676 | { |
gertk | 0:b612024f5aee | 677 | char tmp[20]; |
gertk | 0:b612024f5aee | 678 | struct Z80OpcodeTable* current = &opcodes_main; |
gertk | 0:b612024f5aee | 679 | struct Z80OpcodeEntry* entries = current->entries; |
gertk | 0:b612024f5aee | 680 | char* fmt; |
gertk | 0:b612024f5aee | 681 | byte opcode; |
gertk | 0:b612024f5aee | 682 | ushort parm; |
gertk | 0:b612024f5aee | 683 | int offset = 0; |
gertk | 0:b612024f5aee | 684 | int PC = ctx->PC; |
gertk | 0:b612024f5aee | 685 | int size = 0; |
gertk | 0:b612024f5aee | 686 | |
gertk | 0:b612024f5aee | 687 | if (dump) |
gertk | 0:b612024f5aee | 688 | dump[0] = 0; |
gertk | 0:b612024f5aee | 689 | |
gertk | 0:b612024f5aee | 690 | if (decode) |
gertk | 0:b612024f5aee | 691 | decode[0] = 0; |
gertk | 0:b612024f5aee | 692 | |
gertk | 0:b612024f5aee | 693 | do |
gertk | 0:b612024f5aee | 694 | { |
gertk | 0:b612024f5aee | 695 | opcode = read8(ctx, PC + offset); |
gertk | 0:b612024f5aee | 696 | size++; |
gertk | 0:b612024f5aee | 697 | |
gertk | 0:b612024f5aee | 698 | PC++; |
gertk | 0:b612024f5aee | 699 | ctx->R++; |
gertk | 0:b612024f5aee | 700 | fmt = entries[opcode].format; |
gertk | 0:b612024f5aee | 701 | if (fmt != NULL) |
gertk | 0:b612024f5aee | 702 | { |
gertk | 0:b612024f5aee | 703 | PC -= offset; |
gertk | 0:b612024f5aee | 704 | parm = read16(ctx, PC); |
gertk | 0:b612024f5aee | 705 | |
gertk | 0:b612024f5aee | 706 | if (entries[opcode].operand_type == OP_NONE) |
gertk | 0:b612024f5aee | 707 | size++; |
gertk | 0:b612024f5aee | 708 | else |
gertk | 0:b612024f5aee | 709 | size += 2; |
gertk | 0:b612024f5aee | 710 | if (entries[opcode].operand_type != OP_WORD) |
gertk | 0:b612024f5aee | 711 | { |
gertk | 0:b612024f5aee | 712 | parm &= 0xFF; |
gertk | 0:b612024f5aee | 713 | size--; |
gertk | 0:b612024f5aee | 714 | } |
gertk | 0:b612024f5aee | 715 | |
gertk | 0:b612024f5aee | 716 | if (decode) |
gertk | 0:b612024f5aee | 717 | sprintf(decode, fmt, parm); |
gertk | 0:b612024f5aee | 718 | |
gertk | 0:b612024f5aee | 719 | PC += offset; |
gertk | 0:b612024f5aee | 720 | break; |
gertk | 0:b612024f5aee | 721 | } |
gertk | 0:b612024f5aee | 722 | else if (entries[opcode].table != NULL) |
gertk | 0:b612024f5aee | 723 | { |
gertk | 0:b612024f5aee | 724 | current = entries[opcode].table; |
gertk | 0:b612024f5aee | 725 | entries = current->entries; |
gertk | 0:b612024f5aee | 726 | offset = current->opcode_offset; |
gertk | 0:b612024f5aee | 727 | } |
gertk | 0:b612024f5aee | 728 | |
gertk | 0:b612024f5aee | 729 | else |
gertk | 0:b612024f5aee | 730 | { |
gertk | 0:b612024f5aee | 731 | if (decode != NULL) |
gertk | 0:b612024f5aee | 732 | strcpy(decode, "NOP (ignored)"); |
gertk | 0:b612024f5aee | 733 | break; |
gertk | 0:b612024f5aee | 734 | } |
gertk | 0:b612024f5aee | 735 | } while(1); |
gertk | 0:b612024f5aee | 736 | |
gertk | 0:b612024f5aee | 737 | if (dump) |
gertk | 0:b612024f5aee | 738 | { |
gertk | 0:b612024f5aee | 739 | for (offset = 0; offset < size; offset++) |
gertk | 0:b612024f5aee | 740 | { |
gertk | 0:b612024f5aee | 741 | sprintf(tmp, "%02X", read8(ctx, ctx->PC + offset)); |
gertk | 0:b612024f5aee | 742 | strcat(dump, tmp); |
gertk | 0:b612024f5aee | 743 | } |
gertk | 0:b612024f5aee | 744 | } |
gertk | 0:b612024f5aee | 745 | } |
gertk | 0:b612024f5aee | 746 | |
gertk | 0:b612024f5aee | 747 | |
gertk | 0:b612024f5aee | 748 | void Z80RESET (Z80Context* ctx) |
gertk | 0:b612024f5aee | 749 | { |
gertk | 0:b612024f5aee | 750 | ctx->PC = 0x0000; |
gertk | 0:b612024f5aee | 751 | BR.F = 0; |
gertk | 0:b612024f5aee | 752 | ctx->IM = 0; |
gertk | 0:b612024f5aee | 753 | ctx->IFF1 = ctx->IFF2 = 0; |
gertk | 0:b612024f5aee | 754 | } |
gertk | 0:b612024f5aee | 755 | |
gertk | 0:b612024f5aee | 756 | |
gertk | 0:b612024f5aee | 757 | void Z80INT (Z80Context* ctx, byte value) |
gertk | 0:b612024f5aee | 758 | { |
gertk | 0:b612024f5aee | 759 | if (!ctx->IFF1) |
gertk | 0:b612024f5aee | 760 | return; |
gertk | 0:b612024f5aee | 761 | |
gertk | 0:b612024f5aee | 762 | if (ctx->IM == 0) |
gertk | 0:b612024f5aee | 763 | { |
gertk | 0:b612024f5aee | 764 | /* FIXME What to do? */ |
gertk | 0:b612024f5aee | 765 | /* opcode = Val; |
gertk | 0:b612024f5aee | 766 | execute();*/ |
gertk | 0:b612024f5aee | 767 | } |
gertk | 0:b612024f5aee | 768 | else if (ctx->IM == 1) |
gertk | 0:b612024f5aee | 769 | { |
gertk | 0:b612024f5aee | 770 | doPush(ctx, ctx->PC); |
gertk | 0:b612024f5aee | 771 | ctx->PC = 0x0038; |
gertk | 0:b612024f5aee | 772 | } |
gertk | 0:b612024f5aee | 773 | else if (ctx->IM == 2) |
gertk | 0:b612024f5aee | 774 | { |
gertk | 0:b612024f5aee | 775 | doPush(ctx, ctx->PC); |
gertk | 0:b612024f5aee | 776 | ctx->PC = (ctx->I << 8) | value; |
gertk | 0:b612024f5aee | 777 | } |
gertk | 0:b612024f5aee | 778 | } |
gertk | 0:b612024f5aee | 779 | |
gertk | 0:b612024f5aee | 780 | |
gertk | 0:b612024f5aee | 781 | void Z80NMI (Z80Context* ctx) |
gertk | 0:b612024f5aee | 782 | { |
gertk | 0:b612024f5aee | 783 | ctx->IFF1 = 0; |
gertk | 0:b612024f5aee | 784 | doPush(ctx, ctx->PC); |
gertk | 0:b612024f5aee | 785 | ctx->PC = 0x0066; |
gertk | 0:b612024f5aee | 786 | } |