Xemu [doxygen]  hyppo 0a42be3a057156924bc1b626a687bd6e27349c45 @ Sat 19 Mar 02:15:11 CET 2022
z8k1.c
Go to the documentation of this file.
1 /* Z8001 CPU emulator
2  * Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu
3  * Copyright (C)2018 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
4  * --------------------------------------------------------------------------------------
5  * Written from the technical manual of the Z8000 released by Zilog by me,
6  * so it can be very ugly, strange and incorrect code, especially, because
7  * Z8000 is a new thing me, first try to even get to know it ...
8  * In many cases, the source is about the most crude solution, far from being
9  * optimized. Also, Z8K though being 16 bit CPU, the internal emu struct is 8 bit
10  * based mainly to simplify things and not to be confused with different byte order
11  * between Z8K and emu host or similar issues.
12  * --------------------------------------------------------------------------------------
13  * My main problem was: I couldn't find any existing open source Z8001 emulation.
14  * MAME has "something" but MAME's license is "strange" and also it markes the emulation
15  * as "non-working". Also it's C++ what I couldn't even understand. So I haven't even
16  * tried to use that resource of course, other than checking out the binary itself if
17  * it can emulate a Commodore 900. Some resources mention that Commodore 900 is a "rather
18  * simple typical Z8001 based machine". OK, I've tried to find other Z8001 based
19  * machines. I could find P8000 system which uses Z8001, and it has an emulator.
20  * But well, no source at all. Ok then, so I give up, I have to write my own from
21  * zero ...
22  * --------------------------------------------------------------------------------------
23  * This file was extremely useful for me:
24  * https://raw.githubusercontent.com/bsdphk/PyRevEng/master/cpus/z8000_instructions.txt
25  * since I don't have the Z8000 manual only a poor quality scanned PDF, and it was
26  * a fantasic way to write a python program myself (not the one in PyRevEng!) to generate
27  * the skeleton of the big switch/case statement and comments on the opcode composition.
28  * Surely, maybe even more can be generated right from the listing file, but most of the
29  * code is hand-written here anyway after this step.
30 
31  ****************************************************************************************
32 
33 This program is free software; you can redistribute it and/or modify
34 it under the terms of the GNU General Public License as published by
35 the Free Software Foundation; either version 2 of the License, or
36 (at your option) any later version.
37 
38 This program is distributed in the hope that it will be useful,
39 but WITHOUT ANY WARRANTY; without even the implied warranty of
40 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
41 GNU General Public License for more details.
42 
43 You should have received a copy of the GNU General Public License
44 along with this program; if not, write to the Free Software
45 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
46 
47 
48 #include "xemu/emutools.h"
49 #include "z8k1.h"
50 
51 // Undefine this, to see compiler errors we need to fix cycles at
52 //#define TODO_CYCLES 1
53 
54 
55 #define BEGIN do{
56 #define END }while(0);break;
57 #define OPCODE(n) END case n: BEGIN
58 
59 
60 #define DO_DISASM
61 #define DO_EXEC 1
62 
63 #define FLAG_CARRY 0x80
64 #define FLAG_ZERO 0x40
65 #define FLAG_SIGN 0x20
66 #define FLAG_PV 0x10
67 #define FLAG_DA 0x08
68 #define FLAG_HC 0x04
69 #define F_CARRY_BOOL (!!(z8k1.flags & FLAG_CARRY))
70 #define F_ZERO_BOOL (!!(z8k1.flags & FLAG_ZERO))
71 #define F_SIGN_BOOL (!!(z8k1.flags & FLAG_SIGN))
72 #define F_PV_BOOL (!!(z8k1.flags & FLAG_PV))
73 #define F_DA_BOOL (!!(z8k1.flags & FLAG_DA))
74 #define F_HC_BOOL (!!(z8k1.flags & FLAG_HC))
75 
76 
77 // Lower 3 bits are not used.
78 // SEG: 1 = CPU in segmented mode (not for Z8002)
79 // SYS: 1 = CPU is in system mode (privileged opcodes can be used, stack pointer changes etc - priv ops in user mode causes traps)
80 // EPA: 1 = extended processing architecture (when 0, EPA ops cause traps)
81 // VIE: 1 = vectored interrupts enabled
82 // NVIE: 1 = non-vectored interrupts enabled
83 #define FCW_SEG 0x80
84 #define FCW_SYS 0x40
85 #define FCW_EPA 0x20
86 #define FCW_VIE 0x10
87 #define FCW_NVIE 0x08
88 #define FCW_ALL_MASK (FCW_SEG|FCW_SYS|FCW_EPA|FCW_VIE|FCW_NVIE)
89 
90 
91 
92 #define IS_SEGMENTED_MODE (z8k1.fcw & FCW_SEG)
93 #define IS_SYSTEM_MODE (z8k1.fcw & FCW_SYS)
94 #define IS_USER_MODE (!(IS_SYSTEM_MODE))
95 
96 static int do_disasm = 1;
97 
98 
99 #ifdef DO_DISASM
100 #define DISASM(fmt,...) do { if (XEMU_UNLIKELY(do_disasm)) DEBUGPRINT("%02X:%04X %04X " fmt NL, z8k1.codeseg, pc_orig, opc, __VA_ARGS__); } while(0)
101 #else
102 #define DISASM(fmt,...)
103 #endif
104 
105 
106 
107 #define NOT_EMULATED_OPCODE() FATAL("ERROR: Opcode not emulated: $%04X at $%02X:%04X", opc, z8k1.codeseg, pc_orig)
108 #define NOT_EMULATED_OPCODE_VARIANT() FATAL("ERROR: Opcode VARIANT not emulated: $%04X at $%02X:%04X", opc, z8k1.codeseg, pc_orig)
109 #define RESERVED_OPCODE() FATAL("ERROR: Reserved opcode: $%04X at $%02X:%04X\n", opc, z8k1.codeseg, pc_orig);
110 
111 
112 // The *internal* (to this emulator, not for Z8000!) representation
113 // of the general purpose registers. Internally, we use 8 bit scheme,
114 // that's why we have 32 of them, and not 16. Note, that Z8000 register
115 // reference encoding is a bit tricky, ie it can only do byte based
116 // reference for the first 8 16-bit register, but can access all of
117 // them as 16 bit versions, and also 32/64 bit access can be done.
118 // Logically we use the register file in this order:
119 // HIGH byte of REG0, LOW byte of REG0, HIGH byte of REG1, LOW byte of REG1, etc ..
120 // for 16 bits registers. See the macro REG8INDEX().
121 // Also, this is the *actual* and *used* register set. Things like user/system
122 // mode stack etc is not handled, and must be COPIED the appropriate one here
123 // on CPU mode change, etc!
124 static struct {
126  Uint8 fcw, flags; // for real, these are one word in most cases
134  //int m1; // FIXME: no sane "bus mode" (encoded with 4 bits) are used in emulation. this wanted to mean the opcode fetch though if set in read mem callback
138 } z8k1;
139 
140 
141 #ifdef DO_DISASM
142 static const char *__reg8names__[16] = {
143  "RH0", "RH1", "RH2", "RH3", "RH4", "RH5", "RH6", "RH7",
144  "RL0", "RL1", "RL2", "RL3", "RL4", "RL5", "RL6", "RL7"
145 };
146 #define reg8names(n) __reg8names__[(n) & 0xF]
147 static const char *__reg16names__[16] = {
148  "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
149  "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15"
150 };
151 #define reg16names(n) __reg16names__[(n) & 0xF]
152 static const char *__reg32names__[16] = {
153  "RR0", "RR0?", "RR2", "RR2?", "RR4", "RR4?", "RR6", "RR6?",
154  "RR8", "RR8?", "RR10", "RR10?", "RR12", "RR12?", "RR14", "RR14?"
155 };
156 #define reg32names(n) __reg32names__[(n) & 0xF]
157 static const char *__reg64names__[16] = {
158  "RQ0", "RQ0?", "RQ0??", "RQ0???", "RQ4", "RQ4?", "RQ4??", "RQ4???",
159  "RQ8", "RQ8?", "RQ8??", "RQ8???", "RQ12", "RQ12?", "RQ12??", "RQ12???"
160 };
161 #define reg64names(n) __reg64names__[(n) & 0xF]
162 static const char *__ccnames__[16] = {
163  "F", "LT", "LE", "ULE", "PE", "MI", "Z", "C",
164  "T", "GE", "GT", "UGT", "PO", "PL", "NZ", "NC"
165 };
166 #define ccnames(n) __ccnames__[(n) & 0xF]
167 #endif
168 
169 
170 
171 static Uint16 READCODE ( void )
172 {
173  Uint16 ret;
174  if (XEMU_UNLIKELY(z8k1.pc & 1))
175  FATAL("READCODE() at odd address $%04X", z8k1.pc);
176  ret = z8k1_read_code_cb(z8k1.codeseg, z8k1.pc);
177  z8k1.pc += 2;
178  //z8k1.opfetch_cycle++;
179  return ret;
180 }
181 
182 // Check conditions based on flags, with the "cc" field of the opcode
183 // Note: Z8K has "T" and "F" codes as well, being always True and always False (though "F" sounds a bit useless, T can be useful!)
184 // Note: some of the coniditions have more names, ie "S" is also "MI" minus, etc etc ...
185 static int check_cc ( int cc )
186 {
187  switch (cc & 0xF) {
188  case 0x0: // F: always false!
189  return 0;
190  case 0x1: // LT: less-than: S XOR V = 1, that is: S != V
191  return F_SIGN_BOOL ^ F_PV_BOOL;
192  case 0x2: // LE: less than or equal: Z OR (S XOR V) = 1
193  return F_ZERO_BOOL | (F_SIGN_BOOL ^ F_PV_BOOL);
194  case 0x3: // ULE: unsigned less than or equal: (C OR Z) = 1
195  return F_CARRY_BOOL | F_ZERO_BOOL;
196  case 0x4: // OV/PE = overflow or parity even
197  return F_PV_BOOL;
198  case 0x5: // MI = minus, test for S=1
199  return F_SIGN_BOOL;
200  case 0x6: // EQ/Z = equal or zero, test for Z=1
201  return F_ZERO_BOOL;
202  case 0x7: // ULT/carry
203  return F_CARRY_BOOL;
204  case 0x8: // T: always true!
205  return 1;
206  case 0x9: // GE: greater than or equal: S XOR V = 0, that is: S == V
207  return !(F_SIGN_BOOL ^ F_PV_BOOL);
208  case 0xA: // GT: greater than: Z OR (S XOR V) = 0
209  return !(F_ZERO_BOOL | (F_SIGN_BOOL ^ F_PV_BOOL));
210  case 0xB: // UGT: unsigned greater than: ((C = 0) AND (Z = 0)) = 1
211  return (!F_CARRY_BOOL) & (!F_ZERO_BOOL);
212  case 0xC: //
213  return !(F_PV_BOOL);
214  case 0xD: //
215  return !(F_SIGN_BOOL);
216  case 0xE: //
217  return !(F_ZERO_BOOL);
218  case 0xF: //
219  return !(F_CARRY_BOOL);
220  }
221  FATAL("Cannot happen"); // clang is stupid, cannot figure out that all cases are handled ...
222 }
223 
224 
225 
226 
227 #define F_ZERO_BY8(v) (((v) & 0xFF) ? 0 : FLAG_ZERO)
228 #define F_SIGN_BY8(v) (((v) & 0x80) ? FLAG_SIGN : 0)
229 #define F_CARRY_BY8(v) (((v) & 0x100) ? FLAG_CARRY : 0)
230 #define F_OVERFLOW_BY8(ad1,ad2,res) (((((ad1) & 0x80) == ((ad2) & 0x80)) && (((ad1) & 0x80) != ((res) & 0x80))) ? FLAG_PV : 0)
231 
232 #define F_ZERO_BY16(v) (((v) & 0xFFFF) ? 0 : FLAG_ZERO)
233 #define F_SIGN_BY16(v) (((v) & 0x8000) ? FLAG_SIGN : 0)
234 #define F_CARRY_BY16(v) (((v) & 0x10000) ? FLAG_CARRY : 0)
235 #define F_OVERFLOW_BY16(ad1,ad2,res) (((((ad1) & 0x8000) == ((ad2) & 0x8000)) && (((ad1) & 0x8000) != ((res) & 0x8000))) ? FLAG_PV : 0)
236 
237 #define F_PARITY_BY8(v) yay
238 #define F_PARITY_BY16(v) yay
239 
240 #define F_HALFCARRY_BY8(ad1,ad2,res) ((((ad1) ^ (ad2) ^ (res)) & 16) ? FLAG_HC : 0)
241 
242 
243 
244 
245 
246 
247 
248 // WARNING! Register number encoding used by Z8K is "logical" EXCEPT OF
249 // byte registers! This REG8INDEX can/must be used when/only 8 bit registers
250 // are accessed. In that case, this macro even handled an out-of range index.
251 #define REG8INDEX(index) ((((index)&7)<<1)|(((index)&8)>>3))
252 
253 
254 // Nibbles of the word from 3 (MS-nib) to 0
255 // I am still not sure this word "nibble" should be "nible" "nibble" "nyble" or "nybble" ...
256 #define NIB3(n) (((n) >> 12) & 0xF)
257 #define NIB2(n) (((n) >> 8) & 0xF)
258 #define NIB1(n) (((n) >> 4) & 0xF)
259 #define NIB0(n) ((n) & 0xF)
260 
261 #define OPCNIB3 NIB3(opc)
262 #define OPCNIB2 NIB2(opc)
263 #define OPCNIB1 NIB1(opc)
264 #define OPCNIB0 NIB0(opc)
265 
266 
267 static inline Uint8 GetReg8 ( int index ) // Get register value according to a 8 bit Z8K encoded register
268 {
269  return (index & 8) ? (z8k1.regs[index & 7] & 0xFF) : (z8k1.regs[index & 7] >> 8);
270 }
271 
272 static inline void SetReg8 ( int index, Uint8 data )
273 {
274  if (index & 8)
275  z8k1.regs[index & 7] = (z8k1.regs[index & 7] & 0xFF00) | data;
276  else
277  z8k1.regs[index & 7] = (z8k1.regs[index & 7] & 0x00FF) | (data << 8);
278 }
279 
280 static inline Uint16 GetReg16 ( int index )
281 {
282  return z8k1.regs[index & 0xF];
283 }
284 
285 static inline void SetReg16 ( int index, Uint8 data )
286 {
287  z8k1.regs[index & 0xF] = data;
288 }
289 
290 static inline Uint32 GetReg32 ( int index )
291 {
292  index &= 0xE;
293  return ((Uint32)z8k1.regs[index] << 16) | (Uint32)z8k1.regs[index + 1];
294 }
295 
296 static inline void SetReg32 ( int index, Uint32 data )
297 {
298  index &= 0xE;
299  z8k1.regs[index] = data >> 16;
300  z8k1.regs[index + 1] = data & 0xFFFF;
301 }
302 
303 
304 #if 0
305 // that is tricky ... it seems, Z8K wastes a byte to have word aligned
306 // immediate byte value in the code,
307 // but it's unclear that the low or high byte is used actually to fill
308 // a register in case of a 8 bit immediate data "normally encoded".
309 // (Z8000 manual seems to indicate that both of low/high bytes should
310 // have the same value, so it gives the hint, that it's based on the
311 // actual 8 bit register used lo or hi 8 bit part of a register)
312 // I am just guessing that the low/hi usage is connected to the lo/hi
313 // 8 bit register selected ...
314 // Index is the encoded register number
315 static inline Uint8 GetVal8FromImmediateWord ( int index, Uint16 data )
316 {
317  return (index & 8) ? (data & 0xFF) : (data >> 8);
318 }
319 
320 #define IMMEDBYTEFROMWORD(index,n) (((n)>>(((index)&8)?0:8))&0xFF)
321 
322 
323 static inline void SetReg8FromWord ( int index, Uint16 data )
324 {
325  if (index & 8)
326  z8k1.regs[index & 7] = (z8k1.regs[index & 7] & 0xFF00) | (data & 0x00FF);
327  else
328  z8k1.regs[index & 7] = (z8k1.regs[index & 7] & 0x00FF) | (data & 0xFF00);
329 }
330 
331 static inline void SetReg16 ( int index, Uint16 data )
332 {
333  index &= 0xE;
334  z8k1.RegisterFile[index] = data >> 8;
335  z8k1.RegisterFile[index + 1] = data & 0xFF;
336 }
337 #endif
338 
339 #if 0
340 // that is tricky ... it seems, Z8K wastes a byte to have word aligned
341 // but it's unclear that the low or high byte is used actually to fill
342 // a register in case of an immediate data "normally encoded".
343 // I am just guessing that the low/hi usage is connected to the lo/hi
344 // 8 bit register selected ...
345 static inline void SetReg8FromCodeRead16 ( int index )
346 {
347  Uint16 data = READCODE();
348  index = REG8INDEX(index);
349  RegisterFile[index] = (index & 1) ? (data & 0xFF) : (data >> 8);
350 }
351 
352 static inline void SetReg16FromCodeRead ( int index )
353 {
354  Uint16 data = READCODE();
355  index &= 0xE;
356  RegisterFile[index ] = data >> 8;
357  RegisterFile[index + 1] = data & 0xFF;
358 }
359 
360 static inline void SetReg32FromCodeRead ( int index )
361 {
362  Uint16 data = READCODE();
363  index &= 0xC;
364  RegisterFile[index ] = data >> 8;
365  RegisterFile[index + 1] = data & 0xFF;
366  data = READCODE();
367  RegisterFile[index + 2] = data >> 8;
368  RegisterFile[index + 3] = data & 0xFF;
369 }
370 #endif
371 
372 static inline Uint8 IncReg8 ( int index, int incval )
373 {
374  Uint8 temp = incval + GetReg8(index);
375  SetReg8(index, temp);
376  return temp;
377 }
378 
379 
380 static inline Uint16 IncReg16 ( int index, int incval )
381 {
382  z8k1.regs[index & 0xF] += incval;
383  return z8k1.regs[index & 0xF];
384 }
385 
386 #ifdef DO_DISASM
387 static char disasm_get_address_code[5+5+1];
388 static char disasm_get_address[5+3+1+1];
389 #endif
390 
391 
392 static void get_address ( void )
393 {
394  if (IS_SEGMENTED_MODE) {
395  // segmented mode
396  int seg = READCODE();
397  z8k1.use_seg = (seg >> 8) & 0x7F;
398  if (seg & 0x8000) {
399  z8k1.use_ofs = READCODE();
400 #ifdef DO_DISASM
401  sprintf(disasm_get_address_code, "%04X %04X", seg, z8k1.use_ofs);
402  sprintf(disasm_get_address, "$%02X:$%04X", z8k1.use_seg, z8k1.use_ofs);
403 #endif
404  z8k1.get_address_mode = 1;
405  } else {
406  z8k1.use_ofs = seg & 0xFF;
407 #ifdef DO_DISASM
408  sprintf(disasm_get_address_code, "%04X", seg);
409  sprintf(disasm_get_address, "$%02X:$%02X", z8k1.use_seg, z8k1.use_ofs);
410 #endif
411  z8k1.get_address_mode = 2;
412  }
413  } else {
414  // nonsegmented mode, simple reads a word as the address
415  z8k1.use_seg = 0;
416  z8k1.use_ofs = READCODE();
417 #ifdef DO_DISASM
418  sprintf(disasm_get_address_code, "%04X", z8k1.use_ofs);
419  sprintf(disasm_get_address, "$%04X", z8k1.use_ofs);
420 #endif
421  z8k1.get_address_mode = 0;
422  }
423 }
424 
425 
426 
427 #if 0
428 static Uint16 fetch_address ()
429 {
430  if (IS_SEGMENTED_MODE) {
431  Uint8 seg = READCODE_HI();
432  if (seg & 0x80) {
433  cycles_extra_fetch = 3;
434  use_seg = seg & 0x7F;
435  pc++; // FIXME: ignore one byte with segmented-long offset
436  Uint16 ret = READCODE_HI() << 8;
437  return ret | READCODE_LO();
438  } else {
439  use_seg = seg;
440  return READCODE_LO();
441  }
442  } else {
443  use_seg = 0; // FIXME: when non-segmented mode, it's the right way?
444  Uint16 ret = READCODE_HI() << 8;
445  return ret | READCODE_LO();
446  }
447 }
448 #endif
449 
450 
451 
452 static void set_fcw_byte ( Uint8 newfcw )
453 {
454  newfcw &= FCW_ALL_MASK;
455  // Check mode (system/normal) and "clone" stack pointer (+seg) to the normal register file
456  // with backing up for the old mode. That is, RegisterFile always reflects the current CPU
457  // mode, but separate stack pointer/seg is stored for both modes in my emulation.
458  if ((newfcw & FCW_SYS) != (z8k1.fcw & FCW_SYS)) {
459  if (newfcw & FCW_SYS) { // CPU mode transition: normal -> system
460  DEBUGPRINT("Z8000: FCW: CPU mode change: normal -> system" NL);
461  // backup normal stack pointer + seg
462  z8k1.stackptrusr = GetReg16(15);
463  z8k1.stacksegusr = (GetReg16(14) >> 8) & 0x7F;
464  // copy-in system stack pointer + seg
465  SetReg16(15, z8k1.stackptrsys);
466  SetReg16(14, z8k1.stacksegsys << 8);
467  } else { // CPU mode transition: system -> normal
468  DEBUGPRINT("Z8000: FCW: CPU mode change: system -> normal" NL);
469  // backip system stack pointer + seg
470  z8k1.stackptrsys = GetReg16(15);
471  z8k1.stacksegsys = (GetReg16(14) >> 8) & 0x7F;
472  // copy-in normal stack pointer + seg
473  SetReg16(15, z8k1.stackptrusr);
474  SetReg16(14, z8k1.stacksegusr << 8);
475  }
476  }
477  if ((newfcw & FCW_SEG) != (z8k1.fcw & FCW_SEG)) {
478  DEBUGPRINT("Z8000: FCW: CPU segmented change: %s" NL, (newfcw & FCW_SEG) ? "ON" : "OFF");
479  }
480  if (newfcw != z8k1.fcw)
481  DEBUGPRINT("Z8000: FCW: %02X -> %02X" NL, z8k1.fcw, newfcw);
482  z8k1.fcw = newfcw;
483 }
484 
485 
486 
487 void z8k1_reset ( void )
488 {
489  memset(z8k1.regs, 0, sizeof z8k1.regs);
490  z8k1.refresh = 0; // refresh register
491  z8k1.psaseg = 0;
492  z8k1.psaofs = 0;
493  // You should NEVER directly access these! Let these set_fcw_byte() to handle.
494  // Teset is the sole exception of this rule, since set_fcw_byte() will clone from these,
495  // and can be unititalized otherwise.
496  // The other exception will be the privileges instruction involves normal (user mode)
497  // stack pointer set/queried from system mode, see the LDCTL opcode emulations.
498  z8k1.stacksegusr = 0;
499  z8k1.stackptrusr = 0;
500  z8k1.stacksegsys = 0;
501  z8k1.stackptrsys = 0;
502  // Z8K1 initializes some registers near the beginning of the system memory
503  Uint16 data = z8k1_read_code_cb(0, 2);
504  set_fcw_byte(data >> 8); // FCW byte (hi byte of the word)
505  // the CPU flags (actually FCW + flags form a word but anyway, I handle as two separated entities, easier and quickier to manipulate in opcode emulation,
506  // since flags are often modified but the "real' FCW part is kinda limited what can modify it, only a few privileged opcodes, which must call
507  // set_fcw_byte anyway to take care about normal/system mode transition and so on)
508  // Flags has unused bits at pos 0,1. Be careful, documents often call FCW for the whole word, ie the lower byte being the "traditional" CPU flags!
509  z8k1.flags = data & 0xFC;
510  data = z8k1_read_code_cb(0, 4);
511  z8k1.codeseg = (data >> 8) & 0x7F; // code segment, Z8K1 uses 7 bits segment numbers! [low byte of this word is unused - AFAIK ...]
512  z8k1.pc = z8k1_read_code_cb(0, 6); // also initialize the PC itself
513  printf("Z8000: reset -> FCW=$%02X%02X SEG=$%02X PC=$%04X\n" NL, z8k1.fcw, z8k1.flags, z8k1.codeseg, z8k1.pc);
514 }
515 
516 void z8k1_init ( void )
517 {
518 }
519 
520 int z8k1_step ( int cycles_limit )
521 {
522  int cycles = 0;
523  do {
524  int pc_orig = z8k1.pc;
525  //z8k1.opfetchcycle = 0;
526  Uint16 opc = READCODE();
527  switch (opc >> 8) {
528  // the seems to be crazy order of opcodes has a reason: the opcode
529  // construction of Z8K, to keep opcodes closer with different addr.modes ...
530  // this is not always makes things that way, but in mode cases it does
531 
532  /*************************** OPC-HI = $00 ***************************/
533  case 0x00:
534  // ADDB Rbd,#data |0 0|0 0 0 0 0 0|0 0 0 0| Rbd
535  // ADDB Rd,@Rs {BYTE} |0 0|0 0 0 0 0 0| Rs!=0 | Rd
537  break;
538 
539  /*************************** OPC-HI = $01 ***************************/
540  case 0x01:
541  // ADD Rd,#data |0 0|0 0 0 0 0 1|0 0 0 0| Rd
542  // ADD Rd,@Rs {WORD} |0 0|0 0 0 0 0 1| Rs!=0 | Rd
544  break;
545 
546  /*************************** OPC-HI = $40 ***************************/
547  case 0x40:
548  // ADDB Rd,address {BYTE} |0 1|0 0 0 0 0 0|0 0 0 0| Rd
549  // ADDB Rd,addr(Rs) {BYTE} |0 1|0 0 0 0 0 0| Rs!=0 | Rd
551  break;
552 
553  /*************************** OPC-HI = $41 ***************************/
554  case 0x41:
555  // ADD Rd,address {WORD} |0 1|0 0 0 0 0 1|0 0 0 0| Rd
556  // ADD Rd,addr(Rs) {WORD} |0 1|0 0 0 0 0 1| Rs!=0 | Rd
558  break;
559 
560  /*************************** OPC-HI = $80 ***************************/
561  case 0x80:
562  // ADDB Rd,Rs {BYTE} |1 0|0 0 0 0 0 0| Rs | Rd
564  break;
565 
566  /*************************** OPC-HI = $81 ***************************/
567  case 0x81:
568  // ADD Rd,Rs {WORD} |1 0|0 0 0 0 0 1| Rs | Rd
570  break;
571 
572  /*************************** OPC-HI = $02 ***************************/
573  case 0x02:
574  // SUBB Rbd,#data |0 0|0 0 0 0 1 0|0 0 0 0| Rbd
575  // SUB Rd,@Rs {BYTE} |0 0|0 0 0 0 1 0| Rs!=0 | Rd
577  break;
578 
579  /*************************** OPC-HI = $03 ***************************/
580  case 0x03:
581  // SUB Rd,#data |0 0|0 0 0 0 1 1|0 0 0 0| Rd
582  // SUB Rd,@Rs {WORD} |0 0|0 0 0 0 1 1| Rs!=0 | Rd
584  break;
585 
586  /*************************** OPC-HI = $42 ***************************/
587  case 0x42:
588  // SUBB Rd,address {BYTE} |0 1|0 0 0 0 1 0|0 0 0 0| Rd
589  // SUBB Rd,addr(Rs) {BYTE} |0 1|0 0 0 0 1 0| Rs!=0 | Rd
591  break;
592 
593  /*************************** OPC-HI = $43 ***************************/
594  case 0x43:
595  // SUB Rd,address {WORD} |0 1|0 0 0 0 1 1|0 0 0 0| Rd
596  // SUB Rd,addr(Rs) {WORD} |0 1|0 0 0 0 1 1| Rs!=0 | Rd
598  break;
599 
600  /*************************** OPC-HI = $82 ***************************/
601  case 0x82:
602  // SUBB Rd,Rs {BYTE} |1 0|0 0 0 0 1 0| Rs | Rd
604  break;
605 
606  /*************************** OPC-HI = $83 ***************************/
607  case 0x83:
608  // SUB Rd,Rs {WORD} |1 0|0 0 0 0 1 1| Rs | Rd
609  DISASM("|%s\t%s,%s", "SUB", reg16names(OPCNIB0), reg16names(OPCNIB1));
610  if (DO_EXEC) {
611  int s = GetReg16(OPCNIB1), d = GetReg16(OPCNIB0), r = d - s;
612  z8k1.flags = (z8k1.flags & (FLAG_DA | FLAG_HC)) | F_CARRY_BY16(r) | F_ZERO_BY16(r) | F_SIGN_BY16(r) | F_OVERFLOWSUB_BY16(s,d,r); // FIXME: overflow on SUB is different!!!!!!!
613  SetReg16(OPCNIB0, r);
614  cycles += 4;
615  }
616  break;
617 
618  /*************************** OPC-HI = $04 ***************************/
619  case 0x04:
620  // ORB Rbd,#data |0 0|0 0 0 1 0 0|0 0 0 0| Rbd
621  // ORB Rd,@Rs {BYTE} |0 0|0 0 0 1 0 0| Rs!=0 | Rd
623  break;
624 
625  /*************************** OPC-HI = $05 ***************************/
626  case 0x05:
627  // OR Rd,#data |0 0|0 0 0 1 0 1|0 0 0 0| Rd
628  // OR Rd,@Rs {WORD} |0 0|0 0 0 1 0 1| Rs!=0 | Rd
630  break;
631 
632  /*************************** OPC-HI = $44 ***************************/
633  case 0x44:
634  // ORB Rd,address {BYTE} |0 1|0 0 0 1 0 0|0 0 0 0| Rd
635  // ORB Rd,addr(Rs) {BYTE} |0 1|0 0 0 1 0 0| Rs!=0 | Rd
637  break;
638 
639  /*************************** OPC-HI = $45 ***************************/
640  case 0x45:
641  // OR Rd,address {WORD} |0 1|0 0 0 1 0 1|0 0 0 0| Rd
642  // OR Rd,addr(Rs) {WORD} |0 1|0 0 0 1 0 1| Rs!=0 | Rd
644  break;
645 
646  /*************************** OPC-HI = $84 ***************************/
647  case 0x84:
648  // ORB Rd,Rs {BYTE} |1 0|0 0 0 1 0 0| Rs | Rd
650  break;
651 
652  /*************************** OPC-HI = $85 ***************************/
653  case 0x85:
654  // OR Rd,Rs {WORD} |1 0|0 0 0 1 0 1| Rs | Rd
656  break;
657 
658  /*************************** OPC-HI = $06 ***************************/
659  case 0x06:
660  // ANDB Rbd,#data |0 0|0 0 0 1 1 0|0 0 0 0| Rbd
661  // ANDB Rd,@Rs {BYTE} |0 0|0 0 0 1 1 0| Rs!=0 | Rd
663  break;
664 
665  /*************************** OPC-HI = $07 ***************************/
666  case 0x07:
667  // AND Rd,#data |0 0|0 0 0 1 1 1|0 0 0 0| Rd
668  // AND Rd,@Rs {WORD} |0 0|0 0 0 1 1 1| Rs!=0 | Rd
670  break;
671 
672  /*************************** OPC-HI = $46 ***************************/
673  case 0x46:
674  // ANDB Rd,address {BYTE} |0 1|0 0 0 1 1 0|0 0 0 0| Rd
675  // ANDB Rd,addr(Rs) {BYTE} |0 1|0 0 0 1 1 0| Rs!=0 | Rd
677  break;
678 
679  /*************************** OPC-HI = $47 ***************************/
680  case 0x47:
681  // AND Rd,address {WORD} |0 1|0 0 0 1 1 1|0 0 0 0| Rd
682  // AND Rd,addr(Rs) {WORD} |0 1|0 0 0 1 1 1| Rs!=0 | Rd
684  break;
685 
686  /*************************** OPC-HI = $86 ***************************/
687  case 0x86:
688  // ANDB Rd,Rs {BYTE} |1 0|0 0 0 1 1 0| Rs | Rd
690  break;
691 
692  /*************************** OPC-HI = $87 ***************************/
693  case 0x87:
694  // AND Rd,Rs {WORD} |1 0|0 0 0 1 1 1| Rs | Rd
696  break;
697 
698  /*************************** OPC-HI = $08 ***************************/
699  case 0x08:
700  // XORB Rbd,#data |0 0|0 0 1 0 0 0|0 0 0 0| Rbd
701  // XORB Rd,@Rs {BYTE} |0 0|0 0 1 0 0 0| Rs!=0 | Rd
703  break;
704 
705  /*************************** OPC-HI = $09 ***************************/
706  case 0x09:
707  // XOR Rd,#data |0 0|0 0 1 0 0 1|0 0 0 0| Rd
708  // XOR Rd,@Rs {WORD} |0 0|0 0 1 0 0 1| Rs!=0 | Rd
710  break;
711 
712  /*************************** OPC-HI = $48 ***************************/
713  case 0x48:
714  // XORB Rd,address {BYTE} |0 1|0 0 1 0 0 0|0 0 0 0| Rd
715  // XORB Rd,addr(Rs) {BYTE} |0 1|0 0 1 0 0 0| Rs!=0 | Rd
717  break;
718 
719  /*************************** OPC-HI = $49 ***************************/
720  case 0x49:
721  // XOR Rd,address {WORD} |0 1|0 0 1 0 0 1|0 0 0 0| Rd
722  // XOR Rd,addr(Rs) {WORD} |0 1|0 0 1 0 0 1| Rs!=0 | Rd
724  break;
725 
726  /*************************** OPC-HI = $88 ***************************/
727  case 0x88:
728  // XORB Rd,Rs {BYTE} |1 0|0 0 1 0 0 0| Rs | Rd
730  break;
731 
732  /*************************** OPC-HI = $89 ***************************/
733  case 0x89:
734  // XOR Rd,Rs {WORD} |1 0|0 0 1 0 0 1| Rs | Rd
736  break;
737 
738  /*************************** OPC-HI = $0A ***************************/
739  case 0x0A:
740  // CPB Rbd,#data |0 0|0 0 1 0 1 0|0 0 0 0| Rbd
741  // CPB Rd,@Rs {BYTE} |0 0|0 0 1 0 1 0| Rs!=0 | Rd
743  break;
744 
745  /*************************** OPC-HI = $0B ***************************/
746  case 0x0B:
747  // CP Rd,#data |0 0|0 0 1 0 1 1|0 0 0 0| Rd
748  // CP Rd,@Rs {WORD} |0 0|0 0 1 0 1 1| Rs!=0 | Rd
750  break;
751 
752  /*************************** OPC-HI = $4A ***************************/
753  case 0x4A:
754  // CPB Rd,address {BYTE} |0 1|0 0 1 0 1 0|0 0 0 0| Rd
755  // CPB Rd,addr(Rs) {BYTE} |0 1|0 0 1 0 1 0| Rs!=0 | Rd
757  break;
758 
759  /*************************** OPC-HI = $4B ***************************/
760  case 0x4B:
761  // CP Rd,address {WORD} |0 1|0 0 1 0 1 1|0 0 0 0| Rd
762  // CP Rd,addr(Rs) {WORD} |0 1|0 0 1 0 1 1| Rs!=0 | Rd
764  break;
765 
766  /*************************** OPC-HI = $8A ***************************/
767  case 0x8A:
768  // CPB Rd,Rs {BYTE} |1 0|0 0 1 0 1 0| Rs | Rd
770  break;
771 
772  /*************************** OPC-HI = $8B ***************************/
773  case 0x8B:
774  // CP Rd,Rs {WORD} |1 0|0 0 1 0 1 1| Rs | Rd
776  break;
777 
778  /*************************** OPC-HI = $0C ***************************/
779  case 0x0C:
780  // CLRB @Rd {BYTE} |0 0|0 0 1 1 0 0| Rd!=0 |1 0 0 0
781  // COMB @Rd {BYTE} |0 0|0 0 1 1 0 0| Rd!=0 |0 0 0 0
782  // CPB @Rd,#data |0 0|0 0 1 1 0|0| Rd!=0 |0 0 0 1
783  // LDB @Rd,#data |0 0|0 0 1 1 0 0| Rd!=0 |0 1 0 1
784  // NEGB @Rd {BYTE} |0 0|0 0 1 1 0 0| Rd!=0 |0 0 1 0
785  // TESTB @Rd {BYTE} |0 0|0 0 1 1 0 0| Rd!=0 |0 1 0 0
786  // TSETB @Rd {BYTE} |0 0|0 0 1 1 0 0| Rd!=0 |0 1 1 0
788  break;
789 
790  /*************************** OPC-HI = $0D ***************************/
791  case 0x0D:
792  // CLR @Rd {WORD} |0 0|0 0 1 1 0 1| Rd!=0 |1 0 0 0
793  // COM @Rd {WORD} |0 0|0 0 1 1 0 1| Rd!=0 |0 0 0 0
794  // CP @Rd,#data |0 0|0 0 1 1 0|1| Rd!=0 |0 0 0 1
795  // LD @Rd,#data |0 0|0 0 1 1 0 1| Rd!=0 |0 1 0 1
796  // NEG @Rd {WORD} |0 0|0 0 1 1 0 1| Rd!=0 |0 0 1 0
797  // PUSH @Rd,#data |0 0|0 0 1 1 0 1| Rd!=0 |1 0 0 1
798  // TEST @Rd {WORD} |0 0|0 0 1 1 0 1| Rd!=0 |0 1 0 0
799  // TSET @Rd {WORD} |0 0|0 0 1 1 0 1| Rd!=0 |0 1 1 0
801  break;
802 
803  /*************************** OPC-HI = $4C ***************************/
804  case 0x4C:
805  // CLRB address {BYTE} |0 1|0 0 1 1 0 0|0 0 0 0|1 0 0 0
806  // CLRB addr(Rd) {BYTE} |0 1|0 0 1 1 0 0| Rd!=0 |1 0 0 0
807  // COMB address {BYTE} |0 1|0 0 1 1 0 0|0 0 0 0|0 0 0 0
808  // COMB addr(Rd) {BYTE} |0 1|0 0 1 1 0 0| Rd!=0 |0 0 0 0
809  // CPB address,#data |0 1|0 0 1 1 0|0|0 0 0 0|0 0 0 1
810  // CPB addr(Rd),#data |0 1|0 0 1 1 0|0| Rd!=0 |0 0 0 1
811  // LDB address,#data |0 1|0 0 1 1 0 0|0 0 0 0|0 1 0 1
812  // LDB addr(Rd),#data |0 1|0 0 1 1 0 0| Rd!=0 |0 1 0 1
813  // NEGB address {BYTE} |0 1|0 0 1 1 0 0|0 0 0 0|0 0 1 0
814  // NEGB addr(Rd) {BYTE} |0 1|0 0 1 1 0 0| Rd!=0 |0 0 1 0
815  // TESTB address {BYTE} |0 1|0 0 1 1 0 0|0 0 0 0|0 1 0 0
816  // TESTB addr(Rd) {BYTE} |0 1|0 0 1 1 0 0| Rd!=0 |0 1 0 0
817  // TSETB address {BYTE} |0 1|0 0 1 1 0 0|0 0 0 0|0 1 1 0
818  // TSETB addr(Rd) {BYTE} |0 1|0 0 1 1 0 0| Rd!=0 |0 1 1 0
820  break;
821 
822  /*************************** OPC-HI = $4D ***************************/
823  case 0x4D:
824  // CLR address {WORD} |0 1|0 0 1 1 0 1|0 0 0 0|1 0 0 0
825  // CLR addr(Rd) {WORD} |0 1|0 0 1 1 0 1| Rd!=0 |1 0 0 0
826  // COM address {WORD} |0 1|0 0 1 1 0 1|0 0 0 0|0 0 0 0
827  // COM addr(Rd) {WORD} |0 1|0 0 1 1 0 1| Rd!=0 |0 0 0 0
828  // CP address,#data |0 1|0 0 1 1 0|1|0 0 0 0|0 0 0 1
829  // CP addr(Rd),#data |0 1|0 0 1 1 0|1| Rd!=0 |0 0 0 1
830  // LD address,#data |0 1|0 0 1 1 0 1|0 0 0 0|0 1 0 1
831  // LD addr(Rd),#data |0 1|0 0 1 1 0 1| Rd!=0 |0 1 0 1
832  // NEG address {WORD} |0 1|0 0 1 1 0 1|0 0 0 0|0 0 1 0
833  // NEG addr(Rd) {WORD} |0 1|0 0 1 1 0 1| Rd!=0 |0 0 1 0
834  // TEST address {WORD} |0 1|0 0 1 1 0 1|0 0 0 0|0 1 0 0
835  // TEST addr(Rd) {WORD} |0 1|0 0 1 1 0 1| Rd!=0 |0 1 0 0
836  // TSET address {WORD} |0 1|0 0 1 1 0 1|0 0 0 0|0 1 1 0
837  // TSET addr(Rd) {WORD} |0 1|0 0 1 1 0 1| Rd!=0 |0 1 1 0
839  break;
840 
841  /*************************** OPC-HI = $8C ***************************/
842  case 0x8C:
843  // CLRB Rd {BYTE} |1 0|0 0 1 1 0 0| Rd |1 0 0 0
844  // COMB Rd {BYTE} |1 0|0 0 1 1 0 0| Rd |0 0 0 0
845  // LDCTLB FLAGS,Rbs |1 0 0 0 1 1 0 0| Rbs |1 0 0 1
846  // LDCTLB Rbd,FLAGS |1 0 0 0 1 1 0 0| Rbd |0 0 0 1
847  // NEGB Rd {BYTE} |1 0|0 0 1 1 0 0| Rd |0 0 1 0
848  // TESTB Rd {BYTE} |1 0|0 0 1 1 0 0| Rd |0 1 0 0
849  // TSETB Rd {BYTE} |1 0|0 0 1 1 0 0| Rd |0 1 1 0
851  break;
852 
853  /*************************** OPC-HI = $8D ***************************/
854  case 0x8D:
855  // CLR Rd {WORD} |1 0|0 0 1 1 0 1| Rd |1 0 0 0
856  // COM Rd {WORD} |1 0|0 0 1 1 0 1| Rd |0 0 0 0
857  // COMFLG flags |1 0 0 0 1 1 0 1| flags |0 1 0 1
858  // NEG Rd {WORD} |1 0|0 0 1 1 0 1| Rd |0 0 1 0
859  // NOP |1 0 0 0 1 1 0 1|0 0 0 0 0 1 1 1
860  // RESFLG flags |1 0|0 0 1 1 0 1| flags |0 0 1 1
861  // SETFLG flags |1 0 0 0 1 1 0 1| flags |0 0 0 1
862  // TEST Rd {WORD} |1 0|0 0 1 1 0 1| Rd |0 1 0 0
863  // TSET Rd {WORD} |1 0|0 0 1 1 0 1| Rd |0 1 1 0
865  break;
866 
867  /*************************** OPC-HI = $0E ***************************/
868  case 0x0E:
869  RESERVED_OPCODE();
870  break;
871 
872  /*************************** OPC-HI = $0F ***************************/
873  case 0x0F:
874  // EPU2MEM @Rd,#n |0 0|0 0 1 1 1 1| Rd!=0 |1 1|x x|x x x x x x x x x x x x| n-1
875  // MEM2EPU @Rd,#n |0 0|0 0 1 1 1 1| Rd!=0 |0 1|x x|x x x x x x x x x x x x| n-1
877  break;
878 
879  /*************************** OPC-HI = $4E ***************************/
880  case 0x4E:
881  RESERVED_OPCODE();
882  break;
883 
884  /*************************** OPC-HI = $4F ***************************/
885  case 0x4F:
886  // EPU2MEM addr(Rd),#n |0 1|0 0 1 1 1 1| Rd!=0 |1 1|x x|x x x x x x x x x x x x| n-1
887  // EPU2MEM address,#n |0 1|0 0 1 1 1 1|0 0 0 0|1 1|x x|x x x x x x x x x x x x| n-1
888  // MEM2EPU addr(Rd),#n |0 1|0 0 1 1 1 1| Rd!=0 |0 1|x x|x x x x x x x x x x x x| n-1
889  // MEM2EPU address,#n |0 1|0 0 1 1 1 1|0 0 0 0|0 1|x x|x x x x x x x x x x x x| n-1
891  break;
892 
893  /*************************** OPC-HI = $8E ***************************/
894  case 0x8E:
895  // FCW2EPU |1 0|0 0 1 1 1 0|x x x x|1 0|x x|x x x x|0 0 0 0|x x x x|0 0 0 0
896  // EPUINT #n |1 0|0 0 1 1 1 0|x x x x|0 1|x x x x x x x x x x x x x x| n-1
898  break;
899 
900  /*************************** OPC-HI = $8F ***************************/
901  case 0x8F:
902  // EPU2CPU Rd,#n |1 0|0 0 1 1 1 1|0|x x x|0 0|x x|x x x x| Rd |x x x x| n-1
903  // CPU2EPU Rs,#n |1 0|0 0 1 1 1 1|0|x x x|1 0|x x|x x x x| Rs |x x x x| n-1
904  // EPU2FCW |1 0|0 0 1 1 1 1|x x x x|0 0|x x|x x x x|0 0 0 0|x x x x|0 0 0 0
906  break;
907 
908  /*************************** OPC-HI = $10 ***************************/
909  case 0x10:
910  // CPL RRd,#data |0 0|0 1 0 0 0 0|0 0 0 0| RRd
911  // CPL RRd,@Rs |0 0|0 1 0 0 0 0| Rs!=0 | RRd
913  break;
914 
915  /*************************** OPC-HI = $11 ***************************/
916  case 0x11:
917  // PUSHL @Rd,@Rs |0 0|0 1 0 0 0 1| Rd!=0 | Rs!=0
919  break;
920 
921  /*************************** OPC-HI = $50 ***************************/
922  case 0x50:
923  // CPL RRd,address |0 1|0 1 0 0 0 0|0 0 0 0| RRd
924  // CPL RRd,addr(Rs) |0 1|0 1 0 0 0 0| Rs!=0 | RRd
926  break;
927 
928  /*************************** OPC-HI = $51 ***************************/
929  case 0x51:
930  // PUSHL @Rd,address |0 1|0 1 0 0 0 1| Rd!=0 |0 0 0 0
931  // PUSHL @Rd,addr(Rs) |0 1|0 1 0 0 0 1| Rd!=0 | Rs!=0
933  break;
934 
935  /*************************** OPC-HI = $90 ***************************/
936  case 0x90:
937  // CPL RRd,RRs |1 0|0 1 0 0 0 0| RRs | RRd
939  break;
940 
941  /*************************** OPC-HI = $91 ***************************/
942  case 0x91:
943  // PUSHL @Rd,RRs |1 0|0 1 0 0 0 1| Rd!=0 | RRs
945  break;
946 
947  /*************************** OPC-HI = $12 ***************************/
948  case 0x12:
949  // SUBL RRd,#data |0 0|0 1 0 0 1 0|0 0 0 0| RRd
950  // SUBL RRd,@Rs |0 0|0 1 0 0 1 0| Rs!=0 | RRd
952  break;
953 
954  /*************************** OPC-HI = $13 ***************************/
955  case 0x13:
956  // PUSH @Rd,@Rs |0 0|0 1 0 0 1 1| Rd!=0 | Rs!=0
958  break;
959 
960  /*************************** OPC-HI = $52 ***************************/
961  case 0x52:
962  // SUBL RRd,address |0 1|0 1 0 0 1 0|0 0 0 0| RRd
963  // SUBL RRd,addr(Rs) |0 1|0 1 0 0 1 0| Rs!=0 | RRd
965  break;
966 
967  /*************************** OPC-HI = $53 ***************************/
968  case 0x53:
969  // PUSH @Rd,address |0 1|0 1 0 0 1 1| Rd!=0 |0 0 0 0
970  // PUSH @Rd,addr(Rs) |0 1|0 1 0 0 1 1| Rd!=0 | Rs!=0
972  break;
973 
974  /*************************** OPC-HI = $92 ***************************/
975  case 0x92:
976  // SUBL RRd,RRs |1 0|0 1 0 0 1 0| RRs | RRd
978  break;
979 
980  /*************************** OPC-HI = $93 ***************************/
981  case 0x93:
982  // PUSH @Rd,Rs |1 0|0 1 0 0 1 1| Rd!=0 | Rs
984  break;
985 
986  /*************************** OPC-HI = $14 ***************************/
987  case 0x14:
988  // LDL RRd,@Rs |0 0|0 1 0 1 0 0| Rs!=0 | RRd
989  // LDL RRd,#data |0 0|0 1 0 1 0 0|0 0 0 0| RRd
990  if (OPCNIB1) {
992  } else {
993  Uint32 val = READCODE() << 16;
994  val |= READCODE();
995  DISASM("%04X %04X|%s\t%s,#$%08X", val >> 16, val & 0xFFFF, "LDL", reg32names(OPCNIB0), val);
996  if (DO_EXEC) {
997  SetReg32(OPCNIB0, val);
998  cycles += 11;
999  }
1000  }
1001  break;
1002 
1003  /*************************** OPC-HI = $15 ***************************/
1004  case 0x15:
1005  // POPL @Rd,@Rs |0 0|0 1 0 1 0 1| Rs!=0 | Rd!=0
1007  break;
1008 
1009  /*************************** OPC-HI = $54 ***************************/
1010  case 0x54:
1011  // LDL RRd,address |0 1|0 1 0 1 0 0|0 0 0 0| RRd
1012  // LDL RRd,addr(Rs) |0 1|0 1 0 1 0 0| Rs!=0 | RRd
1014  break;
1015 
1016  /*************************** OPC-HI = $55 ***************************/
1017  case 0x55:
1018  // POPL address,@Rs |0 1|0 1 0 1 0 1| Rs!=0 |0 0 0 0
1019  // POPL addr(Rd),@Rs |0 1|0 1 0 1 0 1| Rs!=0 | Rd!=0
1021  break;
1022 
1023  /*************************** OPC-HI = $94 ***************************/
1024  case 0x94:
1025  // LDL RRd,RRs |1 0|0 1 0 1 0 0| RRs | RRd
1027  break;
1028 
1029  /*************************** OPC-HI = $95 ***************************/
1030  case 0x95:
1031  // POPL RRd,@Rs |1 0|0 1 0 1 0 1| Rs!=0 | RRd
1033  break;
1034 
1035  /*************************** OPC-HI = $16 ***************************/
1036  case 0x16:
1037  // ADDL RRd,#data |0 0|0 1 0 1 1 0|0 0 0 0| RRd
1038  // ADDL RRd,@Rs |0 0|0 1 0 1 1 0| Rs!=0 | RRd
1040  break;
1041 
1042  /*************************** OPC-HI = $17 ***************************/
1043  case 0x17:
1044  // POP @Rd,@Rs |0 0|0 1 0 1 1 1| Rs!=0 | Rd!=0
1046  break;
1047 
1048  /*************************** OPC-HI = $56 ***************************/
1049  case 0x56:
1050  // ADDL RRd,address |0 1|0 1 0 1 1 0|0 0 0 0| RRd
1051  // ADDL RRd,addr(Rs) |0 1|0 1 0 1 1 0| Rs!=0 | RRd
1053  break;
1054 
1055  /*************************** OPC-HI = $57 ***************************/
1056  case 0x57:
1057  // POP address,@Rs |0 1|0 1 0 1 1 1| Rs!=0 |0 0 0 0
1058  // POP addr(Rd),@Rs |0 1|0 1 0 1 1 1| Rs!=0 | Rd!=0
1060  break;
1061 
1062  /*************************** OPC-HI = $96 ***************************/
1063  case 0x96:
1064  // ADDL RRd,RRs |1 0|0 1 0 1 1 0| RRs | RRd
1066  break;
1067 
1068  /*************************** OPC-HI = $97 ***************************/
1069  case 0x97:
1070  // POP Rd,@Rs |1 0|0 1 0 1 1 1| Rs!=0 | Rd
1072  break;
1073 
1074  /*************************** OPC-HI = $18 ***************************/
1075  case 0x18:
1076  // MULTL RQd,#data |0 0|0 1 1 0 0 0|0 0 0 0| RQd
1077  // MULTL RQd,@Rs |0 0|0 1 1 0 0 0| Rs!=0 | RQd
1079  break;
1080 
1081  /*************************** OPC-HI = $19 ***************************/
1082  case 0x19:
1083  // MULT RRd,#data |0 0|0 1 1 0 0 1|0 0 0 0| RRd
1084  // MULT RRd,@Rs |0 0|0 1 1 0 0 1| Rs!=0 | RRd
1086  break;
1087 
1088  /*************************** OPC-HI = $58 ***************************/
1089  case 0x58:
1090  // MULTL RQd,address |0 1|0 1 1 0 0 0|0 0 0 0| RQd
1091  // MULTL RQd,addr(Rs) |0 1|0 1 1 0 0 0| Rs!=0 | RQd
1093  break;
1094 
1095  /*************************** OPC-HI = $59 ***************************/
1096  case 0x59:
1097  // MULT RRd,address |0 1|0 1 1 0 0 1|0 0 0 0| RRd
1098  // MULT RRd,addr(Rs) |0 1|0 1 1 0 0 1| Rs!=0 | RRd
1100  break;
1101 
1102  /*************************** OPC-HI = $98 ***************************/
1103  case 0x98:
1104  // MULTL RQd,RRs |1 0|0 1 1 0 0 0| Rs | RRd
1106  break;
1107 
1108  /*************************** OPC-HI = $99 ***************************/
1109  case 0x99:
1110  // MULT RRd,Rs |1 0|0 1 1 0 0 1| Rs | RRd
1112  break;
1113 
1114  /*************************** OPC-HI = $1A ***************************/
1115  case 0x1A:
1116  // DIVL RQd,#data |0 0|0 1 1 0 1 0|0 0 0 0| RQd
1117  // DIVL RQd,@Rs |0 0|0 1 1 0 1 0| Rs!=0 | RQd
1119  break;
1120 
1121  /*************************** OPC-HI = $1B ***************************/
1122  case 0x1B:
1123  // DIV RRd,#data |0 0|0 1 1 0 1 1|0 0 0 0| RRd
1124  // DIV RRd,@Rs |0 0|0 1 1 0 1 1| Rs!=0 | RRd
1126  break;
1127 
1128  /*************************** OPC-HI = $5A ***************************/
1129  case 0x5A:
1130  // DIVL RQD,address |0 1|0 1 1 0 1 0|0 0 0 0| RQd
1131  // DIVL RQd,addr(Rs) |0 1|0 1 1 0 1 0| Rs!=0 | RQd
1133  break;
1134 
1135  /*************************** OPC-HI = $5B ***************************/
1136  case 0x5B:
1137  // DIV RRd,address |0 1|0 1 1 0 1 1|0 0 0 0| RRd
1138  // DIV RRd,addr(Rs) |0 1|0 1 1 0 1 1| Rs!=0 | RRd
1140  break;
1141 
1142  /*************************** OPC-HI = $9A ***************************/
1143  case 0x9A:
1144  // DIVL RQd,RRs |1 0|0 1 1 0 1 0| RRs | RQd
1146  break;
1147 
1148  /*************************** OPC-HI = $9B ***************************/
1149  case 0x9B:
1150  // DIV RRd,Rs |1 0|0 1 1 0 1 1| Rs | RRd
1152  break;
1153 
1154  /*************************** OPC-HI = $1C ***************************/
1155  case 0x1C:
1156  // LDM Rd,@Rs,#n |0 0|0 1 1 1 0 0| Rs!=0 |0 0 0 1|0 0 0 0| Rd |0 0 0 0| n-1
1157  // LDM @Rd,Rs,#n |0 0|0 1 1 1 0 0| Rd!=0 |1 0 0 1|0 0 0 0| Rs |0 0 0 0| n-1
1158  // TESTL @Rd |0 0|0 1 1 1 0 0| Rd!=0 |1 0 0 0
1160  break;
1161 
1162  /*************************** OPC-HI = $1D ***************************/
1163  case 0x1D:
1164  // LDL @Rd,RRs |0 0|0 1 1 1 0 1| Rd!=0 | RRs
1166  break;
1167 
1168  /*************************** OPC-HI = $5C ***************************/
1169  case 0x5C:
1170  // LDM Rd,address,#n |0 1|0 1 1 1 0 0|0 0 0 0|0 0 0 1|0 0 0 0| Rd |0 0 0 0| n-1
1171  // LDM Rd,addr(Rs),#n |0 1|0 1 1 1 0 0| Rs!=0 |0 0 0 1|0 0 0 0| Rd |0 0 0 0| n-1
1172  // LDM address,Rs,#n |0 1|0 1 1 1 0 0|0 0 0 0|1 0 0 1|0 0 0 0| Rs |0 0 0 0| n-1
1173  // LDM addr(Rd),Rs,#n |0 1|0 1 1 1 0 0| Rd!=0 |1 0 0 1|0 0 0 0| Rs |0 0 0 0| n-1
1174  // TESTL address |0 1|0 1 1 1 0 0|0 0 0 0|1 0 0 0
1175  // TESTL addr(Rd) |0 1|0 1 1 1 0 0| Rd!=0 |1 0 0 0
1177  break;
1178 
1179  /*************************** OPC-HI = $5D ***************************/
1180  case 0x5D:
1181  // LDL address,RRs |0 1|0 1 1 1 0 1|0 0 0 0| RRs
1182  // LDL addr(Rd),RRs |0 1|0 1 1 1 0 1| Rd!=0 | RRs
1184  break;
1185 
1186  /*************************** OPC-HI = $9C ***************************/
1187  case 0x9C:
1188  // TESTL RRd |1 0|0 1 1 1 0 0| RRd |1 0 0 0
1190  break;
1191 
1192  /*************************** OPC-HI = $9D ***************************/
1193  case 0x9D:
1194  RESERVED_OPCODE();
1195  break;
1196 
1197  /*************************** OPC-HI = $1E ***************************/
1198  case 0x1E:
1199  // JP cc,@Rd |0 0|0 1 1 1 1 0| Rd!=0 | cc
1200  // in segmented mode: RRd!
1202  break;
1203 
1204  /*************************** OPC-HI = $1F ***************************/
1205  case 0x1F:
1206  // CALL @Rd |0 0|0 1 1 1 1 1| Rd!=0 |0 0 0 0
1208  break;
1209 
1210  /*************************** OPC-HI = $5E ***************************/
1211  case 0x5E:
1212  // JP cc,address |0 1|0 1 1 1 1 0|0 0 0 0| cc
1213  // JP cc,addr(Rd) |0 1|0 1 1 1 1 0| Rd!=0 | cc
1214  if (OPCNIB1) {
1216  } else {
1217  get_address();
1218  DISASM("%s|%s\t%s,%s", disasm_get_address_code, "JP", ccnames(OPCNIB0), disasm_get_address);
1219  if (DO_EXEC) {
1220  if (check_cc(OPCNIB0)) {
1221  z8k1.codeseg = z8k1.use_seg;
1222  z8k1.pc = z8k1.use_ofs;
1223  }
1224  static const int jp_cycles[] = { 7, 8, 10 };
1225  cycles += jp_cycles[z8k1.get_address_mode];
1226  }
1227  }
1228  break;
1229 
1230  /*************************** OPC-HI = $5F ***************************/
1231  case 0x5F:
1232  // CALL address |0 1|0 1 1 1 1 1|0 0 0 0|0 0 0 0
1233  // CALL addr(Rd) |0 1|0 1 1 1 1 1| Rd!=0 |0 0 0 0
1235  break;
1236 
1237  /*************************** OPC-HI = $9E ***************************/
1238  case 0x9E:
1239  // RET cc |1 0|0 1 1 1 1 0|0 0 0 0| cc
1241  break;
1242 
1243  /*************************** OPC-HI = $9F ***************************/
1244  case 0x9F:
1245  RESERVED_OPCODE();
1246  break;
1247 
1248  /*************************** OPC-HI = $20 ***************************/
1249  case 0x20:
1250  // LDB Rd,@Rs {BYTE} |0 0|1 0 0 0 0 0| Rs!=0 | Rd
1251  // LDB Rbd,#data |0 0|1 0 0 0 0 0|0 0 0 0| Rbd
1253  break;
1254 
1255  /*************************** OPC-HI = $21 ***************************/
1256  case 0x21:
1257  // LD Rd,@Rs {WORD} |0 0|1 0 0 0 0 1| Rs!=0 | Rd
1258  // LD Rd,#data |0 0|1 0 0 0 0 1|0 0 0 0| Rd
1259  if (OPCNIB1) {
1261  } else {
1262  Uint16 data = READCODE();
1263  DISASM("%04X|%s\t%s,#$%04X", data, "LD", reg16names(OPCNIB0), data);
1264  if (DO_EXEC) {
1265  SetReg16(OPCNIB0, data);
1266  cycles += 7;
1267  }
1268  }
1269  break;
1270 
1271  /*************************** OPC-HI = $60 ***************************/
1272  case 0x60:
1273  // LDB Rd,address {BYTE} |0 1|1 0 0 0 0 0|0 0 0 0| Rd
1274  // LDB Rd,addr(Rs) {BYTE} |0 1|1 0 0 0 0 0| Rs!=0 | Rd
1276  break;
1277 
1278  /*************************** OPC-HI = $61 ***************************/
1279  case 0x61:
1280  // LD Rd,address {WORD} |0 1|1 0 0 0 0 1|0 0 0 0| Rd
1281  // LD Rd,addr(Rs) {WORD} |0 1|1 0 0 0 0 1| Rs!=0 | Rd
1283  break;
1284 
1285  /*************************** OPC-HI = $A0 ***************************/
1286  case 0xA0:
1287  // LDB Rd,Rs {BYTE} |1 0|1 0 0 0 0 0| Rs | Rd
1288  DISASM("|%s\t%s,%s", "LDB", reg8names(OPCNIB0), reg8names(OPCNIB1));
1289  if (DO_EXEC) {
1290  SetReg8(OPCNIB0, GetReg8(OPCNIB1));
1291  cycles += 3;
1292  }
1293  break;
1294 
1295  /*************************** OPC-HI = $A1 ***************************/
1296  case 0xA1:
1297  // LD Rd,Rs {WORD} |1 0|1 0 0 0 0 1| Rs | Rd
1298  DISASM("|%s\t%s,%s", "LDB", reg16names(OPCNIB0), reg16names(OPCNIB1));
1299  if (DO_EXEC) {
1300  SetReg16(OPCNIB0, GetReg16(OPCNIB1));
1301  cycles += 3;
1302  }
1303  break;
1304 
1305  /*************************** OPC-HI = $22 ***************************/
1306  case 0x22:
1307  // RESB @Rd,#b {BYTE} |0 0|1 0 0 0 1 0| Rd!=0 | b
1308  // RESB Rd,Rs {BYTE} |0 0|1 0 0 0 1 0|0 0 0 0| Rs |0 0 0 0| Rd |0 0 0 0|0 0 0 0
1310  break;
1311 
1312  /*************************** OPC-HI = $23 ***************************/
1313  case 0x23:
1314  // RES @Rd,#b {WORD} |0 0|1 0 0 0 1 1| Rd!=0 | b
1315  // RES Rd,Rs {WORD} |0 0|1 0 0 0 1 1|0 0 0 0| Rs |0 0 0 0| Rd |0 0 0 0|0 0 0 0
1317  break;
1318 
1319  /*************************** OPC-HI = $62 ***************************/
1320  case 0x62:
1321  // RESB address,#b {BYTE} |0 1|1 0 0 0 1 0|0 0 0 0| b
1322  // RESB addr(Rd),#b {BYTE} |0 1|1 0 0 0 1 0| Rd!=0 | b
1324  break;
1325 
1326  /*************************** OPC-HI = $63 ***************************/
1327  case 0x63:
1328  // RES address,#b {WORD} |0 1|1 0 0 0 1 1|0 0 0 0| b
1329  // RES addr(Rd),#b {WORD} |0 1|1 0 0 0 1 1| Rd!=0 | b
1331  break;
1332 
1333  /*************************** OPC-HI = $A2 ***************************/
1334  case 0xA2:
1335  // RESB Rd,#b {BYTE} |1 0|1 0 0 0 1 0| Rd | b
1337  break;
1338 
1339  /*************************** OPC-HI = $A3 ***************************/
1340  case 0xA3:
1341  // RES Rd,#b {WORD} |1 0|1 0 0 0 1 1| Rd | b
1343  break;
1344 
1345  /*************************** OPC-HI = $24 ***************************/
1346  case 0x24:
1347  // SETB @Rd,#b {BYTE} |0 0|1 0 0 1 0 0| Rd!=0 | b
1348  // SETB Rd,Rs {BYTE} |0 0|1 0 0 1 0 0|0 0 0 0| Rs |0 0 0 0| Rd |0 0 0 0 0 0 0 0
1350  break;
1351 
1352  /*************************** OPC-HI = $25 ***************************/
1353  case 0x25:
1354  // SET @Rd,#b {WORD} |0 0|1 0 0 1 0 1| Rd!=0 | b
1355  // SET Rd,Rs {WORD} |0 0|1 0 0 1 0 1|0 0 0 0| Rs |0 0 0 0| Rd |0 0 0 0 0 0 0 0
1357  break;
1358 
1359  /*************************** OPC-HI = $64 ***************************/
1360  case 0x64:
1361  // SETB address,#b {BYTE} |0 1|1 0 0 1 0 0|0 0 0 0| b
1362  // SETB addr(Rd),#b {BYTE} |0 1|1 0 0 1 0 0| Rd!=0 | b
1364  break;
1365 
1366  /*************************** OPC-HI = $65 ***************************/
1367  case 0x65:
1368  // SET address,#b {WORD} |0 1|1 0 0 1 0 1|0 0 0 0| b
1369  // SET addr(Rd),#b {WORD} |0 1|1 0 0 1 0 1| Rd!=0 | b
1371  break;
1372 
1373  /*************************** OPC-HI = $A4 ***************************/
1374  case 0xA4:
1375  // SETB Rd,#b {BYTE} |1 0|1 0 0 1 0 0| Rd | b
1377  break;
1378 
1379  /*************************** OPC-HI = $A5 ***************************/
1380  case 0xA5:
1381  // SET Rd,#b {WORD} |1 0|1 0 0 1 0 1| Rd | b
1383  break;
1384 
1385  /*************************** OPC-HI = $26 ***************************/
1386  case 0x26:
1387  // BITB @Rd,#b {BYTE} |0 0|1 0 0 1 1 0| Rd!=0 | b
1388  // BITB Rd,Rs {BYTE} |0 0|1 0 0 1 1 0|0 0 0 0| Rs |0 0 0 0| Rd |0 0 0 0|0 0 0 0
1390  break;
1391 
1392  /*************************** OPC-HI = $27 ***************************/
1393  case 0x27:
1394  // BIT @Rd,#b {WORD} |0 0|1 0 0 1 1 1| Rd!=0 | b
1395  // BIT Rd,Rs {WORD} |0 0|1 0 0 1 1 1|0 0 0 0| Rs |0 0 0 0| Rd |0 0 0 0|0 0 0 0
1397  break;
1398 
1399  /*************************** OPC-HI = $66 ***************************/
1400  case 0x66:
1401  // BITB address,#b {BYTE} |0 1|1 0 0 1 1 0|0 0 0 0| b
1402  // BITB addr(Rd),#b {BYTE} |0 1|1 0 0 1 1 0| Rd!=0 | b
1404  break;
1405 
1406  /*************************** OPC-HI = $67 ***************************/
1407  case 0x67:
1408  // BIT address,#b {WORD} |0 1|1 0 0 1 1 1|0 0 0 0| b
1409  // BIT addr(Rd),#b {WORD} |0 1|1 0 0 1 1 1| Rd!=0 | b
1411  break;
1412 
1413  /*************************** OPC-HI = $A6 ***************************/
1414  case 0xA6:
1415  // BITB Rd,#b {BYTE} |1 0|1 0 0 1 1 0| Rd | b
1417  break;
1418 
1419  /*************************** OPC-HI = $A7 ***************************/
1420  case 0xA7:
1421  // BIT Rd,#b {WORD} |1 0|1 0 0 1 1 1| Rd | b
1423  break;
1424 
1425  /*************************** OPC-HI = $28 ***************************/
1426  case 0x28:
1427  // INCB @Rd,#n {BYTE} |0 0|1 0 1 0 0 0| Rd!=0 | n-1
1429  break;
1430 
1431  /*************************** OPC-HI = $29 ***************************/
1432  case 0x29:
1433  // INC @Rd,#n {WORD} |0 0|1 0 1 0 0 1| Rd!=0 | n-1
1435  break;
1436 
1437  /*************************** OPC-HI = $68 ***************************/
1438  case 0x68:
1439  // INCB address,#n {BYTE} |0 1|1 0 1 0 0 0|0 0 0 0| n-1
1440  // INCB addr(Rd),#n {BYTE} |0 1|1 0 1 0 0 0| Rd!=0 | n-1
1442  break;
1443 
1444  /*************************** OPC-HI = $69 ***************************/
1445  case 0x69:
1446  // INC address,#n {WORD} |0 1|1 0 1 0 0 1|0 0 0 0| n-1
1447  // INC addr(Rd),#n {WORD} |0 1|1 0 1 0 0 1| Rd!=0 | n-1
1449  break;
1450 
1451  /*************************** OPC-HI = $A8 ***************************/
1452  case 0xA8:
1453  // INCB Rd,#n {BYTE} |1 0|1 0 1 0 0 0| Rd | n-1
1454  DISASM("|%s\t%s,#$%02X", "INCB", reg8names(OPCNIB1), OPCNIB0 + 1);
1455  if (DO_EXEC) {
1456  int n = OPCNIB0 + 1, d = GetReg8(OPCNIB1), r = n + d;
1457  SetReg8(OPCNIB1, r);
1458  z8k1.flags = (z8k1.flags & (FLAG_CARRY | FLAG_DA | FLAG_HC)) | F_ZERO_BY16(r) | F_SIGN_BY16(r) | F_OVERFLOW_BY16(d,n,r);
1459  cycles += 4;
1460  }
1461  break;
1462 
1463  /*************************** OPC-HI = $A9 ***************************/
1464  case 0xA9:
1465  // INC Rd,#n {WORD} |1 0|1 0 1 0 0 1| Rd | n-1
1467  break;
1468 
1469  /*************************** OPC-HI = $2A ***************************/
1470  case 0x2A:
1471  // DECB @Rd,#n {BYTE} |0 0|1 0 1 0 1 0| Rd!=0 | n-1
1473  break;
1474 
1475  /*************************** OPC-HI = $2B ***************************/
1476  case 0x2B:
1477  // DEC @Rd,#n {WORD} |0 0|1 0 1 0 1 1| Rd!=0 | n-1
1479  break;
1480 
1481  /*************************** OPC-HI = $6A ***************************/
1482  case 0x6A:
1483  // DECB address,#n {BYTE} |0 1|1 0 1 0 1 0|0 0 0 0| n-1
1484  // DECB addr(Rd),#n {BYTE} |0 1|1 0 1 0 1 0| Rd!=0 | n-1
1486  break;
1487 
1488  /*************************** OPC-HI = $6B ***************************/
1489  case 0x6B:
1490  // DEC address,#n {WORD} |0 1|1 0 1 0 1 1|0 0 0 0| n-1
1491  // DEC addr(Rd),#n {WORD} |0 1|1 0 1 0 1 1| Rd!=0 | n-1
1493  break;
1494 
1495  /*************************** OPC-HI = $AA ***************************/
1496  case 0xAA:
1497  // DECB Rd,#n {BYTE} |1 0|1 0 1 0 1 0| Rd | n-1
1499  break;
1500 
1501  /*************************** OPC-HI = $AB ***************************/
1502  case 0xAB:
1503  // DEC Rd,#n {WORD} |1 0|1 0 1 0 1 1| Rd | n-1
1505  break;
1506 
1507  /*************************** OPC-HI = $2C ***************************/
1508  case 0x2C:
1509  // EXB Rd,@Rs {BYTE} |0 0|1 0 1 1 0 0| Rs!=0 | Rd
1511  break;
1512 
1513  /*************************** OPC-HI = $2D ***************************/
1514  case 0x2D:
1515  // EX Rd,@Rs {WORD} |0 0|1 0 1 1 0 1| Rs!=0 | Rd
1517  break;
1518 
1519  /*************************** OPC-HI = $6C ***************************/
1520  case 0x6C:
1521  // EXB Rd,address {BYTE} |0 1|1 0 1 1 0 0|0 0 0 0| Rd
1522  // EXB Rd,addr(Rs) {BYTE} |0 1|1 0 1 1 0 0| Rs!=0 | Rd
1524  break;
1525 
1526  /*************************** OPC-HI = $6D ***************************/
1527  case 0x6D:
1528  // EX Rd,address {WORD} |0 1|1 0 1 1 0 1|0 0 0 0| Rd
1529  // EX Rd,addr(Rs) {WORD} |0 1|1 0 1 1 0 1| Rs!=0 | Rd
1531  break;
1532 
1533  /*************************** OPC-HI = $AC ***************************/
1534  case 0xAC:
1535  // EXB Rd,Rs {BYTE} |1 0|1 0 1 1 0 0| Rs | Rd
1537  break;
1538 
1539  /*************************** OPC-HI = $AD ***************************/
1540  case 0xAD:
1541  // EX Rd,Rs {WORD} |1 0|1 0 1 1 0 1| Rs | Rd
1543  break;
1544 
1545  /*************************** OPC-HI = $2E ***************************/
1546  case 0x2E:
1547  // LDB @Rd,Rs {BYTE} |0 0|1 0 1 1 1 0| Rd!=0 | Rs
1549  break;
1550 
1551  /*************************** OPC-HI = $2F ***************************/
1552  case 0x2F:
1553  // LD @Rd,Rs {WORD} |0 0|1 0 1 1 1 1| Rd!=0 | Rs
1555  break;
1556 
1557  /*************************** OPC-HI = $6E ***************************/
1558  case 0x6E:
1559  // LDB address,Rs {BYTE} |0 1|1 0 1 1 1 0|0 0 0 0| Rs
1560  // LDB addr(Rd),Rs {BYTE} |0 1|1 0 1 1 1 0| Rd!=0 | Rs
1562  break;
1563 
1564  /*************************** OPC-HI = $6F ***************************/
1565  case 0x6F:
1566  // LD address,Rs {WORD} |0 1|1 0 1 1 1 1|0 0 0 0| Rs
1567  // LD addr(Rd),Rs {WORD} |0 1|1 0 1 1 1 1| Rd!=0 | Rs
1569  break;
1570 
1571  /*************************** OPC-HI = $AE ***************************/
1572  case 0xAE:
1573  // TCCB cc,Rd {BYTE} |1 0|1 0 1 1 1 0| Rd | cc
1575  break;
1576 
1577  /*************************** OPC-HI = $AF ***************************/
1578  case 0xAF:
1579  // TCC cc,Rd {WORD} |1 0|1 0 1 1 1 1| Rd | cc
1581  break;
1582 
1583  /*************************** OPC-HI = $30 ***************************/
1584  case 0x30:
1585  // LDB Rd,Rs(#disp16) {BYTE} |0 0|1 1 0 0 0 0| Rs!=0 | Rd | disp16
1586  // LDRB Rd,disp16 {BYTE} |0 0 1 1 0 0 0 0|0 0 0 0| Rd | disp16
1588  break;
1589 
1590  /*************************** OPC-HI = $31 ***************************/
1591  case 0x31:
1592  // LD Rd,Rs(#disp16) {WORD} |0 0|1 1 0 0 0 1| Rs!=0 | Rd | disp16
1593  // LDR Rd,disp16 {WORD} |0 0 1 1 0 0 0 1|0 0 0 0| Rd | disp16
1595  break;
1596 
1597  /*************************** OPC-HI = $70 ***************************/
1598  case 0x70:
1599  // LDB Rd,Rs(Rx) {BYTE} |0 1|1 1 0 0 0 0| Rs!=0 | Rd |0 0 0 0| Rx |0 0 0 0 0 0 0 0
1601  break;
1602 
1603  /*************************** OPC-HI = $71 ***************************/
1604  case 0x71:
1605  // LD Rd,Rs(Rx) {WORD} |0 1|1 1 0 0 0 1| Rs!=0 | Rd |0 0 0 0| Rx |0 0 0 0 0 0 0 0
1607  break;
1608 
1609  /*************************** OPC-HI = $B0 ***************************/
1610  case 0xB0:
1611  // DAB Rbd |1 0|1 1 0 0 0 0| Rbd |0 0 0 0
1613  break;
1614 
1615  /*************************** OPC-HI = $B1 ***************************/
1616  case 0xB1:
1617  // EXTSB Rd |1 0|1 1 0 0 0 1| Rd |0 0 0 0
1618  // EXTS RRd |1 0|1 1 0 0 0 1| RRd |1 0 1 0
1619  // EXTSL RQd |1 0|1 1 0 0 0 1| RQd |0 1 1 1
1620  switch (OPCNIB0) {
1621  case 0:
1622  DISASM("|EXTSB\t%s", reg16names(OPCNIB1));
1623  if (DO_EXEC) {
1624  if (z8k1.regs[OPCNIB1] & 0x80)
1625  z8k1.regs[OPCNIB1] |= 0xFF00;
1626  else
1627  z8k1.regs[OPCNIB1] &= 0x00FF;
1628  cycles += 11;
1629  }
1630  break;
1631  case 9:
1632  DISASM("|EXTS\t%s", reg32names(OPCNIB1));
1633  if (DO_EXEC) {
1634  z8k1.regs[OPCNIB1 & 0xE] = (z8k1.regs[OPCNIB1 | 1] & 0x8000) ? 0xFFFF : 0x0000;
1635  cycles += 11;
1636  }
1637  break;
1638  case 7:
1639  DISASM("|EXTSL\t%s", reg64names(OPCNIB1));
1640  if (DO_EXEC) {
1641  z8k1.regs[OPCNIB1 & 0xC] = z8k1.regs[(OPCNIB1 & 0xC) | 1] = (z8k1.regs[(OPCNIB1 & 0xC) | 2] & 0x8000) ? 0xFFFF : 0x0000;
1642  cycles += 11;
1643  }
1644  break;
1645  default:
1647  }
1648  break;
1649 
1650  /*************************** OPC-HI = $32 ***************************/
1651  case 0x32:
1652  // LDB Rd(#disp16),Rs {BYTE} |0 0|1 1 0 0 1 0| Rd!=0 | Rs | disp16
1653  // LDRB disp16,Rs {BYTE} |0 0 1 1 0 0 1 0|0 0 0 0| Rs | disp16
1655  break;
1656 
1657  /*************************** OPC-HI = $33 ***************************/
1658  case 0x33:
1659  // LD Rd(#disp16),Rs {WORD} |0 0|1 1 0 0 1 1| Rd!=0 | Rs | disp16
1660  // LDR disp16,Rs {WORD} |0 0 1 1 0 0 1 1|0 0 0 0| Rs | disp16
1662  break;
1663 
1664  /*************************** OPC-HI = $72 ***************************/
1665  case 0x72:
1666  // LDB Rd(Rx),Rs {BYTE} |0 1|1 1 0 0 1 0| Rd!=0 | Rs |0 0 0 0| Rx |0 0 0 0 0 0 0 0
1668  break;
1669 
1670  /*************************** OPC-HI = $73 ***************************/
1671  case 0x73:
1672  // LD Rd(Rx),Rs {WORD} |0 1|1 1 0 0 1 1| Rd!=0 | Rs |0 0 0 0| Rx |0 0 0 0 0 0 0 0
1674  break;
1675 
1676  /*************************** OPC-HI = $B2 ***************************/
1677  case 0xB2:
1678  // RLB Rd,#S {BYTE} |1 0|1 1 0 0 1 0| Rd |0 0|S|0
1679  // RLCB Rd,#S {BYTE} |1 0|1 1 0 0 1 0| Rd |1 0|S|0
1680  // RRB Rd,#S {BYTE} |1 0|1 1 0 0 1 0| Rd |0 1|S|0
1681  // RRCB Rd,#S {BYTE} |1 0|1 1 0 0 1 0| Rd |1 1|S|0
1682  // SDAB Rbd,Rs |1 0|1 1 0 0 1 0| Rbd |1 0 1 1|0 0 0 0| Rs |0 0 0 0 0 0 0 0
1683  // SDLB Rbd,Rs |1 0|1 1 0 0 1 0| Rbd |0 0 1 1|0 0 0 0| Rs |0 0 0 0 0 0 0 0
1684  // SLAB Rbd,#b |1 0|1 1 0 0 1 0| Rbd |1 0 0 1| b
1685  // SLLB Rbd,#b |1 0|1 1 0 0 1 0| Rbd |0 0 0 1| b
1687  break;
1688 
1689  /*************************** OPC-HI = $B3 ***************************/
1690  case 0xB3:
1691  // RL Rd,#S {WORD} |1 0|1 1 0 0 1 1| Rd |0 0|S|0
1692  // RLC Rd,#S {WORD} |1 0|1 1 0 0 1 1| Rd |1 0|S|0
1693  // RR Rd,#S {WORD} |1 0|1 1 0 0 1 1| Rd |0 1|S|0
1694  // RRC Rd,#S {WORD} |1 0|1 1 0 0 1 1| Rd |1 1|S|0
1695  // SDA Rd,Rs |1 0|1 1 0 0 1 1| Rd |1 0 1 1|0 0 0 0| Rs |0 0 0 0 0 0 0 0
1696  // SDAL RRd,Rs |1 0|1 1 0 0 1 1| RRd |1 1 1 1|0 0 0 0| Rs |0 0 0 0 0 0 0 0
1697  // SDL Rd,Rs |1 0|1 1 0 0 1 1| Rd |0 0 1 1|0 0 0 0| Rs |0 0 0 0 0 0 0 0
1698  // SDLL RRd,Rs |1 0|1 1 0 0 1 1| RRd |0 1 1 1|0 0 0 0| Rs |0 0 0 0 0 0 0 0
1699  // SLA Rd,#b |1 0|1 1 0 0 1 1| Rd |1 0 0 1| b
1700  // SLAL RRd,#b |1 0|1 1 0 0 1 1| RRd |1 1 0 1| b
1701  // SLL Rd,#b |1 0|1 1 0 0 1 1| Rd |0 0 0 1| b
1702  // SLLL RRd,#b |1 0|1 1 0 0 1 1| RRd |0 1 0 1| b
1704  break;
1705 
1706  /*************************** OPC-HI = $34 ***************************/
1707  case 0x34:
1708  // LDA Sd,Rs(#disp16) |0 0|1 1 0 1 0 0| Rs!=0 | Sd | disp16
1709  // LDAR Rd,disp16 |0 0 1 1 0 1 0 0|0 0 0 0| Rd | disp16
1710  if (OPCNIB1) {
1712  } else {
1713  Uint16 disp = READCODE();
1714  Uint16 val = z8k1.pc + (Sint16)disp;
1715  if (IS_SEGMENTED_MODE) {
1716  DISASM("%04X|%s\t%s,$%04X", disp, "LDAR", reg32names(OPCNIB0), val);
1717  if (DO_EXEC) SetReg32(OPCNIB0, (z8k1.codeseg << 16) | val);
1718  } else {
1719  DISASM("%04X|%s\t%s,$%04X", disp, "LDAR", reg16names(OPCNIB0), val);
1720  if (DO_EXEC) SetReg16(OPCNIB0, val);
1721  }
1722  if (DO_EXEC) cycles += 15;
1723  }
1724  break;
1725 
1726  /*************************** OPC-HI = $35 ***************************/
1727  case 0x35:
1728  // LDL RRd,Rs(#disp16) |0 0 1 1 0 1 0 1| Rs!=0 | RRd | disp16
1729  // LDRL RRd,disp16 |0 0 1 1 0 1 0 1|0 0 0 0| RRd | disp16
1731  break;
1732 
1733  /*************************** OPC-HI = $74 ***************************/
1734  case 0x74:
1735  // LDA Sd,Rs(Rx) |0 1|1 1 0 1 0 0| Rs!=0 | Sd |0 0 0 0| Rx |0 0 0 0|0 0 0 0
1737  break;
1738 
1739  /*************************** OPC-HI = $75 ***************************/
1740  case 0x75:
1741  // LDL RRd,Rs(Rx) |0 1|1 1 0 1 0|1| Rs!=0 | RRd |0 0 0 0| Rx |0 0 0 0 0 0 0 0
1743  break;
1744 
1745  /*************************** OPC-HI = $B4 ***************************/
1746  case 0xB4:
1747  // ADCB Rd,Rs {BYTE} |1 0|1 1 0 1 0 0| Rs | Rd
1748  DISASM("|%s\t%s,%s", "ADCB", reg8names(OPCNIB0), reg8names(OPCNIB1));
1749  if (DO_EXEC) {
1750  int s = GetReg8(OPCNIB1), d = GetReg8(OPCNIB0), r = s + d + F_CARRY_BOOL;
1751  z8k1.flags = F_CARRY_BY8(r) | F_ZERO_BY8(r) | F_SIGN_BY8(r) | F_OVERFLOW_BY8(s,d,r) | F_HALFCARRY_BY8(s,d,r);
1752  SetReg8(OPCNIB0, r);
1753  cycles += 5;
1754  }
1755  break;
1756 
1757  /*************************** OPC-HI = $B5 ***************************/
1758  case 0xB5:
1759  // ADC Rd,Rs {WORD} |1 0|1 1 0 1 0 1| Rs | Rd
1760  DISASM("|%s\t%s,%s", "ADC", reg16names(OPCNIB0), reg16names(OPCNIB1));
1761  if (DO_EXEC) {
1762  int s = GetReg16(OPCNIB1), d = GetReg16(OPCNIB0), r = s + d + F_CARRY_BOOL;
1763  z8k1.flags = (z8k1.flags & (FLAG_DA | FLAG_HC)) | F_CARRY_BY16(r) | F_ZERO_BY16(r) | F_SIGN_BY16(r) | F_OVERFLOW_BY16(s,d,r);
1764  SetReg16(OPCNIB0, r);
1765  cycles += 5;
1766  }
1767  break;
1768 
1769  /*************************** OPC-HI = $36 ***************************/
1770  case 0x36:
1771  RESERVED_OPCODE();
1772  break;
1773 
1774  /*************************** OPC-HI = $37 ***************************/
1775  case 0x37:
1776  // LDL Rd(#disp16),RRs |0 0|1 1 0 1 1 1| Rd!=0 | RRs | disp16
1777  // LDRL disp16,RRs |0 0 1 1 0 1 1 1|0 0 0 0| RRs | disp16
1779  break;
1780 
1781  /*************************** OPC-HI = $76 ***************************/
1782  case 0x76:
1783  // LDA Sd,address |0 1|1 1 0 1 1 0|0 0 0 0| Sd
1784  // LDA Sd,addr(Rs) |0 1|1 1 0 1 1 0| Rs!=0 | Sd
1786  break;
1787 
1788  /*************************** OPC-HI = $77 ***************************/
1789  case 0x77:
1790  // LDL Rd(Rx),RRs |0 1|1 1 0 1 1 1| Rd!=0 | RRs |0 0 0 0| Rx |0 0 0 0 0 0 0 0
1792  break;
1793 
1794  /*************************** OPC-HI = $B6 ***************************/
1795  case 0xB6:
1796  // SBCB Rd,Rs {BYTE} |1 0|1 1 0 1 1 0| Rs | Rd
1798  break;
1799 
1800  /*************************** OPC-HI = $B7 ***************************/
1801  case 0xB7:
1802  // SBC Rd,Rs {WORD} |1 0|1 1 0 1 1 1| Rs | Rd
1804  break;
1805 
1806  /*************************** OPC-HI = $38 ***************************/
1807  case 0x38:
1808  RESERVED_OPCODE();
1809  break;
1810 
1811  /*************************** OPC-HI = $39 ***************************/
1812  case 0x39:
1813  // LDPS @Rs |0 0|1 1 1 0 0 1| Rs!=0 |0 0 0 0
1815  break;
1816 
1817  /*************************** OPC-HI = $78 ***************************/
1818  case 0x78:
1819  RESERVED_OPCODE();
1820  break;
1821 
1822  /*************************** OPC-HI = $79 ***************************/
1823  case 0x79:
1824  // LDPS address |0 1|1 1 1 0 0 1|0 0 0 0|0 0 0 0
1825  // LDPS addr(Rs) |0 1|1 1 1 0 0 1| Rs!=0 |0 0 0 0
1827  break;
1828 
1829  /*************************** OPC-HI = $B8 ***************************/
1830  case 0xB8:
1831  // TRDB @Rd,@Rs,r |1 0|1 1 1 0 0 0| Rd!=0 |1 0 0 0|0 0 0 0| r | Rs!=0 |0 0 0 0
1832  // TRDBR @Rd,@Rs,r |1 0|1 1 1 0 0 0| Rd!=0 |1 1 0 0|0 0 0 0| r | Rs!=0 |0 0 0 0
1833  // TRIB @Rd,@Rs,r |1 0|1 1 1 0 0 0| Rd!=0 |0 0 0 0|0 0 0 0| r | Rs!=0 |0 0 0 0
1834  // TRIBR @Rd,@Rs,r |1 0|1 1 1 0 0 0| Rd!=0 |0 1 0 0|0 0 0 0| r | Rs!=0 |0 0 0 0
1835  // TRTDB @Rs1,@Rs2,r |1 0|1 1 1 0 0 0| Rs1!=0|1 0 1 0|0 0 0 0| r | Rs2!=0|0 0 0 0
1836  // TRTDRB @Rd,@Rs,r |1 0|1 1 1 0 0 0| Rd!=0 |1 1 1 0|0 0 0 0| r | Rs!=0 |1 1 1 0
1837  // TRTIB @Rs1,@Rs2,r |1 0|1 1 1 0 0 0| Rs1!=0|0 0 1 0|0 0 0 0| r | Rs2!=0|0 0 0 0
1838  // TRTIRB @Rd,@Rs,r |1 0|1 1 1 0 0 0| Rd!=0 |0 1 1 0|0 0 0 0| r | Rs!=0 |1 1 1 0
1840  break;
1841 
1842  /*************************** OPC-HI = $B9 ***************************/
1843  case 0xB9:
1844  RESERVED_OPCODE();
1845  break;
1846 
1847  /*************************** OPC-HI = $3A ***************************/
1848  case 0x3A:
1849  // INB S,Rd,port {BYTE} |0 0|1 1 1 0 1 0| Rd |0 1 0|S| port
1850  // INDB S,@Rd,@Rs,r {BYTE} |0 0 1 1 1 0 1 0| Rs!=0 |0 0 0|S|0 0 0 0| r | Rd!=0 |1 0 0 0
1851  // INDRB S,@Rd,@Rs,r {BYTE} |0 0 1 1 1 0 1 0| Rs!=0 |1 0 0|S|0 0 0 0| r | Rd!=0 |0 0 0 0
1852  // INIB S,@Rd,@Rs,r {BYTE} |0 0 1 1 1 0 1 0| Rs!=0 |1 0 0|S|0 0 0 0| r | Rd!=0 |1 0 0 0
1853  // INIRB S,@Rd,@Rs,r {BYTE} |0 0 1 1 1 0 1 0| Rs!=0 |0 0 0|S|0 0 0 0| r | Rd!=0 |0 0 0 0
1854  // OTDRB S,@Rd,@Rs,r {BYTE} |0 0 1 1 1 0 1 0| Rs!=0 |1 0 1|S|0 0 0 0| r | Rd!=0 |0 0 0 0
1855  // OTIRB S,@Rd,@Rs,r {BYTE} |0 0 1 1 1 0 1 0| Rs!=0 |0 0 1|S|0 0 0 0| r | Rd!=0 |0 0 0 0
1856  // OUTB S,port,Rs {BYTE} |0 0 1 1 1 0 1 0| Rs |0 1 1|S| port
1857  // OUTDB S,@Rd,@Rs,r {BYTE} |0 0 1 1 1 0 1 0| Rs!=0 |1 0 1|S|0 0 0 0| r | Rd!=0 |1 0 0 0
1858  // OUTIB S,@Rd,@Rs,r {BYTE} |0 0 1 1 1 0 1 0| Rs!=0 |0 0 1|S|0 0 0 0| r | Rd!=0 |1 0 0 0
1859  switch ((opc >> 1) & 7) {
1860  case 3:
1861  BEGIN
1862  Uint16 port = READCODE();
1863  DISASM("%04X|%s\t$%04X,%s", port, (opc & 1) ? "SOUTB" : "OUTB", port, reg8names(OPCNIB1));
1864  if (DO_EXEC) {
1865  cycles += 12;
1866  z8k1_out_byte_cb(opc & 1, port, GetReg8(OPCNIB1));
1867  }
1868  END;
1869  default:
1871  }
1872  break;
1873 
1874  /*************************** OPC-HI = $3B ***************************/
1875  case 0x3B:
1876  // IN S,Rd,port {WORD} |0 0|1 1 1 0 1 1| Rd |0 1 0|S| port
1877  // IND S,@Rd,@Rs,r {WORD} |0 0 1 1 1 0 1 1| Rs!=0 |0 0 0|S|0 0 0 0| r | Rd!=0 |1 0 0 0
1878  // INDR S,@Rd,@Rs,r {WORD} |0 0 1 1 1 0 1 1| Rs!=0 |1 0 0|S|0 0 0 0| r | Rd!=0 |0 0 0 0
1879  // INI S,@Rd,@Rs,r {WORD} |0 0 1 1 1 0 1 1| Rs!=0 |1 0 0|S|0 0 0 0| r | Rd!=0 |1 0 0 0
1880  // INIR S,@Rd,@Rs,r {WORD} |0 0 1 1 1 0 1 1| Rs!=0 |0 0 0|S|0 0 0 0| r | Rd!=0 |0 0 0 0
1881  // OTDR S,@Rd,@Rs,r {WORD} |0 0 1 1 1 0 1 1| Rs!=0 |1 0 1|S|0 0 0 0| r | Rd!=0 |0 0 0 0
1882  // OTIR S,@Rd,@Rs,r {WORD} |0 0 1 1 1 0 1 1| Rs!=0 |0 0 1|S|0 0 0 0| r | Rd!=0 |0 0 0 0
1883  // OUT S,port,Rs {WORD} |0 0 1 1 1 0 1 1| Rs |0 1 1|S| port
1884  // OUTD S,@Rd,@Rs,r {WORD} |0 0 1 1 1 0 1 1| Rs!=0 |1 0 1|S|0 0 0 0| r | Rd!=0 |1 0 0 0
1885  // OUTI S,@Rd,@Rs,r {WORD} |0 0 1 1 1 0 1 1| Rs!=0 |0 0 1|S|0 0 0 0| r | Rd!=0 |1 0 0 0
1887  break;
1888 
1889  /*************************** OPC-HI = $7A ***************************/
1890  case 0x7A:
1891  // HALT |0 1 1 1 1 0 1 0|0 0 0 0 0 0 0 0
1893  break;
1894 
1895  /*************************** OPC-HI = $7B ***************************/
1896  case 0x7B:
1897  // IRET |0 1 1 1 1 0 1 1|0 0 0 0 0 0 0 0
1898  // MBIT |0 1 1 1 1 0 1 1|0 0 0 0 1 0 1 0
1899  // MREQ Rd |0 1|1 1 1 0 1 1| Rd |1 1 0 1
1900  // MRES |0 1 1 1 1 0 1 1|0 0 0 0 1 0 0 1
1901  // MSET |0 1 1 1 1 0 1 1|0 0 0 0 1 0 0 0
1903  break;
1904 
1905  /*************************** OPC-HI = $BA ***************************/
1906  case 0xBA:
1907  // CPDB Rd,@Rs,r,cc {BYTE} |1 0|1 1 1 0 1 0| Rs!=0 |1 0 0 0|0 0 0 0| r | Rd | cc
1908  // CPDRB Rd,@Rs,r,cc {BYTE} |1 0|1 1 1 0 1 0| Rs!=0 |1 1 0 0|0 0 0 0| r | Rd | cc
1909  // CPIB Rd,@Rs,r,cc {BYTE} |1 0|1 1 1 0 1 0| Rs!=0 |0 0 0 0|0 0 0 0| r | Rd | cc
1910  // CPIRB Rd,@Rs,r,cc {BYTE} |1 0|1 1 1 0 1 0| Rs!=0 |0 1 0 0|0 0 0 0| r | Rd | cc
1911  // CPSDB @Rd,@Rs,r,cc {BYTE} |1 0|1 1 1 0 1 0| Rs!=0 |1 0 1 0|0 0 0 0| r | Rd!=0 | cc
1912  // CPSDRB @Rd,@Rs,r,cc {BYTE} |1 0|1 1 1 0 1 0| Rs!=0 |1 1 1 0|0 0 0 0| r | Rd!=0 | cc
1913  // CPSIB @Rd,@Rs,r,cc {BYTE} |1 0|1 1 1 0 1 0| Rs!=0 |0 0 1 0|0 0 0 0| r | Rd!=0 | cc
1914  // CPSIRB @Rd,@Rs,r,cc {BYTE} |1 0|1 1 1 0 1 0| Rs!=0 |0 1 1 0|0 0 0 0| r | Rd!=0 | cc
1915  // LDDB @Rd,@Rs,r {BYTE} |1 0 1 1 1 0 1 0| Rs!=0 |1 0 0 1|0 0 0 0| r | Rd!=0 |1 0 0 0
1916  // LDDRB @Rd,@Rs,r {BYTE} |1 0 1 1 1 0 1 0| Rs!=0 |1 0 0 1|0 0 0 0| r | Rd!=0 |0 0 0 0
1917  // LDIB @Rd,@Rs,r {BYTE} |1 0 1 1 1 0 1 0| Rs!=0 |0 0 0 1|0 0 0 0| r | Rd!=0 |1 0 0 0
1918  // LDIRB @Rd,@Rs,r {BYTE} |1 0 1 1 1 0 1 0| Rs!=0 |0 0 0 1|0 0 0 0| r | Rd!=0 |0 0 0 0
1920  break;
1921 
1922  /*************************** OPC-HI = $BB ***************************/
1923  case 0xBB:
1924  // CPD Rd,@Rs,r,cc {WORD} |1 0|1 1 1 0 1 1| Rs!=0 |1 0 0 0|0 0 0 0| r | Rd | cc
1925  // CPDR Rd,@Rs,r,cc {WORD} |1 0|1 1 1 0 1 1| Rs!=0 |1 1 0 0|0 0 0 0| r | Rd | cc
1926  // CPI Rd,@Rs,r,cc {WORD} |1 0|1 1 1 0 1 1| Rs!=0 |0 0 0 0|0 0 0 0| r | Rd | cc
1927  // CPIR Rd,@Rs,r,cc {WORD} |1 0|1 1 1 0 1 1| Rs!=0 |0 1 0 0|0 0 0 0| r | Rd | cc
1928  // CPSD @Rd,@Rs,r,cc {WORD} |1 0|1 1 1 0 1 1| Rs!=0 |1 0 1 0|0 0 0 0| r | Rd!=0 | cc
1929  // CPSDR @Rd,@Rs,r,cc {WORD} |1 0|1 1 1 0 1 1| Rs!=0 |1 1 1 0|0 0 0 0| r | Rd!=0 | cc
1930  // CPSI @Rd,@Rs,r,cc {WORD} |1 0|1 1 1 0 1 1| Rs!=0 |0 0 1 0|0 0 0 0| r | Rd!=0 | cc
1931  // CPSIR @Rd,@Rs,r,cc {WORD} |1 0|1 1 1 0 1 1| Rs!=0 |0 1 1 0|0 0 0 0| r | Rd!=0 | cc
1932  // LDD @Rd,@Rs,r {WORD} |1 0 1 1 1 0 1 1| Rs!=0 |1 0 0 1|0 0 0 0| r | Rd!=0 |1 0 0 0
1933  // LDDR @Rd,@Rs,r {WORD} |1 0 1 1 1 0 1 1| Rs!=0 |1 0 0 1|0 0 0 0| r | Rd!=0 |0 0 0 0
1934  // LDI @Rd,@Rs,r {WORD} |1 0 1 1 1 0 1 1| Rs!=0 |0 0 0 1|0 0 0 0| r | Rd!=0 |1 0 0 0
1935  // LDIR @Rd,@Rs,r {WORD} |1 0 1 1 1 0 1 1| Rs!=0 |0 0 0 1|0 0 0 0| r | Rd!=0 |0 0 0 0
1937  break;
1938 
1939  /*************************** OPC-HI = $3C ***************************/
1940  case 0x3C:
1941  // INB Rd,@Rs {BYTE} |0 0|1 1 1 1 0 0| Rs!=0 | Rd
1943  break;
1944 
1945  /*************************** OPC-HI = $3D ***************************/
1946  case 0x3D:
1947  // IN Rd,@Rs {WORD} |0 0|1 1 1 1 0 1| Rs!=0 | Rd
1949  break;
1950 
1951  /*************************** OPC-HI = $7C ***************************/
1952  case 0x7C:
1953  // DI int |0 1|1 1 1 1 0 0|0 0 0 0 0 0|int
1954  // EI int |0 1 1 1 1 1 0 0|0 0 0 0 0 1|int
1956  break;
1957 
1958  /*************************** OPC-HI = $7D ***************************/
1959  case 0x7D: // Privileged instruction!
1960  // LDCTL FCW,Rs |0 1 1 1 1 1 0 1| Rs |1 0 1 0
1961  // LDCTL REFRESH,Rs |0 1 1 1 1 1 0 1| Rs |1 0 1 1
1962  // LDCTL PSAPSEG,Rs |0 1 1 1 1 1 0 1| Rs |1 1 0 0
1963  // LDCTL PSAPOFF,Rs |0 1 1 1 1 1 0 1| Rs |1 1 0 1
1964  // LDCTL NSPSEG,Rs |0 1 1 1 1 1 0 1| Rs |1 1 1 0
1965  // LDCTL NSPOFF,Rs |0 1 1 1 1 1 0 1| Rs |1 1 1 1
1966  // LDCTL Rd,FCW |0 1 1 1 1 1 0 1| Rd |0 0 1 0
1967  // LDCTL Rd,REFRESH |0 1 1 1 1 1 0 1| Rd |0 0 1 1
1968  // LDCTL Rd,PSAPSEG |0 1 1 1 1 1 0 1| Rd |0 1 0 0
1969  // LDCTL Rd,PSAPOFF |0 1 1 1 1 1 0 1| Rd |0 1 0 1
1970  // LDCTL Rd,NSPSEG |0 1 1 1 1 1 0 1| Rd |0 1 1 0
1971  // LDCTL Rd,NSPOFF |0 1 1 1 1 1 0 1| Rd |0 1 1 1
1972  switch (OPCNIB0) {
1973  case 2:
1974  DISASM("|%s\t%s,%s", "LDCTL", reg16names(OPCNIB1), "FCW");
1975  if (DO_EXEC) SetReg16(OPCNIB1, (z8k1.fcw << 8) | z8k1.flags);
1976  break;
1977  case 3:
1978  DISASM("|%s\t%s,%s", "LDCTL", reg16names(OPCNIB1), "REFRESH");
1979  if (DO_EXEC) SetReg16(OPCNIB1, z8k1.refresh);
1980  break;
1981  case 4:
1982  DISASM("|%s\t%s,%s", "LDCTL", reg16names(OPCNIB1), "PSAPSEG");
1983  if (DO_EXEC) SetReg16(OPCNIB1, z8k1.psaseg << 8);
1984  break;
1985  case 5:
1986  DISASM("|%s\t%s,%s", "LDCTL", reg16names(OPCNIB1), "PSAPOFF");
1987  if (DO_EXEC) SetReg16(OPCNIB1, z8k1.psaofs);
1988  break;
1989  case 6:
1990  DISASM("|%s\t%s,%s", "LDCTL", reg16names(OPCNIB1), "NSPSEG");
1991  if (DO_EXEC) SetReg16(OPCNIB1, z8k1.stacksegusr << 8);
1992  break;
1993  case 7:
1994  DISASM("|%s\t%s,%s", "LDCTL", reg16names(OPCNIB1), "NSPOFF");
1995  if (DO_EXEC) SetReg16(OPCNIB1, z8k1.stackptrusr);
1996  break;
1997  case 10:
1998  DISASM("|%s\t%s,%s", "LDCTL", "FCW", reg16names(OPCNIB1));
1999  if (DO_EXEC) {
2000  Uint16 temp = GetReg16(OPCNIB1);
2001  set_fcw_byte(temp >> 8);
2002  z8k1.flags = temp & 0xFC;
2003  }
2004  break;
2005  case 11:
2006  DISASM("|%s\t%s,%s", "LDCTL", "REFRESH", reg16names(OPCNIB1));
2007  if (DO_EXEC) z8k1.refresh = GetReg16(OPCNIB1) & 0xFFFE;
2008  break;
2009  case 12:
2010  DISASM("|%s\t%s,%s", "LDCTL", "PSAPSEG", reg16names(OPCNIB1));
2011  if (DO_EXEC) z8k1.psaseg = (GetReg16(OPCNIB1) >> 8) & 0x7F;
2012  break;
2013  case 13:
2014  DISASM("|%s\t%s,%s", "LDCTL", "PSAPOFF", reg16names(OPCNIB1));
2015  if (DO_EXEC) z8k1.psaofs = GetReg16(OPCNIB1);
2016  break;
2017  case 14:
2018  DISASM("|%s\t%s,%s", "LDCTL", "NSPSEG", reg16names(OPCNIB1));
2019  if (DO_EXEC) z8k1.stacksegusr = (GetReg16(OPCNIB1) >> 8) & 0x7F;
2020  break;
2021  case 15:
2022  DISASM("|%s\t%s,%s", "LDCTL", "NSPOFF", reg16names(OPCNIB1));
2023  if (DO_EXEC) z8k1.stackptrusr = GetReg16(OPCNIB1);
2024  break;
2025  default:
2027 
2028  }
2029  if (DO_EXEC)
2030  cycles += 7;
2031  break;
2032 
2033  /*************************** OPC-HI = $BC ***************************/
2034  case 0xBC:
2035  // RRDB Rbl,Rbs |1 0|1 1 1 1 0 0| Rbs | Rbl
2037  break;
2038 
2039  /*************************** OPC-HI = $BD ***************************/
2040  case 0xBD:
2041  // LDK Rd,#nibble |1 0|1 1 1 1 0 1| Rd | nibble
2042  DISASM("%s\t%s,#$%X", "LDK", reg16names(OPCNIB1), OPCNIB0);
2043  if (DO_EXEC) {
2044  SetReg16(OPCNIB1, OPCNIB0);
2045  cycles += 5;
2046  }
2047  break;
2048 
2049  /*************************** OPC-HI = $3E ***************************/
2050  case 0x3E:
2051  // OUTB @Rd,Rs {BYTE} |0 0 1 1 1 1 1 0| Rd!=0 | Rs
2053  break;
2054 
2055  /*************************** OPC-HI = $3F ***************************/
2056  case 0x3F:
2057  // OUT @Rd,Rs {WORD} |0 0 1 1 1 1 1 1| Rd!=0 | Rs
2059  break;
2060 
2061  /*************************** OPC-HI = $7E ***************************/
2062  case 0x7E:
2063  RESERVED_OPCODE();
2064  break;
2065 
2066  /*************************** OPC-HI = $7F ***************************/
2067  case 0x7F:
2068  // SC #src |0 1 1 1 1 1 1 1| src
2070  break;
2071 
2072  /*************************** OPC-HI = $BE ***************************/
2073  case 0xBE:
2074  // RLDB Rbl,Rbs |1 0|1 1 1 1 1|0| Rbs | Rbl
2076  break;
2077 
2078  /*************************** OPC-HI = $BF ***************************/
2079  case 0xBF:
2080  RESERVED_OPCODE();
2081  break;
2082 
2083 
2084 
2085 #if 0
2086  // ADCB
2087  case 0xB4:
2088  BEGIN
2089  int vals = GetReg8(opc2 >> 4), vald = GetReg8(opc2 & 0xF);
2090  int temp = vals + vald + F_CARRY_BOOL;
2091  flags =
2092  (temp & 0x100 ? FLAG_CARRY : 0) |
2093  (temp & 0x0FF ? 0 : FLAG_ZERO) |
2094  (temp & 0x080 ? FLAG_SIGN : 0) |
2095  (((vals & 0x80) == (vald & 0x80)) && ((temp & 0x80) != (vals & 0x80))) ? FLAG_PV : 0;
2096  SetReg8(opc & 0xF, temp & 0xFF);
2097  END;
2098 #endif
2099  // ADC
2100  //case 0xB5:
2101 #if 0
2102  // 0x20:
2103  // -- or: LDB R8,#data -> though this is a longer form of the LDB with the same effect, use $CX opcodes instead! shorter in size and cycles too!
2104  case 0x20:
2105  if ((opc2 & 0xF0)) {
2106 
2107  } else { // see the comment at the top of this "case", not so useful
2108  cycles += 7;
2109  Uint8 datah = READCODE();
2110  Uint8 datal = READCODE();
2111  Uint8 data = (opc2 & 8) ? datal : datah; // FIXME: just guessing this the "data byte twice" strange situation!
2112  DISASM("%02X:%04X %02X%02X%02X%02X\tLDB*\t%s,#%02X",
2113  codeseg, pc_orig,
2114  opc, opc2, datah, datal,
2115  reg8names[opc2 & 0xF],
2116  data
2117  );
2118  if (DO_EXEC)
2119  SetReg8(opc2 & 0xF, data);
2120  }
2121  break;
2122 #endif
2123 
2124  /************************************************************************************
2125  * "Compact" instruction formats $C0-$FF, not following the generic opcode scheme.
2126  * This is in fact good, since some opcodes can have shorter (only one word for these)
2127  * construction. Some instructions have longer version as well (above) but not so
2128  * sane idea to use them for sure. These compact opcodes are only four different
2129  * instructions for real, but all of them uses only the four high bits of the opcode
2130  * word, and use the lower 4 for other purposes to help to shorten the opcode.
2131  ************************************************************************************/
2132 
2133  // $C0-$CF: LDB (load immediate byte)
2134  // Low nybl of opcode selects a 8 bit register
2135  // low byte of opcode is the 8 bit immediate data
2136  case 0xC0: case 0xC1: case 0xC2: case 0xC3: case 0xC4: case 0xC5: case 0xC6: case 0xC7:
2137  case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF:
2138  DISASM("|%s\t%s,#$%02X", "LDB", reg8names(OPCNIB2), opc & 0xFF);
2139  if (DO_EXEC) {
2140  SetReg8(OPCNIB2, opc & 0xFF);
2141  cycles += 5;
2142  }
2143  break;
2144  // $D0-$DF: CALR, cal relative
2145  // lower 12 bits are the relative offset, high 4 bits the "opcode" itself only.
2146  // the offset itself is a signed 12 bit value, though divided by 2
2147  case 0xD0: case 0xD1: case 0xD2: case 0xD3: case 0xD4: case 0xD5: case 0xD6: case 0xD7:
2148  case 0xD8: case 0xD9: case 0xDA: case 0xDB: case 0xDC: case 0xDD: case 0xDE: case 0xDF:
2149  BEGIN
2150  Uint16 pc_new = ((opc & 0x800) ? (
2151  (opc & 0xFFF) - 0x1000
2152  ) : (
2153  opc & 0xFFF
2154  )) * 2 + z8k1.pc;
2155  DISASM("|%s\t$%04X", "CALR", pc_new);
2156  if (DO_EXEC) {
2157  //PUSH_PC(); // FIXME TODO
2158  z8k1.pc = pc_new;
2159  cycles += IS_SEGMENTED_MODE ? 15 : 10;
2160  }
2161  END;
2162  // $E0-$EF: JR CC,...
2163  // Low nybl of opcode contains the condition (CC)
2164  // Low byte of opcode is the offset, which is a signed value and multiplied by 2 if jump is taken before added to PC
2165  case 0xE0: case 0xE1: case 0xE2: case 0xE3: case 0xE4: case 0xE5: case 0xE6: case 0xE7:
2166  case 0xE8: case 0xE9: case 0xEA: case 0xEB: case 0xEC: case 0xED: case 0xEE: case 0xEF:
2167  BEGIN
2168  Uint16 pc_new = z8k1.pc + (2 * (int)(Sint8)(opc & 0xFF));
2169  DISASM("|%s\t%s,$%04X", "JR", ccnames(OPCNIB2), pc_new);
2170  if (DO_EXEC && check_cc(OPCNIB2))
2171  z8k1.pc = pc_new;
2172  if (DO_EXEC)
2173  cycles += 6;
2174  END;
2175  // $F0-$FF: DJNZ (Decrement Jump if Non-Zero -> DJNZ), DBJNZ if byte register is selected
2176  // low nybl of opcode is the register selection (byte or word reg, see below)
2177  // low byte of opc is offset*2 (but bit7 is byte/word register select instead!)
2178  // Note: DJNZ offset is ALWAYS negative, ie substracted from PC ...
2179  // ... that is, you can't DJNZ forwards, only backwards ...
2180  case 0xF0: case 0xF1: case 0xF2: case 0xF3: case 0xF4: case 0xF5: case 0xF6: case 0xF7:
2181  case 0xF8: case 0xF9: case 0xFA: case 0xFB: case 0xFC: case 0xFD: case 0xFE: case 0xFF:
2182  BEGIN
2183  Uint16 pc_new = z8k1.pc - ((opc & 0x7F) << 1);
2184  if (opc & 0x80) {
2185  DISASM("|%s\t%s,$%04X", "DJNZ", reg16names(OPCNIB2), pc_new);
2186  if (DO_EXEC && IncReg16(OPCNIB2, -1))
2187  z8k1.pc = pc_new;
2188  } else {
2189  DISASM("|%s\t%s,$%04X", "DBJNZ", reg8names(OPCNIB2), pc_new);
2190  if (DO_EXEC && IncReg8(OPCNIB2, -1))
2191  z8k1.pc = pc_new;
2192  }
2193  if (DO_EXEC)
2194  cycles += 11;
2195  END;
2196 #if 0
2197  default:
2198  printf("Unknown opcode $%02X\n", opc);
2199  return -1;
2200 #endif
2201  }
2202  } while (cycles < cycles_limit);
2203  return cycles;
2204 }
stacksegusr
Uint8 stacksegusr
Definition: z8k1.c:130
use_ofs
Uint16 use_ofs
Definition: z8k1.c:135
index
int index
Definition: vera.c:66
stackptrusr
Uint16 stackptrusr
Definition: z8k1.c:129
F_CARRY_BY8
#define F_CARRY_BY8(v)
Definition: z8k1.c:229
psaofs
Uint16 psaofs
Definition: z8k1.c:133
stacksegsys
Uint8 stacksegsys
Definition: z8k1.c:130
FCW_SEG
#define FCW_SEG
Definition: z8k1.c:83
pc
Uint16 pc
Definition: z8k1.c:127
emutools.h
flags
Uint8 flags
Definition: z8k1.c:126
use_seg
Uint8 use_seg
Definition: z8k1.c:136
fcw
Uint8 fcw
Definition: z8k1.c:126
stackptrsys
Uint16 stackptrsys
Definition: z8k1.c:129
FCW_SYS
#define FCW_SYS
Definition: z8k1.c:84
seg
Uint8 seg
Definition: roms.c:41
F_CARRY_BOOL
#define F_CARRY_BOOL
Definition: z8k1.c:69
z8k1_init
void z8k1_init(void)
Definition: z8k1.c:516
reg8names
#define reg8names(n)
Definition: z8k1.c:146
FLAG_DA
#define FLAG_DA
Definition: z8k1.c:67
DO_EXEC
#define DO_EXEC
Definition: z8k1.c:61
BEGIN
#define BEGIN
Definition: z8k1.c:55
z8k1_step
int z8k1_step(int cycles_limit)
Definition: z8k1.c:520
z8k1_out_byte_cb
void z8k1_out_byte_cb(int special, Uint16 addr, Uint8 data)
ccnames
#define ccnames(n)
Definition: z8k1.c:166
m65-memcontent-generator.data
data
Definition: m65-memcontent-generator.py:119
Uint32
uint32_t Uint32
Definition: fat32.c:49
psaseg
Uint8 psaseg
Definition: z8k1.c:132
END
#define END
Definition: z8k1.c:56
Uint8
uint8_t Uint8
Definition: fat32.c:51
codeseg
Uint8 codeseg
Definition: z8k1.c:128
FLAG_ZERO
#define FLAG_ZERO
Definition: z8k1.c:64
DISASM
#define DISASM(fmt,...)
Definition: z8k1.c:100
z8k1_reset
void z8k1_reset(void)
Definition: z8k1.c:487
F_CARRY_BY16
#define F_CARRY_BY16(v)
Definition: z8k1.c:234
FCW_ALL_MASK
#define FCW_ALL_MASK
Definition: z8k1.c:88
DEBUGPRINT
#define DEBUGPRINT(...)
Definition: emutools_basicdefs.h:171
F_ZERO_BY16
#define F_ZERO_BY16(v)
Definition: z8k1.c:232
REG8INDEX
#define REG8INDEX(index)
Definition: z8k1.c:251
OPCNIB0
#define OPCNIB0
Definition: z8k1.c:264
NOT_EMULATED_OPCODE
#define NOT_EMULATED_OPCODE()
Definition: z8k1.c:107
reg32names
#define reg32names(n)
Definition: z8k1.c:156
z8k1_read_code_cb
Uint16 z8k1_read_code_cb(int seg, Uint16 ofs)
Definition: commodore_900.c:51
NL
#define NL
Definition: fat32.c:37
compress_sd_image.r
def r
Definition: compress_sd_image.py:76
F_ZERO_BY8
#define F_ZERO_BY8(v)
Definition: z8k1.c:227
get_address_mode
int get_address_mode
Definition: z8k1.c:137
FLAG_SIGN
#define FLAG_SIGN
Definition: z8k1.c:65
F_SIGN_BY8
#define F_SIGN_BY8(v)
Definition: z8k1.c:228
regs
Uint16 regs[16]
Definition: z8k1.c:125
F_ZERO_BOOL
#define F_ZERO_BOOL
Definition: z8k1.c:70
reg16names
#define reg16names(n)
Definition: z8k1.c:151
NOT_EMULATED_OPCODE_VARIANT
#define NOT_EMULATED_OPCODE_VARIANT()
Definition: z8k1.c:108
Uint16
uint16_t Uint16
Definition: fat32.c:50
F_OVERFLOW_BY16
#define F_OVERFLOW_BY16(ad1, ad2, res)
Definition: z8k1.c:235
F_PV_BOOL
#define F_PV_BOOL
Definition: z8k1.c:72
OPCNIB2
#define OPCNIB2
Definition: z8k1.c:262
F_SIGN_BY16
#define F_SIGN_BY16(v)
Definition: z8k1.c:233
F_OVERFLOW_BY8
#define F_OVERFLOW_BY8(ad1, ad2, res)
Definition: z8k1.c:230
RESERVED_OPCODE
#define RESERVED_OPCODE()
Definition: z8k1.c:109
reg64names
#define reg64names(n)
Definition: z8k1.c:161
z8k1.h
FATAL
#define FATAL(...)
Definition: xep128.h:117
OPCNIB1
#define OPCNIB1
Definition: z8k1.c:263
F_SIGN_BOOL
#define F_SIGN_BOOL
Definition: z8k1.c:71
FLAG_PV
#define FLAG_PV
Definition: z8k1.c:66
XEMU_UNLIKELY
#define XEMU_UNLIKELY(__x__)
Definition: emutools_basicdefs.h:125
refresh
Uint16 refresh
Definition: z8k1.c:131
F_HALFCARRY_BY8
#define F_HALFCARRY_BY8(ad1, ad2, res)
Definition: z8k1.c:240
FLAG_HC
#define FLAG_HC
Definition: z8k1.c:68
FLAG_CARRY
#define FLAG_CARRY
Definition: z8k1.c:63
IS_SEGMENTED_MODE
#define IS_SEGMENTED_MODE
Definition: z8k1.c:92