1 /*
2  * Simulator of microcontrollers (inst_xd.cc)
3  *  dd or fd escaped multi-byte opcodes.
4  *
5  *   This module gets pulled in and pre-processed to create
6  *   two modules.  DD prefixed opcodes reference
7  *   IX register, while FD prefixes reference IY register.
8  *   See inst_ddcb.cc and inst_fdcb.cc
9  *
10  * Copyright (C) 1999,2002 Drotos Daniel, Talker Bt.
11  * some z80 coding from Karl Bongers karl@turbobit.com
12  *
13  * To contact author send email to drdani@mazsola.iit.uni-miskolc.hu
14  *
15  */
16 
17 /* This file is part of microcontroller simulator: ucsim.
18 
19 UCSIM is free software; you can redistribute it and/or modify
20 it under the terms of the GNU General Public License as published by
21 the Free Software Foundation; either version 2 of the License, or
22 (at your option) any later version.
23 
24 UCSIM is distributed in the hope that it will be useful,
25 but WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27 GNU General Public License for more details.
28 
29 You should have received a copy of the GNU General Public License
30 along with UCSIM; see the file COPYING.  If not, write to the Free
31 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
32 02111-1307, USA. */
33 /*@1@*/
34 
35 int
inst_Xd_ld(t_mem code)36 cl_z80::inst_Xd_ld(t_mem code)
37 {
38   unsigned short tw;
39 
40   switch (code) {
41     case 0x21: // LD IX,nnnn
42       regs_IX_OR_IY = fetch2();
43     return(resGO);
44     case 0x22: // LD (nnnn),IX
45       tw = fetch2();
46       store2(tw, regs_IX_OR_IY);
47       vc.wr+= 2;
48     return(resGO);
49     case 0x26: // LD HX,nn
50       regs_iX_h = fetch1();
51     return(resGO);
52     case 0x2A: // LD IX,(nnnn)
53       tw = fetch2();
54       regs_IX_OR_IY = get2(tw);
55       vc.rd+= 2;
56     return(resGO);
57     case 0x2E: // LD LX,nn
58       regs_iX_l = fetch1();
59     return(resGO);
60     case 0x36: // LD (IX+dd),nn
61       tw = add_u16_disp(regs_IX_OR_IY, fetch());
62       store1(tw, fetch());
63       vc.wr++;
64     return(resGO);
65     case 0x44: // LD B,HX
66       regs.bc.h = regs_iX_h;
67     return(resGO);
68     case 0x45: // LD B,LX
69       regs.bc.h = regs_iX_l;
70     return(resGO);
71     case 0x46: // LD B,(IX+dd)
72       regs.bc.h = get1(add_u16_disp(regs_IX_OR_IY,fetch()));
73       vc.rd++;
74     return(resGO);
75     case 0x4C: // LD C,HX
76       regs.bc.l = regs_iX_h;
77     return(resGO);
78     case 0x4D: // LD C,LX
79       regs.bc.l = regs_iX_l;
80     return(resGO);
81     case 0x4E: // LD C,(IX+dd)
82       regs.bc.l = get1(add_u16_disp(regs_IX_OR_IY,fetch()));
83       vc.rd++;
84     return(resGO);
85     case 0x54: // LD D,HX
86       regs.de.h = regs_iX_h;
87     return(resGO);
88     case 0x55: // LD D,LX
89       regs.de.h = regs_iX_l;
90     return(resGO);
91     case 0x56: // LD D,(IX+dd)
92       regs.de.h = get1(add_u16_disp(regs_IX_OR_IY,fetch()));
93       vc.rd++;
94     return(resGO);
95     case 0x5C: // LD E,H
96       regs.de.l = regs.hl.h;
97     return(resGO);
98     case 0x5D: // LD E,L
99       regs.de.l = regs.hl.l;
100     return(resGO);
101     case 0x5E: // LD E,(IX+dd)
102       regs.de.l = get1(add_u16_disp(regs_IX_OR_IY,fetch()));
103       vc.rd++;
104     return(resGO);
105     case 0x60: // LD HX,B
106       regs_iX_h = regs.bc.h;
107     return(resGO);
108     case 0x61: // LD HX,C
109       regs_iX_h = regs.bc.l;
110     return(resGO);
111     case 0x62: // LD HX,D
112       regs_iX_h = regs.de.h;
113     return(resGO);
114     case 0x63: // LD HX,E
115       regs_iX_h = regs.de.l;
116     return(resGO);
117     case 0x64: // LD HX,HX
118     return(resGO);
119     case 0x65: // LD HX,LX
120       regs_iX_h = regs_iX_l;
121     return(resGO);
122     case 0x66: // LD H,(IX+dd)
123       regs.hl.h = get1(add_u16_disp(regs_IX_OR_IY,fetch()));
124       vc.rd++;
125     return(resGO);
126     case 0x67: // LD HX,A
127       regs_iX_h = regs.raf.A;
128     return(resGO);
129     case 0x68: // LD LX,B
130       regs_iX_l = regs.bc.h;
131     return(resGO);
132     case 0x69: // LD LX,C
133       regs_iX_l = regs.bc.l;
134     return(resGO);
135     case 0x6A: // LD LX,D
136       regs_iX_l = regs.de.h;
137     return(resGO);
138     case 0x6B: // LD LX,E
139       regs_iX_l = regs.de.l;
140     return(resGO);
141     case 0x6C: // LD LX,HX
142       regs_iX_l = regs.hl.h;
143     return(resGO);
144     case 0x6D: // LD LX,LX
145     return(resGO);
146     case 0x6E: // LD L,(IX+dd)
147       regs.hl.l = get1(add_u16_disp(regs_IX_OR_IY,fetch()));
148       vc.rd++;
149     return(resGO);
150     case 0x6F: // LD LX,A
151       regs_iX_l = regs.raf.A;
152     return(resGO);
153     case 0x70: // LD (IX+dd),B
154       store1(add_u16_disp(regs_IX_OR_IY,fetch()), regs.bc.h);
155       vc.wr++;
156     return(resGO);
157     case 0x71: // LD (IX+dd),C
158       store1(add_u16_disp(regs_IX_OR_IY,fetch()), regs.bc.l);
159       vc.wr++;
160     return(resGO);
161     case 0x72: // LD (IX+dd),D
162       store1(add_u16_disp(regs_IX_OR_IY,fetch()), regs.de.h);
163       vc.wr++;
164     return(resGO);
165     case 0x73: // LD (IX+dd),E
166       store1(add_u16_disp(regs_IX_OR_IY,fetch()), regs.de.l);
167       vc.wr++;
168     return(resGO);
169     case 0x74: // LD (IX+dd),H
170       store1(add_u16_disp(regs_IX_OR_IY,fetch()), regs.hl.h);
171       vc.wr++;
172     return(resGO);
173     case 0x75: // LD (IX+dd),L
174       store1(add_u16_disp(regs_IX_OR_IY,fetch()), regs.hl.l);
175       vc.wr++;
176     return(resGO);
177     case 0x77: // LD (IX+dd),A
178       store1(add_u16_disp(regs_IX_OR_IY,fetch()), regs.raf.A);
179       vc.wr++;
180     return(resGO);
181     case 0x7C: // LD A,HX
182       regs.raf.A = regs_iX_h;
183     return(resGO);
184     case 0x7D: // LD A,LX
185       regs.raf.A = regs_iX_l;
186     return(resGO);
187     case 0x7E: // LD A,(IX+dd)
188       regs.raf.A = get1(add_u16_disp(regs_IX_OR_IY,fetch()));
189       vc.rd++;
190     return(resGO);
191     case 0xF9: // LD SP,IX
192       regs.SP = regs_IX_OR_IY;
193     return(resGO);
194   }
195   return(resINV_INST);
196 }
197 
198 int
inst_Xd_add(t_mem code)199 cl_z80::inst_Xd_add(t_mem code)
200 {
201   switch (code) {
202     case 0x09: // ADD IX,BC
203       add_IX_Word(regs.BC);
204       return(resGO);
205     case 0x19: // ADD IX,DE
206       add_IX_Word(regs.DE);
207       return(resGO);
208     case 0x29: // ADD IX,IX
209       add_IX_Word(regs_IX_OR_IY);
210       return(resGO);
211     case 0x39: // ADD IX,SP
212       add_IX_Word(regs.SP);
213     return(resGO);
214     case 0x84: // ADD A,HX
215       add_A_bytereg(regs_iX_h);
216       return(resGO);
217     case 0x85: // ADD A,LX
218       add_A_bytereg(regs_iX_l);
219       return(resGO);
220     case 0x86: // ADD A,(IX+dd)
221       { unsigned char ourtmp;
222         t_addr addr;
223         addr = add_u16_disp(regs_IX_OR_IY, fetch());
224         ourtmp = get1(addr);
225         add_A_bytereg(ourtmp);
226 	vc.rd++;
227       }
228       return(resGO);
229   }
230   return(resINV_INST);
231 }
232 
233 int
inst_Xd_push(t_mem code)234 cl_z80::inst_Xd_push(t_mem code)
235 {
236   switch (code) {
237     case 0xe5: // PUSH IX
238       push2(regs_IX_OR_IY);
239       vc.wr+= 2;
240     return(resGO);
241   }
242   return(resINV_INST);
243 }
244 
245 int
inst_Xd_inc(t_mem code)246 cl_z80::inst_Xd_inc(t_mem code)
247 {
248   switch(code) {
249     case 0x23: // INC IX
250       ++regs_IX_OR_IY;
251     break;
252     case 0x24: // INC HX
253       inc(regs_iX_h);
254     break;
255     case 0x2C: // INC LX
256       inc(regs_iX_l);
257     break;
258     case 0x34: // INC (IX+dd)
259       {
260         t_addr addr;
261         unsigned char tmp;
262         addr = add_u16_disp(regs_IX_OR_IY,fetch());
263         tmp = get1(addr);
264         inc(tmp);
265         store1(addr, tmp);
266 	vc.rd++;
267 	vc.wr++;
268       }
269     break;
270     default:
271       return(resINV_INST);
272     break;
273   }
274   return(resGO);
275 }
276 
277 int
inst_Xd_dec(t_mem code)278 cl_z80::inst_Xd_dec(t_mem code)
279 {
280   switch(code) {
281     case 0x25: // DEC HX
282       dec(regs_iX_h);
283     break;
284     case 0x2B: // DEC IX
285       --regs_IX_OR_IY;
286     break;
287     case 0x2D: // DEC LX
288       dec(regs_iX_l);
289     break;
290     case 0x35: // DEC (IX+dd)
291       {
292         t_addr addr;
293         unsigned char tmp;
294         addr = add_u16_disp(regs_IX_OR_IY,fetch());
295         tmp = get1(addr);
296         dec(tmp);
297         store1(addr, tmp);
298 	vc.rd++;
299 	vc.wr++;
300       }
301     break;
302     default:
303       return(resINV_INST);
304     break;
305   }
306   return(resGO);
307 }
308 
309 
310 /* need ADC, SUB, SBC, AND, XOR, OR, CP */
311 int
inst_Xd_misc(t_mem code)312 cl_z80::inst_Xd_misc(t_mem code)
313 {
314   switch(code) {
315     case 0x8C: // ADC A,HX
316       adc_A_bytereg(regs_iX_h);
317     return(resGO);
318     case 0x8D: // ADC A,LX
319       adc_A_bytereg(regs_iX_l);
320     return(resGO);
321     case 0x8E: // ADC A,(IX+dd)
322       { unsigned char utmp;
323         t_addr addr;
324         addr = add_u16_disp(regs_IX_OR_IY, fetch());
325         utmp = get1(addr);
326         adc_A_bytereg(utmp);
327 	vc.rd++;
328       }
329     return(resGO);
330 
331     case 0x94: // SUB HX
332       sub_A_bytereg(regs_iX_h);
333     return(resGO);
334     case 0x95: // SUB LX
335       sub_A_bytereg(regs_iX_l);
336     return(resGO);
337     case 0x96: // SUB (IX+dd)
338       { unsigned char tmp1;
339         tmp1 = get1(add_u16_disp(regs_IX_OR_IY, fetch()));
340         sub_A_bytereg(tmp1);
341 	vc.rd++;
342       }
343     return(resGO);
344 
345     case 0x9C: // SBC A,HX
346       sbc_A_bytereg(regs_iX_h);
347     return(resGO);
348     case 0x9D: // SBC A,LX
349       sbc_A_bytereg(regs_iX_l);
350     return(resGO);
351     case 0x9E: // SBC A,(IX+dd)
352       { unsigned char utmp;
353         utmp = get1(add_u16_disp(regs_IX_OR_IY, fetch()));
354         sbc_A_bytereg(utmp);
355 	vc.rd++;
356       }
357     return(resGO);
358 
359     case 0xA4: // AND HX
360       and_A_bytereg(regs_iX_h);
361     return(resGO);
362     case 0xA5: // AND LX
363       and_A_bytereg(regs_iX_l);
364     return(resGO);
365     case 0xA6: // AND (IX+dd)
366       { unsigned char utmp;
367         utmp = get1(add_u16_disp(regs_IX_OR_IY, fetch()));
368         and_A_bytereg(utmp);
369 	vc.rd++;
370       }
371     return(resGO);
372 
373     case 0xAC: // XOR HX
374       xor_A_bytereg(regs_iX_h);
375     return(resGO);
376     case 0xAD: // XOR LX
377       xor_A_bytereg(regs_iX_l);
378     return(resGO);
379     case 0xAE: // XOR (IX+dd)
380       { unsigned char utmp;
381         utmp = get1(add_u16_disp(regs_IX_OR_IY, fetch()));
382         xor_A_bytereg(utmp);
383 	vc.rd++;
384       }
385     return(resGO);
386 
387     case 0xB4: // OR HX
388       or_A_bytereg(regs_iX_h);
389     return(resGO);
390     case 0xB5: // OR LX
391       or_A_bytereg(regs_iX_l);
392     return(resGO);
393     case 0xB6: // OR (IX+dd)
394       { unsigned char utmp;
395         utmp = get1(add_u16_disp(regs_IX_OR_IY, fetch()));
396         or_A_bytereg(utmp);
397 	vc.rd++;
398       }
399     return(resGO);
400 
401     case 0xBC: // CP HX
402       cp_bytereg(regs_iX_h);
403     return(resGO);
404     case 0xBD: // CP LX
405       cp_bytereg(regs_iX_l);
406     return(resGO);
407     case 0xBE: // CP (IX+dd)
408       { unsigned char utmp;
409         utmp = get1(add_u16_disp(regs_IX_OR_IY, fetch()));
410         cp_bytereg(utmp);
411 	vc.rd++;
412       }
413     return(resGO);
414   }
415   return(resINV_INST);
416 }
417 
418 int
inst_Xd(t_mem prefix)419 cl_z80::inst_Xd(t_mem prefix)
420 {
421   t_mem code;
422   int i;
423 
424   if (fetch(&code))
425     return(resBREAKPOINT);
426 
427   switch (prefix)
428     {
429     case 0xdd:
430       if ((i= inst_dd_spec(code)) >= 0)
431 	return i;
432     case 0xfd:
433       if ((i= inst_fd_spec(code)) >= 0)
434 	return i;
435     }
436 
437   switch (code)
438     {
439       case 0x21: // LD IX,nnnn
440       case 0x22: // LD (nnnn),IX
441       case 0x26: // LD HX,nn
442       case 0x2A: // LD IX,(nnnn)
443       case 0x2E: // LD LX,nn
444       case 0x36: // LD (IX+dd),nn
445       case 0x44: // LD B,HX
446       case 0x45: // LD B,LX
447       case 0x46: // LD B,(IX+dd)
448       case 0x4C: // LD C,HX
449       case 0x4D: // LD C,LX
450       case 0x4E: // LD C,(IX+dd)
451       case 0x54: // LD D,HX
452       case 0x55: // LD D,LX
453       case 0x56: // LD D,(IX+dd)
454       case 0x5C: // LD E,H
455       case 0x5D: // LD E,L
456       case 0x5E: // LD E,(IX+dd)
457       case 0x60: // LD HX,B
458       case 0x61: // LD HX,C
459       case 0x62: // LD HX,D
460       case 0x63: // LD HX,E
461       case 0x64: // LD HX,HX
462       case 0x66: // LD H,(IX+dd)
463       case 0x67: // LD HX,A
464       case 0x68: // LD LX,B
465       case 0x69: // LD LX,C
466       case 0x6A: // LD LX,D
467       case 0x6B: // LD LX,E
468       case 0x6C: // LD LX,HX
469       case 0x6D: // LD LX,LX
470       case 0x6E: // LD L,(IX+dd)
471       case 0x6F: // LD LX,A
472       case 0x70: // LD (IX+dd),B
473       case 0x71: // LD (IX+dd),C
474       case 0x72: // LD (IX+dd),D
475       case 0x73: // LD (IX+dd),E
476       case 0x74: // LD (IX+dd),H
477       case 0x75: // LD (IX+dd),L
478       case 0x77: // LD (IX+dd),A
479       case 0x7C: // LD A,HX
480       case 0x7D: // LD A,LX
481       case 0x7E: // LD A,(IX+dd)
482       case 0xF9: // LD SP,IX
483         return(inst_Xd_ld(code));
484 
485       case 0x23: // INC IX
486       case 0x24: // INC HX
487       case 0x2C: // INC LX
488       case 0x34: // INC (IX+dd)
489         return(inst_Xd_inc(code));
490 
491       case 0x09: // ADD IX,BC
492       case 0x19: // ADD IX,DE
493       case 0x29: // ADD IX,IX
494       case 0x39: // ADD IX,SP
495       case 0x84: // ADD A,HX
496       case 0x85: // ADD A,LX
497       case 0x86: // ADD A,(IX)
498         return(inst_Xd_add(code));
499 
500       case 0x25: // DEC HX
501       case 0x2B: // DEC IX
502       case 0x2D: // DEC LX
503       case 0x35: // DEC (IX+dd)
504 	return(inst_Xd_dec(code));
505 
506       case 0x8C: // ADC A,HX
507       case 0x8D: // ADC A,LX
508       case 0x8E: // ADC A,(IX)
509       case 0x94: // SUB HX
510       case 0x95: // SUB LX
511       case 0x96: // SUB (IX+dd)
512       case 0x9C: // SBC A,HX
513       case 0x9D: // SBC A,LX
514       case 0x9E: // SBC A,(IX+dd)
515       case 0xA4: // AND HX
516       case 0xA5: // AND LX
517       case 0xA6: // AND (IX+dd)
518       case 0xAC: // XOR HX
519       case 0xAD: // XOR LX
520       case 0xAE: // XOR (IX+dd)
521       case 0xB4: // OR HX
522       case 0xB5: // OR LX
523       case 0xB6: // OR (IX+dd)
524       case 0xBC: // CP HX
525       case 0xBD: // CP LX
526       case 0xBE: // CP (IX+dd)
527         return(inst_Xd_misc(code));
528       break;
529 
530       case 0xCB: // escape, IX prefix to CB commands
531         return(inst_Xdcb()); /* see inst_ddcb.cc */
532       break;
533 
534       case 0xE1: // POP IX
535         regs_IX_OR_IY = get2(regs.SP);
536         regs.SP+=2;
537 	vc.rd+= 2;
538       return(resGO);
539 
540       case 0xE3: // EX (SP),IX
541         {
542           u16_t tempw;
543 
544           tempw = regs_IX_OR_IY;
545           regs_IX_OR_IY = get2(regs.SP);
546           store2(regs.SP, tempw);
547 	  vc.rd+= 2;
548 	  vc.wr+= 2;
549         }
550       return(resGO);
551 
552       case 0xE5: // PUSH IX
553         push2(regs_IX_OR_IY);
554 	vc.wr+= 2;
555       return(resGO);
556 
557       case 0xE9: // JP (IX)
558         PC = regs_IX_OR_IY;
559       return(resGO);
560 
561       default:
562       return(resINV_INST);
563     }
564   return(resINV_INST);
565 }
566 
567 /* End of z80.src/inst_xd.cc */
568