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