1 /*
2  * Simulated instructions specific to the LR35902, the Z-80 derivative used
3  * in the gameboy.
4  *
5  * 2011-12-21  created by Leland Morrison
6  *
7  *
8 
9 This file is part of microcontroller simulator: ucsim.
10 
11 UCSIM is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15 
16 UCSIM is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 GNU General Public License for more details.
20 
21 You should have received a copy of the GNU General Public License
22 along with UCSIM; see the file COPYING.  If not, write to the Free
23 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 02111-1307, USA. */
25 /*@1@*/
26 #include "ddconfig.h"
27 
28 #include "lr35902cl.h"
29 
swap_nibbles(u8_t val)30 static u8_t  swap_nibbles(u8_t  val) {
31   return ((val >> 4) & 0x0f) | ((val << 4) & 0xf0);
32 }
33 
inst_cb(void)34 int cl_lr35902::inst_cb(void) {
35   u8_t  result;
36   t_mem       code;
37 
38   if ( (peek1( ) & 0xf8) != 0x30 )
39     return cl_z80::inst_cb( );
40 
41   code = fetch1();
42 
43   /* perform SWAP instead of slia */
44   switch(code) {
45   case 0x30: result = regs.bc.h = swap_nibbles(regs.bc.h); break; /* b */
46   case 0x31: result = regs.bc.l = swap_nibbles(regs.bc.l); break; /* c */
47   case 0x32: result = regs.de.h = swap_nibbles(regs.de.h); break; /* d */
48   case 0x33: result = regs.de.l = swap_nibbles(regs.de.l); break; /* e */
49   case 0x34: result = regs.hl.l = swap_nibbles(regs.hl.h); break; /* h */
50   case 0x35: result = regs.hl.h = swap_nibbles(regs.hl.l); break; /* l */
51   case 0x36: /* SWAP (HL) */
52     {
53       result = swap_nibbles(get1(regs.HL));
54       store1(regs.HL, result);
55       vc.rd++;
56       vc.wr++;
57     }
58     break;
59 
60   case 0x37: result = regs.raf.A = swap_nibbles(regs.raf.A); break; /* swap a */
61   default: return resINV_INST;
62   }
63   regs.raf.F = (result)?0:0x80;  // all except zero are simply cleared
64   return(resGO);
65 }
66 
inst_st_sp_abs(t_mem code)67 int cl_lr35902::inst_st_sp_abs(t_mem code) {
68   if (code == 0x08) {
69     u16_t addr = fetch2( );
70     store2( addr, regs.SP );
71     vc.wr+= 2;
72     return(resGO);
73   }
74 
75   return resINV_INST;
76 }
77 
inst_stop0(t_mem code)78 int cl_lr35902::inst_stop0    (t_mem code) {
79   // TODO: change to wait for a signal for simulated hardware
80   return resHALT;
81 }
82 
inst_ldi(t_mem code)83 int cl_lr35902::inst_ldi   (t_mem code) {
84   if (code == 0x22) {
85     store1( regs.HL, regs.raf.A );
86     regs.HL ++;
87     vc.wr++;
88     return resGO;
89   } else if (code == 0x2A) {
90     regs.raf.A = get1( regs.HL );
91     regs.HL ++;
92     vc.rd++;
93     return resGO;
94   }
95 
96   return resINV_INST;
97 }
98 
inst_ldd(t_mem code)99 int cl_lr35902::inst_ldd   (t_mem code) {
100   if (code == 0x32) {
101     store1( regs.HL, regs.raf.A );
102     regs.HL --;
103     vc.wr++;
104     return resGO;
105   } else if (code == 0x3A) {
106     regs.raf.A = get1( regs.HL );
107     regs.HL --;
108     vc.rd++;
109     return resGO;
110   }
111 
112   return resINV_INST;
113 }
114 
inst_ldh(t_mem code)115 int cl_lr35902::inst_ldh   (t_mem code) {
116   u16_t addr = 0xFF00 + fetch1( );
117 
118   if (code == 0xE0) {
119     store1( addr, regs.raf.A );
120     vc.wr++;
121     return resGO;
122   } else if (code == 0xF0) {
123     regs.raf.A = get1( addr );
124     vc.rd++;
125     return resGO;
126   }
127 
128   return resINV_INST;
129 }
130 
inst_reti(t_mem code)131 int cl_lr35902::inst_reti  (t_mem code) {
132   /* enable interrupts */
133   cl_z80::inst_ei(0xFB);
134 
135   /* pop2(PC); */
136   PC=get2(regs.SP);
137   regs.SP+=2;
138   vc.rd+= 2;
139 
140   return resGO;
141 }
142 
inst_add_sp_d(t_mem code)143 int cl_lr35902::inst_add_sp_d(t_mem code) {
144   u16_t  d = fetch( );
145   /* sign-extend d from 8-bits to 16-bits */
146   d |= (d>>7)*0xFF00;
147 
148   regs.raf.F &= ~(BIT_ALL);  /* clear these */
149   if ((regs.SP & 0x0FFF) + (d & 0x0FFF) > 0x0FFF)
150     regs.raf.F |= BIT_A;
151   if (regs.SP + (int)(d) > 0xffff)
152     regs.raf.F |= BIT_C;
153 
154   regs.SP = (regs.SP + d) & 0xffff;
155 
156   return(resGO);
157 }
158 
inst_ld16(t_mem code)159 int cl_lr35902::inst_ld16  (t_mem code) {
160   u16_t addr = fetch2( );
161   if (code == 0xEA) {
162     store1( addr, regs.raf.A );
163     vc.wr++;
164     return resGO;
165   } else if (code == 0xFA) {
166     regs.raf.A = get1( addr );
167     vc.rd++;
168     return resGO;
169   }
170 
171   return resINV_INST;
172 }
173 
inst_ldhl_sp(t_mem code)174 int cl_lr35902::inst_ldhl_sp (t_mem code) {
175   u16_t  d = fetch( );
176   /* sign-extend d from 8-bits to 16-bits */
177   d |= (d>>7)*0xFF00;
178 
179   regs.raf.F &= ~(BIT_ALL);  /* clear these */
180   if ((regs.SP & 0x0FFF) + (d & 0x0FFF) > 0x0FFF)
181     regs.raf.F |= BIT_A;
182   if (regs.SP + (int)(d) > 0xffff)
183     regs.raf.F |= BIT_C;
184 
185   regs.HL = (regs.SP + d) & 0xffff;
186   return resGO;
187 }
188 
189