diff options
author | Torne Wuff <torne@wolfpuppy.org.uk> | 2011-11-06 22:44:25 +0000 |
---|---|---|
committer | Torne Wuff <torne@wolfpuppy.org.uk> | 2011-11-06 22:44:25 +0000 |
commit | 569285794b9112f0134ddad4bb886308ea4a7be6 (patch) | |
tree | ce702cb07829820261a682c471133c76d11c610e /apps/codecs/libgme/nes_cpu_run.h | |
parent | d9b7d58fa6c9ceb136bea429adf6746cc7138208 (diff) | |
download | rockbox-569285794b9112f0134ddad4bb886308ea4a7be6.tar.gz rockbox-569285794b9112f0134ddad4bb886308ea4a7be6.zip |
Bulk convert all DOS line endings to UNIX.
For the git migration we want a nice clean repository with UNIX line
endings. git does not use svn:eol-style, we just need the file contents to be
sane.
Sorry everybody. I know this messes up blame.
Scumbag *NIX developer says migrating to git will make line ending issues go
away; commits giant change to svn which changes line endings anyway. :)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30924 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/codecs/libgme/nes_cpu_run.h')
-rw-r--r-- | apps/codecs/libgme/nes_cpu_run.h | 2244 |
1 files changed, 1122 insertions, 1122 deletions
diff --git a/apps/codecs/libgme/nes_cpu_run.h b/apps/codecs/libgme/nes_cpu_run.h index 5b964d5070..fd1fea9659 100644 --- a/apps/codecs/libgme/nes_cpu_run.h +++ b/apps/codecs/libgme/nes_cpu_run.h | |||
@@ -1,1122 +1,1122 @@ | |||
1 | // NES 6502 cpu emulator run function | 1 | // NES 6502 cpu emulator run function |
2 | 2 | ||
3 | #if 0 | 3 | #if 0 |
4 | /* Define these macros in the source file before #including this file. | 4 | /* Define these macros in the source file before #including this file. |
5 | - Parameters might be expressions, so they are best evaluated only once, | 5 | - Parameters might be expressions, so they are best evaluated only once, |
6 | though they NEVER have side-effects, so multiple evaluation is OK. | 6 | though they NEVER have side-effects, so multiple evaluation is OK. |
7 | - Output parameters might be a multiple-assignment expression like "a=x", | 7 | - Output parameters might be a multiple-assignment expression like "a=x", |
8 | so they must NOT be parenthesized. | 8 | so they must NOT be parenthesized. |
9 | - Except where noted, time() and related functions will NOT work | 9 | - Except where noted, time() and related functions will NOT work |
10 | correctly inside a macro. TIME() is always correct, and FLUSH_TIME() and | 10 | correctly inside a macro. TIME() is always correct, and FLUSH_TIME() and |
11 | CACHE_TIME() allow the time changing functions to work. | 11 | CACHE_TIME() allow the time changing functions to work. |
12 | - Macros "returning" void may use a {} statement block. */ | 12 | - Macros "returning" void may use a {} statement block. */ |
13 | 13 | ||
14 | // 0 <= addr <= 0xFFFF + page_size | 14 | // 0 <= addr <= 0xFFFF + page_size |
15 | // time functions can be used | 15 | // time functions can be used |
16 | int READ_MEM( addr_t ); | 16 | int READ_MEM( addr_t ); |
17 | void WRITE_MEM( addr_t, int data ); | 17 | void WRITE_MEM( addr_t, int data ); |
18 | // 0 <= READ_MEM() <= 0xFF | 18 | // 0 <= READ_MEM() <= 0xFF |
19 | 19 | ||
20 | // 0 <= addr <= 0x1FF | 20 | // 0 <= addr <= 0x1FF |
21 | int READ_LOW( addr_t ); | 21 | int READ_LOW( addr_t ); |
22 | void WRITE_LOW( addr_t, int data ); | 22 | void WRITE_LOW( addr_t, int data ); |
23 | // 0 <= READ_LOW() <= 0xFF | 23 | // 0 <= READ_LOW() <= 0xFF |
24 | 24 | ||
25 | // Often-used instructions attempt these before using a normal memory access. | 25 | // Often-used instructions attempt these before using a normal memory access. |
26 | // Optional; defaults to READ_MEM() and WRITE_MEM() | 26 | // Optional; defaults to READ_MEM() and WRITE_MEM() |
27 | bool CAN_READ_FAST( addr_t ); // if true, uses result of READ_FAST | 27 | bool CAN_READ_FAST( addr_t ); // if true, uses result of READ_FAST |
28 | void READ_FAST( addr_t, int& out ); // ALWAYS called BEFORE CAN_READ_FAST | 28 | void READ_FAST( addr_t, int& out ); // ALWAYS called BEFORE CAN_READ_FAST |
29 | bool CAN_WRITE_FAST( addr_t ); // if true, uses WRITE_FAST instead of WRITE_MEM | 29 | bool CAN_WRITE_FAST( addr_t ); // if true, uses WRITE_FAST instead of WRITE_MEM |
30 | void WRITE_FAST( addr_t, int data ); | 30 | void WRITE_FAST( addr_t, int data ); |
31 | 31 | ||
32 | // Used by instructions most often used to access the NES PPU (LDA abs and BIT abs). | 32 | // Used by instructions most often used to access the NES PPU (LDA abs and BIT abs). |
33 | // Optional; defaults to READ_MEM. | 33 | // Optional; defaults to READ_MEM. |
34 | void READ_PPU( addr_t, int& out ); | 34 | void READ_PPU( addr_t, int& out ); |
35 | // 0 <= out <= 0xFF | 35 | // 0 <= out <= 0xFF |
36 | 36 | ||
37 | // The following can be used within macros: | 37 | // The following can be used within macros: |
38 | 38 | ||
39 | // Current time | 39 | // Current time |
40 | time_t TIME(); | 40 | time_t TIME(); |
41 | 41 | ||
42 | // Allows use of time functions | 42 | // Allows use of time functions |
43 | void FLUSH_TIME(); | 43 | void FLUSH_TIME(); |
44 | 44 | ||
45 | // Must be used before end of macro if FLUSH_TIME() was used earlier | 45 | // Must be used before end of macro if FLUSH_TIME() was used earlier |
46 | void CACHE_TIME(); | 46 | void CACHE_TIME(); |
47 | 47 | ||
48 | // Configuration (optional; commented behavior if defined) | 48 | // Configuration (optional; commented behavior if defined) |
49 | 49 | ||
50 | // Emulates dummy reads for indexed instructions | 50 | // Emulates dummy reads for indexed instructions |
51 | #define NES_CPU_DUMMY_READS 1 | 51 | #define NES_CPU_DUMMY_READS 1 |
52 | 52 | ||
53 | // Optimizes as if map_code( 0, 0x10000 + cpu_padding, FLAT_MEM ) is always in effect | 53 | // Optimizes as if map_code( 0, 0x10000 + cpu_padding, FLAT_MEM ) is always in effect |
54 | #define FLAT_MEM my_mem_array | 54 | #define FLAT_MEM my_mem_array |
55 | 55 | ||
56 | // Expanded just before beginning of code, to help debugger | 56 | // Expanded just before beginning of code, to help debugger |
57 | #define CPU_BEGIN void my_run_cpu() { | 57 | #define CPU_BEGIN void my_run_cpu() { |
58 | 58 | ||
59 | #endif | 59 | #endif |
60 | 60 | ||
61 | /* Copyright (C) 2003-2008 Shay Green. This module is free software; you | 61 | /* Copyright (C) 2003-2008 Shay Green. This module is free software; you |
62 | can redistribute it and/or modify it under the terms of the GNU Lesser | 62 | can redistribute it and/or modify it under the terms of the GNU Lesser |
63 | General Public License as published by the Free Software Foundation; either | 63 | General Public License as published by the Free Software Foundation; either |
64 | version 2.1 of the License, or (at your option) any later version. This | 64 | version 2.1 of the License, or (at your option) any later version. This |
65 | module is distributed in the hope that it will be useful, but WITHOUT ANY | 65 | module is distributed in the hope that it will be useful, but WITHOUT ANY |
66 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 66 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
67 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | 67 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
68 | details. You should have received a copy of the GNU Lesser General Public | 68 | details. You should have received a copy of the GNU Lesser General Public |
69 | License along with this module; if not, write to the Free Software Foundation, | 69 | License along with this module; if not, write to the Free Software Foundation, |
70 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | 70 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ |
71 | 71 | ||
72 | // Allows MWCW debugger to step through code properly | 72 | // Allows MWCW debugger to step through code properly |
73 | #ifdef CPU_BEGIN | 73 | #ifdef CPU_BEGIN |
74 | CPU_BEGIN | 74 | CPU_BEGIN |
75 | #endif | 75 | #endif |
76 | 76 | ||
77 | // Time | 77 | // Time |
78 | #define TIME() (s_time + s.base) | 78 | #define TIME() (s_time + s.base) |
79 | #define FLUSH_TIME() {s.time = s_time - time_offset;} | 79 | #define FLUSH_TIME() {s.time = s_time - time_offset;} |
80 | #define CACHE_TIME() {s_time = s.time + time_offset;} | 80 | #define CACHE_TIME() {s_time = s.time + time_offset;} |
81 | 81 | ||
82 | // Defaults | 82 | // Defaults |
83 | #ifndef CAN_WRITE_FAST | 83 | #ifndef CAN_WRITE_FAST |
84 | #define CAN_WRITE_FAST( addr ) 0 | 84 | #define CAN_WRITE_FAST( addr ) 0 |
85 | #define WRITE_FAST( addr, data ) | 85 | #define WRITE_FAST( addr, data ) |
86 | #endif | 86 | #endif |
87 | 87 | ||
88 | #ifndef CAN_READ_FAST | 88 | #ifndef CAN_READ_FAST |
89 | #define CAN_READ_FAST( addr ) 0 | 89 | #define CAN_READ_FAST( addr ) 0 |
90 | #define READ_FAST( addr, out ) | 90 | #define READ_FAST( addr, out ) |
91 | #endif | 91 | #endif |
92 | 92 | ||
93 | #ifndef READ_PPU | 93 | #ifndef READ_PPU |
94 | #define READ_PPU( addr, out )\ | 94 | #define READ_PPU( addr, out )\ |
95 | {\ | 95 | {\ |
96 | FLUSH_TIME();\ | 96 | FLUSH_TIME();\ |
97 | out = READ_MEM( addr );\ | 97 | out = READ_MEM( addr );\ |
98 | CACHE_TIME();\ | 98 | CACHE_TIME();\ |
99 | } | 99 | } |
100 | #endif | 100 | #endif |
101 | 101 | ||
102 | #define READ_STACK READ_LOW | 102 | #define READ_STACK READ_LOW |
103 | #define WRITE_STACK WRITE_LOW | 103 | #define WRITE_STACK WRITE_LOW |
104 | 104 | ||
105 | // Dummy reads | 105 | // Dummy reads |
106 | #ifdef NES_CPU_DUMMY_READS | 106 | #ifdef NES_CPU_DUMMY_READS |
107 | // TODO: optimize time handling | 107 | // TODO: optimize time handling |
108 | #define DUMMY_READ( addr, idx ) \ | 108 | #define DUMMY_READ( addr, idx ) \ |
109 | if ( (addr & 0xFF) < idx )\ | 109 | if ( (addr & 0xFF) < idx )\ |
110 | {\ | 110 | {\ |
111 | int const time_offset = 1;\ | 111 | int const time_offset = 1;\ |
112 | FLUSH_TIME();\ | 112 | FLUSH_TIME();\ |
113 | READ_MEM( (addr - 0x100) );\ | 113 | READ_MEM( (addr - 0x100) );\ |
114 | CACHE_TIME();\ | 114 | CACHE_TIME();\ |
115 | } | 115 | } |
116 | #else | 116 | #else |
117 | #define DUMMY_READ( addr, idx ) | 117 | #define DUMMY_READ( addr, idx ) |
118 | #endif | 118 | #endif |
119 | 119 | ||
120 | // Code | 120 | // Code |
121 | #ifdef FLAT_MEM | 121 | #ifdef FLAT_MEM |
122 | #define CODE_PAGE( addr ) (FLAT_MEM) | 122 | #define CODE_PAGE( addr ) (FLAT_MEM) |
123 | #define CODE_OFFSET( addr ) (addr) | 123 | #define CODE_OFFSET( addr ) (addr) |
124 | #else | 124 | #else |
125 | #define CODE_PAGE( addr ) (s.code_map [NES_CPU_PAGE( addr )]) | 125 | #define CODE_PAGE( addr ) (s.code_map [NES_CPU_PAGE( addr )]) |
126 | #define CODE_OFFSET( addr ) NES_CPU_OFFSET( addr ) | 126 | #define CODE_OFFSET( addr ) NES_CPU_OFFSET( addr ) |
127 | #endif | 127 | #endif |
128 | #define READ_CODE( addr ) (CODE_PAGE( addr ) [CODE_OFFSET( addr )]) | 128 | #define READ_CODE( addr ) (CODE_PAGE( addr ) [CODE_OFFSET( addr )]) |
129 | 129 | ||
130 | // Stack | 130 | // Stack |
131 | #define SET_SP( v ) (sp = ((v) + 1) | 0x100) | 131 | #define SET_SP( v ) (sp = ((v) + 1) | 0x100) |
132 | #define GET_SP() ((sp - 1) & 0xFF) | 132 | #define GET_SP() ((sp - 1) & 0xFF) |
133 | #define SP( o ) ((sp + (o - (o>0)*0x100)) | 0x100) | 133 | #define SP( o ) ((sp + (o - (o>0)*0x100)) | 0x100) |
134 | 134 | ||
135 | // Truncation | 135 | // Truncation |
136 | #define BYTE( n ) ((uint8_t ) (n)) /* (unsigned) n & 0xFF */ | 136 | #define BYTE( n ) ((uint8_t ) (n)) /* (unsigned) n & 0xFF */ |
137 | #define SBYTE( n ) ((int8_t ) (n)) /* (BYTE( n ) ^ 0x80) - 0x80 */ | 137 | #define SBYTE( n ) ((int8_t ) (n)) /* (BYTE( n ) ^ 0x80) - 0x80 */ |
138 | #define WORD( n ) ((uint16_t) (n)) /* (unsigned) n & 0xFFFF */ | 138 | #define WORD( n ) ((uint16_t) (n)) /* (unsigned) n & 0xFFFF */ |
139 | 139 | ||
140 | // Flags with hex value for clarity when used as mask. | 140 | // Flags with hex value for clarity when used as mask. |
141 | // Stored in indicated variable during emulation. | 141 | // Stored in indicated variable during emulation. |
142 | int const n80 = 0x80; // nz | 142 | int const n80 = 0x80; // nz |
143 | int const v40 = 0x40; // flags | 143 | int const v40 = 0x40; // flags |
144 | int const r20 = 0x20; | 144 | int const r20 = 0x20; |
145 | int const b10 = 0x10; | 145 | int const b10 = 0x10; |
146 | int const d08 = 0x08; // flags | 146 | int const d08 = 0x08; // flags |
147 | int const i04 = 0x04; // flags | 147 | int const i04 = 0x04; // flags |
148 | int const z02 = 0x02; // nz | 148 | int const z02 = 0x02; // nz |
149 | int const c01 = 0x01; // c | 149 | int const c01 = 0x01; // c |
150 | 150 | ||
151 | #define IS_NEG (nz & 0x8080) | 151 | #define IS_NEG (nz & 0x8080) |
152 | 152 | ||
153 | #define GET_FLAGS( out ) \ | 153 | #define GET_FLAGS( out ) \ |
154 | {\ | 154 | {\ |
155 | out = flags & (v40 | d08 | i04);\ | 155 | out = flags & (v40 | d08 | i04);\ |
156 | out += ((nz >> 8) | nz) & n80;\ | 156 | out += ((nz >> 8) | nz) & n80;\ |
157 | out += c >> 8 & c01;\ | 157 | out += c >> 8 & c01;\ |
158 | if ( !BYTE( nz ) )\ | 158 | if ( !BYTE( nz ) )\ |
159 | out += z02;\ | 159 | out += z02;\ |
160 | } | 160 | } |
161 | 161 | ||
162 | #define SET_FLAGS( in ) \ | 162 | #define SET_FLAGS( in ) \ |
163 | {\ | 163 | {\ |
164 | flags = in & (v40 | d08 | i04);\ | 164 | flags = in & (v40 | d08 | i04);\ |
165 | c = nz = in << 8;\ | 165 | c = nz = in << 8;\ |
166 | nz += ~in & z02;\ | 166 | nz += ~in & z02;\ |
167 | } | 167 | } |
168 | 168 | ||
169 | { | 169 | { |
170 | int const time_offset = 0; | 170 | int const time_offset = 0; |
171 | 171 | ||
172 | // Local state | 172 | // Local state |
173 | struct cpu_state_t s; | 173 | struct cpu_state_t s; |
174 | #ifdef FLAT_MEM | 174 | #ifdef FLAT_MEM |
175 | s.base = cpu->cpu_state_.base; | 175 | s.base = cpu->cpu_state_.base; |
176 | #else | 176 | #else |
177 | s = cpu->cpu_state_; | 177 | s = cpu->cpu_state_; |
178 | #endif | 178 | #endif |
179 | cpu->cpu_state = &s; | 179 | cpu->cpu_state = &s; |
180 | int s_time = cpu->cpu_state_.time; // helps even on x86 | 180 | int s_time = cpu->cpu_state_.time; // helps even on x86 |
181 | 181 | ||
182 | // Registers | 182 | // Registers |
183 | int pc = cpu->r.pc; | 183 | int pc = cpu->r.pc; |
184 | int a = cpu->r.a; | 184 | int a = cpu->r.a; |
185 | int x = cpu->r.x; | 185 | int x = cpu->r.x; |
186 | int y = cpu->r.y; | 186 | int y = cpu->r.y; |
187 | int sp; | 187 | int sp; |
188 | SET_SP( cpu->r.sp ); | 188 | SET_SP( cpu->r.sp ); |
189 | 189 | ||
190 | // Flags | 190 | // Flags |
191 | int flags; | 191 | int flags; |
192 | int c; // carry set if (c & 0x100) != 0 | 192 | int c; // carry set if (c & 0x100) != 0 |
193 | int nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0 | 193 | int nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0 |
194 | { | 194 | { |
195 | int temp = cpu->r.flags; | 195 | int temp = cpu->r.flags; |
196 | SET_FLAGS( temp ); | 196 | SET_FLAGS( temp ); |
197 | } | 197 | } |
198 | 198 | ||
199 | loop: | 199 | loop: |
200 | 200 | ||
201 | // Check all values | 201 | // Check all values |
202 | check( (unsigned) sp - 0x100 < 0x100 ); | 202 | check( (unsigned) sp - 0x100 < 0x100 ); |
203 | check( (unsigned) pc < 0x10000 ); | 203 | check( (unsigned) pc < 0x10000 ); |
204 | check( (unsigned) a < 0x100 ); | 204 | check( (unsigned) a < 0x100 ); |
205 | check( (unsigned) x < 0x100 ); | 205 | check( (unsigned) x < 0x100 ); |
206 | check( (unsigned) y < 0x100 ); | 206 | check( (unsigned) y < 0x100 ); |
207 | 207 | ||
208 | // Read instruction | 208 | // Read instruction |
209 | byte const* instr = CODE_PAGE( pc ); | 209 | byte const* instr = CODE_PAGE( pc ); |
210 | int opcode; | 210 | int opcode; |
211 | 211 | ||
212 | if ( CODE_OFFSET(~0) == ~0 ) | 212 | if ( CODE_OFFSET(~0) == ~0 ) |
213 | { | 213 | { |
214 | opcode = instr [pc]; | 214 | opcode = instr [pc]; |
215 | pc++; | 215 | pc++; |
216 | instr += pc; | 216 | instr += pc; |
217 | } | 217 | } |
218 | else | 218 | else |
219 | { | 219 | { |
220 | instr += CODE_OFFSET( pc ); | 220 | instr += CODE_OFFSET( pc ); |
221 | opcode = *instr++; | 221 | opcode = *instr++; |
222 | pc++; | 222 | pc++; |
223 | } | 223 | } |
224 | 224 | ||
225 | // local to function in case it helps optimizer | 225 | // local to function in case it helps optimizer |
226 | static byte const clock_table [256] = | 226 | static byte const clock_table [256] = |
227 | {// 0 1 2 3 4 5 6 7 8 9 A B C D E F | 227 | {// 0 1 2 3 4 5 6 7 8 9 A B C D E F |
228 | 0,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6,// 0 | 228 | 0,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6,// 0 |
229 | 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 1 | 229 | 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 1 |
230 | 6,6,0,8,3,3,5,5,4,2,2,2,4,4,6,6,// 2 | 230 | 6,6,0,8,3,3,5,5,4,2,2,2,4,4,6,6,// 2 |
231 | 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 3 | 231 | 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 3 |
232 | 6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6,// 4 | 232 | 6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6,// 4 |
233 | 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 5 | 233 | 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 5 |
234 | 6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6,// 6 | 234 | 6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6,// 6 |
235 | 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 7 | 235 | 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 7 |
236 | 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// 8 | 236 | 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// 8 |
237 | 2,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5,// 9 | 237 | 2,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5,// 9 |
238 | 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// A | 238 | 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// A |
239 | 2,5,2,5,4,4,4,4,2,4,2,4,4,4,4,4,// B | 239 | 2,5,2,5,4,4,4,4,2,4,2,4,4,4,4,4,// B |
240 | 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// C | 240 | 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// C |
241 | 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// D | 241 | 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// D |
242 | 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// E | 242 | 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// E |
243 | 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7 // F | 243 | 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7 // F |
244 | }; // 0x00 was 7 and 0x22 was 2 | 244 | }; // 0x00 was 7 and 0x22 was 2 |
245 | 245 | ||
246 | // Update time | 246 | // Update time |
247 | if ( s_time >= 0 ) | 247 | if ( s_time >= 0 ) |
248 | goto out_of_time; | 248 | goto out_of_time; |
249 | 249 | ||
250 | #ifdef CPU_INSTR_HOOK | 250 | #ifdef CPU_INSTR_HOOK |
251 | { CPU_INSTR_HOOK( (pc-1), (&instr [-1]), a, x, y, GET_SP(), TIME() ); } | 251 | { CPU_INSTR_HOOK( (pc-1), (&instr [-1]), a, x, y, GET_SP(), TIME() ); } |
252 | #endif | 252 | #endif |
253 | 253 | ||
254 | s_time += clock_table [opcode]; | 254 | s_time += clock_table [opcode]; |
255 | 255 | ||
256 | int data; | 256 | int data; |
257 | data = *instr; | 257 | data = *instr; |
258 | 258 | ||
259 | switch ( opcode ) | 259 | switch ( opcode ) |
260 | { | 260 | { |
261 | 261 | ||
262 | // Macros | 262 | // Macros |
263 | 263 | ||
264 | #define GET_MSB() (instr [1]) | 264 | #define GET_MSB() (instr [1]) |
265 | #define ADD_PAGE( out ) (pc++, out = data + 0x100 * GET_MSB()) | 265 | #define ADD_PAGE( out ) (pc++, out = data + 0x100 * GET_MSB()) |
266 | #define GET_ADDR() GET_LE16( instr ) | 266 | #define GET_ADDR() GET_LE16( instr ) |
267 | 267 | ||
268 | #define PAGE_PENALTY( lsb ) s_time += (lsb) >> 8; | 268 | #define PAGE_PENALTY( lsb ) s_time += (lsb) >> 8; |
269 | 269 | ||
270 | #define INC_DEC( reg, n ) reg = BYTE( nz = reg + n ); goto loop; | 270 | #define INC_DEC( reg, n ) reg = BYTE( nz = reg + n ); goto loop; |
271 | 271 | ||
272 | #define IND_Y( cross, out ) {\ | 272 | #define IND_Y( cross, out ) {\ |
273 | int temp = READ_LOW( data ) + y;\ | 273 | int temp = READ_LOW( data ) + y;\ |
274 | out = temp + 0x100 * READ_LOW( BYTE( data + 1 ) );\ | 274 | out = temp + 0x100 * READ_LOW( BYTE( data + 1 ) );\ |
275 | cross( temp );\ | 275 | cross( temp );\ |
276 | } | 276 | } |
277 | 277 | ||
278 | #define IND_X( out ) {\ | 278 | #define IND_X( out ) {\ |
279 | int temp = data + x;\ | 279 | int temp = data + x;\ |
280 | out = 0x100 * READ_LOW( BYTE( temp + 1 ) ) + READ_LOW( BYTE( temp ) );\ | 280 | out = 0x100 * READ_LOW( BYTE( temp + 1 ) ) + READ_LOW( BYTE( temp ) );\ |
281 | } | 281 | } |
282 | 282 | ||
283 | #define ARITH_ADDR_MODES( op )\ | 283 | #define ARITH_ADDR_MODES( op )\ |
284 | case op - 0x04: /* (ind,x) */\ | 284 | case op - 0x04: /* (ind,x) */\ |
285 | IND_X( data )\ | 285 | IND_X( data )\ |
286 | goto ptr##op;\ | 286 | goto ptr##op;\ |
287 | case op + 0x0C: /* (ind),y */\ | 287 | case op + 0x0C: /* (ind),y */\ |
288 | IND_Y( PAGE_PENALTY, data )\ | 288 | IND_Y( PAGE_PENALTY, data )\ |
289 | goto ptr##op;\ | 289 | goto ptr##op;\ |
290 | case op + 0x10: /* zp,X */\ | 290 | case op + 0x10: /* zp,X */\ |
291 | data = BYTE( data + x );\ | 291 | data = BYTE( data + x );\ |
292 | case op + 0x00: /* zp */\ | 292 | case op + 0x00: /* zp */\ |
293 | data = READ_LOW( data );\ | 293 | data = READ_LOW( data );\ |
294 | goto imm##op;\ | 294 | goto imm##op;\ |
295 | case op + 0x14: /* abs,Y */\ | 295 | case op + 0x14: /* abs,Y */\ |
296 | data += y;\ | 296 | data += y;\ |
297 | goto ind##op;\ | 297 | goto ind##op;\ |
298 | case op + 0x18: /* abs,X */\ | 298 | case op + 0x18: /* abs,X */\ |
299 | data += x;\ | 299 | data += x;\ |
300 | ind##op:\ | 300 | ind##op:\ |
301 | PAGE_PENALTY( data );\ | 301 | PAGE_PENALTY( data );\ |
302 | case op + 0x08: /* abs */\ | 302 | case op + 0x08: /* abs */\ |
303 | ADD_PAGE( data );\ | 303 | ADD_PAGE( data );\ |
304 | ptr##op:\ | 304 | ptr##op:\ |
305 | FLUSH_TIME();\ | 305 | FLUSH_TIME();\ |
306 | data = READ_MEM( data );\ | 306 | data = READ_MEM( data );\ |
307 | CACHE_TIME();\ | 307 | CACHE_TIME();\ |
308 | case op + 0x04: /* imm */\ | 308 | case op + 0x04: /* imm */\ |
309 | imm##op: | 309 | imm##op: |
310 | 310 | ||
311 | // TODO: more efficient way to handle negative branch that wraps PC around | 311 | // TODO: more efficient way to handle negative branch that wraps PC around |
312 | #define BRANCH( cond )\ | 312 | #define BRANCH( cond )\ |
313 | {\ | 313 | {\ |
314 | ++pc;\ | 314 | ++pc;\ |
315 | if ( !(cond) ) goto loop;\ | 315 | if ( !(cond) ) goto loop;\ |
316 | s_time++;\ | 316 | s_time++;\ |
317 | int offset = SBYTE( data );\ | 317 | int offset = SBYTE( data );\ |
318 | s_time += (BYTE(pc) + offset) >> 8 & 1;\ | 318 | s_time += (BYTE(pc) + offset) >> 8 & 1;\ |
319 | pc = WORD( pc + offset );\ | 319 | pc = WORD( pc + offset );\ |
320 | goto loop;\ | 320 | goto loop;\ |
321 | } | 321 | } |
322 | 322 | ||
323 | // Often-Used | 323 | // Often-Used |
324 | 324 | ||
325 | case 0xB5: // LDA zp,x | 325 | case 0xB5: // LDA zp,x |
326 | a = nz = READ_LOW( BYTE( data + x ) ); | 326 | a = nz = READ_LOW( BYTE( data + x ) ); |
327 | pc++; | 327 | pc++; |
328 | goto loop; | 328 | goto loop; |
329 | 329 | ||
330 | case 0xA5: // LDA zp | 330 | case 0xA5: // LDA zp |
331 | a = nz = READ_LOW( data ); | 331 | a = nz = READ_LOW( data ); |
332 | pc++; | 332 | pc++; |
333 | goto loop; | 333 | goto loop; |
334 | 334 | ||
335 | case 0xD0: // BNE | 335 | case 0xD0: // BNE |
336 | BRANCH( BYTE( nz ) ); | 336 | BRANCH( BYTE( nz ) ); |
337 | 337 | ||
338 | case 0x20: { // JSR | 338 | case 0x20: { // JSR |
339 | int temp = pc + 1; | 339 | int temp = pc + 1; |
340 | pc = GET_ADDR(); | 340 | pc = GET_ADDR(); |
341 | WRITE_STACK( SP( -1 ), temp >> 8 ); | 341 | WRITE_STACK( SP( -1 ), temp >> 8 ); |
342 | sp = SP( -2 ); | 342 | sp = SP( -2 ); |
343 | WRITE_STACK( sp, temp ); | 343 | WRITE_STACK( sp, temp ); |
344 | goto loop; | 344 | goto loop; |
345 | } | 345 | } |
346 | 346 | ||
347 | case 0x4C: // JMP abs | 347 | case 0x4C: // JMP abs |
348 | pc = GET_ADDR(); | 348 | pc = GET_ADDR(); |
349 | goto loop; | 349 | goto loop; |
350 | 350 | ||
351 | case 0xE8: // INX | 351 | case 0xE8: // INX |
352 | INC_DEC( x, 1 ) | 352 | INC_DEC( x, 1 ) |
353 | 353 | ||
354 | case 0x10: // BPL | 354 | case 0x10: // BPL |
355 | BRANCH( !IS_NEG ) | 355 | BRANCH( !IS_NEG ) |
356 | 356 | ||
357 | ARITH_ADDR_MODES( 0xC5 ) // CMP | 357 | ARITH_ADDR_MODES( 0xC5 ) // CMP |
358 | nz = a - data; | 358 | nz = a - data; |
359 | pc++; | 359 | pc++; |
360 | c = ~nz; | 360 | c = ~nz; |
361 | nz &= 0xFF; | 361 | nz &= 0xFF; |
362 | goto loop; | 362 | goto loop; |
363 | 363 | ||
364 | case 0x30: // BMI | 364 | case 0x30: // BMI |
365 | BRANCH( IS_NEG ) | 365 | BRANCH( IS_NEG ) |
366 | 366 | ||
367 | case 0xF0: // BEQ | 367 | case 0xF0: // BEQ |
368 | BRANCH( !BYTE( nz ) ); | 368 | BRANCH( !BYTE( nz ) ); |
369 | 369 | ||
370 | case 0x95: // STA zp,x | 370 | case 0x95: // STA zp,x |
371 | data = BYTE( data + x ); | 371 | data = BYTE( data + x ); |
372 | case 0x85: // STA zp | 372 | case 0x85: // STA zp |
373 | pc++; | 373 | pc++; |
374 | WRITE_LOW( data, a ); | 374 | WRITE_LOW( data, a ); |
375 | goto loop; | 375 | goto loop; |
376 | 376 | ||
377 | case 0xC8: // INY | 377 | case 0xC8: // INY |
378 | INC_DEC( y, 1 ) | 378 | INC_DEC( y, 1 ) |
379 | 379 | ||
380 | case 0xA8: // TAY | 380 | case 0xA8: // TAY |
381 | y = a; | 381 | y = a; |
382 | nz = a; | 382 | nz = a; |
383 | goto loop; | 383 | goto loop; |
384 | 384 | ||
385 | case 0x98: // TYA | 385 | case 0x98: // TYA |
386 | a = y; | 386 | a = y; |
387 | nz = y; | 387 | nz = y; |
388 | goto loop; | 388 | goto loop; |
389 | 389 | ||
390 | case 0xAD:{// LDA abs | 390 | case 0xAD:{// LDA abs |
391 | int addr = GET_ADDR(); | 391 | int addr = GET_ADDR(); |
392 | pc += 2; | 392 | pc += 2; |
393 | READ_PPU( addr, a = nz ); | 393 | READ_PPU( addr, a = nz ); |
394 | goto loop; | 394 | goto loop; |
395 | } | 395 | } |
396 | 396 | ||
397 | case 0x60: // RTS | 397 | case 0x60: // RTS |
398 | pc = 1 + READ_STACK( sp ); | 398 | pc = 1 + READ_STACK( sp ); |
399 | pc += 0x100 * READ_STACK( SP( 1 ) ); | 399 | pc += 0x100 * READ_STACK( SP( 1 ) ); |
400 | sp = SP( 2 ); | 400 | sp = SP( 2 ); |
401 | goto loop; | 401 | goto loop; |
402 | 402 | ||
403 | { | 403 | { |
404 | int addr; | 404 | int addr; |
405 | 405 | ||
406 | case 0x8D: // STA abs | 406 | case 0x8D: // STA abs |
407 | addr = GET_ADDR(); | 407 | addr = GET_ADDR(); |
408 | pc += 2; | 408 | pc += 2; |
409 | if ( CAN_WRITE_FAST( addr ) ) | 409 | if ( CAN_WRITE_FAST( addr ) ) |
410 | { | 410 | { |
411 | WRITE_FAST( addr, a ); | 411 | WRITE_FAST( addr, a ); |
412 | goto loop; | 412 | goto loop; |
413 | } | 413 | } |
414 | sta_ptr: | 414 | sta_ptr: |
415 | FLUSH_TIME(); | 415 | FLUSH_TIME(); |
416 | WRITE_MEM( addr, a ); | 416 | WRITE_MEM( addr, a ); |
417 | CACHE_TIME(); | 417 | CACHE_TIME(); |
418 | goto loop; | 418 | goto loop; |
419 | 419 | ||
420 | case 0x99: // STA abs,Y | 420 | case 0x99: // STA abs,Y |
421 | addr = y + GET_ADDR(); | 421 | addr = y + GET_ADDR(); |
422 | pc += 2; | 422 | pc += 2; |
423 | if ( CAN_WRITE_FAST( addr ) ) | 423 | if ( CAN_WRITE_FAST( addr ) ) |
424 | { | 424 | { |
425 | WRITE_FAST( addr, a ); | 425 | WRITE_FAST( addr, a ); |
426 | goto loop; | 426 | goto loop; |
427 | } | 427 | } |
428 | goto sta_abs_x; | 428 | goto sta_abs_x; |
429 | 429 | ||
430 | case 0x9D: // STA abs,X (slightly more common than STA abs) | 430 | case 0x9D: // STA abs,X (slightly more common than STA abs) |
431 | addr = x + GET_ADDR(); | 431 | addr = x + GET_ADDR(); |
432 | pc += 2; | 432 | pc += 2; |
433 | if ( CAN_WRITE_FAST( addr ) ) | 433 | if ( CAN_WRITE_FAST( addr ) ) |
434 | { | 434 | { |
435 | WRITE_FAST( addr, a ); | 435 | WRITE_FAST( addr, a ); |
436 | goto loop; | 436 | goto loop; |
437 | } | 437 | } |
438 | DUMMY_READ( addr, x ); | 438 | DUMMY_READ( addr, x ); |
439 | sta_abs_x: | 439 | sta_abs_x: |
440 | FLUSH_TIME(); | 440 | FLUSH_TIME(); |
441 | WRITE_MEM( addr, a ); | 441 | WRITE_MEM( addr, a ); |
442 | CACHE_TIME(); | 442 | CACHE_TIME(); |
443 | goto loop; | 443 | goto loop; |
444 | 444 | ||
445 | case 0x91: // STA (ind),Y | 445 | case 0x91: // STA (ind),Y |
446 | #define NO_PAGE_PENALTY( lsb ) | 446 | #define NO_PAGE_PENALTY( lsb ) |
447 | IND_Y( NO_PAGE_PENALTY, addr ) | 447 | IND_Y( NO_PAGE_PENALTY, addr ) |
448 | pc++; | 448 | pc++; |
449 | DUMMY_READ( addr, y ); | 449 | DUMMY_READ( addr, y ); |
450 | goto sta_ptr; | 450 | goto sta_ptr; |
451 | 451 | ||
452 | case 0x81: // STA (ind,X) | 452 | case 0x81: // STA (ind,X) |
453 | IND_X( addr ) | 453 | IND_X( addr ) |
454 | pc++; | 454 | pc++; |
455 | goto sta_ptr; | 455 | goto sta_ptr; |
456 | 456 | ||
457 | } | 457 | } |
458 | 458 | ||
459 | case 0xA9: // LDA #imm | 459 | case 0xA9: // LDA #imm |
460 | pc++; | 460 | pc++; |
461 | a = data; | 461 | a = data; |
462 | nz = data; | 462 | nz = data; |
463 | goto loop; | 463 | goto loop; |
464 | 464 | ||
465 | // common read instructions | 465 | // common read instructions |
466 | { | 466 | { |
467 | int addr; | 467 | int addr; |
468 | 468 | ||
469 | case 0xA1: // LDA (ind,X) | 469 | case 0xA1: // LDA (ind,X) |
470 | IND_X( addr ) | 470 | IND_X( addr ) |
471 | pc++; | 471 | pc++; |
472 | goto a_nz_read_addr; | 472 | goto a_nz_read_addr; |
473 | 473 | ||
474 | case 0xB1:// LDA (ind),Y | 474 | case 0xB1:// LDA (ind),Y |
475 | addr = READ_LOW( data ) + y; | 475 | addr = READ_LOW( data ) + y; |
476 | PAGE_PENALTY( addr ); | 476 | PAGE_PENALTY( addr ); |
477 | addr += 0x100 * READ_LOW( BYTE( data + 1 ) ); | 477 | addr += 0x100 * READ_LOW( BYTE( data + 1 ) ); |
478 | pc++; | 478 | pc++; |
479 | READ_FAST( addr, a = nz ); | 479 | READ_FAST( addr, a = nz ); |
480 | if ( CAN_READ_FAST( addr ) ) | 480 | if ( CAN_READ_FAST( addr ) ) |
481 | goto loop; | 481 | goto loop; |
482 | DUMMY_READ( addr, y ); | 482 | DUMMY_READ( addr, y ); |
483 | goto a_nz_read_addr; | 483 | goto a_nz_read_addr; |
484 | 484 | ||
485 | case 0xB9: // LDA abs,Y | 485 | case 0xB9: // LDA abs,Y |
486 | PAGE_PENALTY( data + y ); | 486 | PAGE_PENALTY( data + y ); |
487 | addr = GET_ADDR() + y; | 487 | addr = GET_ADDR() + y; |
488 | pc += 2; | 488 | pc += 2; |
489 | READ_FAST( addr, a = nz ); | 489 | READ_FAST( addr, a = nz ); |
490 | if ( CAN_READ_FAST( addr ) ) | 490 | if ( CAN_READ_FAST( addr ) ) |
491 | goto loop; | 491 | goto loop; |
492 | goto a_nz_read_addr; | 492 | goto a_nz_read_addr; |
493 | 493 | ||
494 | case 0xBD: // LDA abs,X | 494 | case 0xBD: // LDA abs,X |
495 | PAGE_PENALTY( data + x ); | 495 | PAGE_PENALTY( data + x ); |
496 | addr = GET_ADDR() + x; | 496 | addr = GET_ADDR() + x; |
497 | pc += 2; | 497 | pc += 2; |
498 | READ_FAST( addr, a = nz ); | 498 | READ_FAST( addr, a = nz ); |
499 | if ( CAN_READ_FAST( addr ) ) | 499 | if ( CAN_READ_FAST( addr ) ) |
500 | goto loop; | 500 | goto loop; |
501 | DUMMY_READ( addr, x ); | 501 | DUMMY_READ( addr, x ); |
502 | a_nz_read_addr: | 502 | a_nz_read_addr: |
503 | FLUSH_TIME(); | 503 | FLUSH_TIME(); |
504 | a = nz = READ_MEM( addr ); | 504 | a = nz = READ_MEM( addr ); |
505 | CACHE_TIME(); | 505 | CACHE_TIME(); |
506 | goto loop; | 506 | goto loop; |
507 | 507 | ||
508 | } | 508 | } |
509 | 509 | ||
510 | // Branch | 510 | // Branch |
511 | 511 | ||
512 | case 0x50: // BVC | 512 | case 0x50: // BVC |
513 | BRANCH( !(flags & v40) ) | 513 | BRANCH( !(flags & v40) ) |
514 | 514 | ||
515 | case 0x70: // BVS | 515 | case 0x70: // BVS |
516 | BRANCH( flags & v40 ) | 516 | BRANCH( flags & v40 ) |
517 | 517 | ||
518 | case 0xB0: // BCS | 518 | case 0xB0: // BCS |
519 | BRANCH( c & 0x100 ) | 519 | BRANCH( c & 0x100 ) |
520 | 520 | ||
521 | case 0x90: // BCC | 521 | case 0x90: // BCC |
522 | BRANCH( !(c & 0x100) ) | 522 | BRANCH( !(c & 0x100) ) |
523 | 523 | ||
524 | // Load/store | 524 | // Load/store |
525 | 525 | ||
526 | case 0x94: // STY zp,x | 526 | case 0x94: // STY zp,x |
527 | data = BYTE( data + x ); | 527 | data = BYTE( data + x ); |
528 | case 0x84: // STY zp | 528 | case 0x84: // STY zp |
529 | pc++; | 529 | pc++; |
530 | WRITE_LOW( data, y ); | 530 | WRITE_LOW( data, y ); |
531 | goto loop; | 531 | goto loop; |
532 | 532 | ||
533 | case 0x96: // STX zp,y | 533 | case 0x96: // STX zp,y |
534 | data = BYTE( data + y ); | 534 | data = BYTE( data + y ); |
535 | case 0x86: // STX zp | 535 | case 0x86: // STX zp |
536 | pc++; | 536 | pc++; |
537 | WRITE_LOW( data, x ); | 537 | WRITE_LOW( data, x ); |
538 | goto loop; | 538 | goto loop; |
539 | 539 | ||
540 | case 0xB6: // LDX zp,y | 540 | case 0xB6: // LDX zp,y |
541 | data = BYTE( data + y ); | 541 | data = BYTE( data + y ); |
542 | case 0xA6: // LDX zp | 542 | case 0xA6: // LDX zp |
543 | data = READ_LOW( data ); | 543 | data = READ_LOW( data ); |
544 | case 0xA2: // LDX #imm | 544 | case 0xA2: // LDX #imm |
545 | pc++; | 545 | pc++; |
546 | x = data; | 546 | x = data; |
547 | nz = data; | 547 | nz = data; |
548 | goto loop; | 548 | goto loop; |
549 | 549 | ||
550 | case 0xB4: // LDY zp,x | 550 | case 0xB4: // LDY zp,x |
551 | data = BYTE( data + x ); | 551 | data = BYTE( data + x ); |
552 | case 0xA4: // LDY zp | 552 | case 0xA4: // LDY zp |
553 | data = READ_LOW( data ); | 553 | data = READ_LOW( data ); |
554 | case 0xA0: // LDY #imm | 554 | case 0xA0: // LDY #imm |
555 | pc++; | 555 | pc++; |
556 | y = data; | 556 | y = data; |
557 | nz = data; | 557 | nz = data; |
558 | goto loop; | 558 | goto loop; |
559 | 559 | ||
560 | case 0xBC: // LDY abs,X | 560 | case 0xBC: // LDY abs,X |
561 | data += x; | 561 | data += x; |
562 | PAGE_PENALTY( data ); | 562 | PAGE_PENALTY( data ); |
563 | case 0xAC:{// LDY abs | 563 | case 0xAC:{// LDY abs |
564 | int addr = data + 0x100 * GET_MSB(); | 564 | int addr = data + 0x100 * GET_MSB(); |
565 | pc += 2; | 565 | pc += 2; |
566 | FLUSH_TIME(); | 566 | FLUSH_TIME(); |
567 | y = nz = READ_MEM( addr ); | 567 | y = nz = READ_MEM( addr ); |
568 | CACHE_TIME(); | 568 | CACHE_TIME(); |
569 | goto loop; | 569 | goto loop; |
570 | } | 570 | } |
571 | 571 | ||
572 | case 0xBE: // LDX abs,y | 572 | case 0xBE: // LDX abs,y |
573 | data += y; | 573 | data += y; |
574 | PAGE_PENALTY( data ); | 574 | PAGE_PENALTY( data ); |
575 | case 0xAE:{// LDX abs | 575 | case 0xAE:{// LDX abs |
576 | int addr = data + 0x100 * GET_MSB(); | 576 | int addr = data + 0x100 * GET_MSB(); |
577 | pc += 2; | 577 | pc += 2; |
578 | FLUSH_TIME(); | 578 | FLUSH_TIME(); |
579 | x = nz = READ_MEM( addr ); | 579 | x = nz = READ_MEM( addr ); |
580 | CACHE_TIME(); | 580 | CACHE_TIME(); |
581 | goto loop; | 581 | goto loop; |
582 | } | 582 | } |
583 | 583 | ||
584 | { | 584 | { |
585 | int temp; | 585 | int temp; |
586 | case 0x8C: // STY abs | 586 | case 0x8C: // STY abs |
587 | temp = y; | 587 | temp = y; |
588 | goto store_abs; | 588 | goto store_abs; |
589 | 589 | ||
590 | case 0x8E: // STX abs | 590 | case 0x8E: // STX abs |
591 | temp = x; | 591 | temp = x; |
592 | store_abs: | 592 | store_abs: |
593 | { | 593 | { |
594 | int addr = GET_ADDR(); | 594 | int addr = GET_ADDR(); |
595 | pc += 2; | 595 | pc += 2; |
596 | if ( CAN_WRITE_FAST( addr ) ) | 596 | if ( CAN_WRITE_FAST( addr ) ) |
597 | { | 597 | { |
598 | WRITE_FAST( addr, temp ); | 598 | WRITE_FAST( addr, temp ); |
599 | goto loop; | 599 | goto loop; |
600 | } | 600 | } |
601 | FLUSH_TIME(); | 601 | FLUSH_TIME(); |
602 | WRITE_MEM( addr, temp ); | 602 | WRITE_MEM( addr, temp ); |
603 | CACHE_TIME(); | 603 | CACHE_TIME(); |
604 | goto loop; | 604 | goto loop; |
605 | } | 605 | } |
606 | } | 606 | } |
607 | 607 | ||
608 | // Compare | 608 | // Compare |
609 | 609 | ||
610 | case 0xEC: {// CPX abs | 610 | case 0xEC: {// CPX abs |
611 | int addr = GET_ADDR(); | 611 | int addr = GET_ADDR(); |
612 | pc++; | 612 | pc++; |
613 | FLUSH_TIME(); | 613 | FLUSH_TIME(); |
614 | data = READ_MEM( addr ); | 614 | data = READ_MEM( addr ); |
615 | CACHE_TIME(); | 615 | CACHE_TIME(); |
616 | goto cpx_data; | 616 | goto cpx_data; |
617 | } | 617 | } |
618 | 618 | ||
619 | case 0xE4: // CPX zp | 619 | case 0xE4: // CPX zp |
620 | data = READ_LOW( data ); | 620 | data = READ_LOW( data ); |
621 | case 0xE0: // CPX #imm | 621 | case 0xE0: // CPX #imm |
622 | cpx_data: | 622 | cpx_data: |
623 | nz = x - data; | 623 | nz = x - data; |
624 | pc++; | 624 | pc++; |
625 | c = ~nz; | 625 | c = ~nz; |
626 | nz &= 0xFF; | 626 | nz &= 0xFF; |
627 | goto loop; | 627 | goto loop; |
628 | 628 | ||
629 | case 0xCC:{// CPY abs | 629 | case 0xCC:{// CPY abs |
630 | int addr = GET_ADDR(); | 630 | int addr = GET_ADDR(); |
631 | pc++; | 631 | pc++; |
632 | FLUSH_TIME(); | 632 | FLUSH_TIME(); |
633 | data = READ_MEM( addr ); | 633 | data = READ_MEM( addr ); |
634 | CACHE_TIME(); | 634 | CACHE_TIME(); |
635 | goto cpy_data; | 635 | goto cpy_data; |
636 | } | 636 | } |
637 | 637 | ||
638 | case 0xC4: // CPY zp | 638 | case 0xC4: // CPY zp |
639 | data = READ_LOW( data ); | 639 | data = READ_LOW( data ); |
640 | case 0xC0: // CPY #imm | 640 | case 0xC0: // CPY #imm |
641 | cpy_data: | 641 | cpy_data: |
642 | nz = y - data; | 642 | nz = y - data; |
643 | pc++; | 643 | pc++; |
644 | c = ~nz; | 644 | c = ~nz; |
645 | nz &= 0xFF; | 645 | nz &= 0xFF; |
646 | goto loop; | 646 | goto loop; |
647 | 647 | ||
648 | // Logical | 648 | // Logical |
649 | 649 | ||
650 | ARITH_ADDR_MODES( 0x25 ) // AND | 650 | ARITH_ADDR_MODES( 0x25 ) // AND |
651 | nz = (a &= data); | 651 | nz = (a &= data); |
652 | pc++; | 652 | pc++; |
653 | goto loop; | 653 | goto loop; |
654 | 654 | ||
655 | ARITH_ADDR_MODES( 0x45 ) // EOR | 655 | ARITH_ADDR_MODES( 0x45 ) // EOR |
656 | nz = (a ^= data); | 656 | nz = (a ^= data); |
657 | pc++; | 657 | pc++; |
658 | goto loop; | 658 | goto loop; |
659 | 659 | ||
660 | ARITH_ADDR_MODES( 0x05 ) // ORA | 660 | ARITH_ADDR_MODES( 0x05 ) // ORA |
661 | nz = (a |= data); | 661 | nz = (a |= data); |
662 | pc++; | 662 | pc++; |
663 | goto loop; | 663 | goto loop; |
664 | 664 | ||
665 | case 0x2C:{// BIT abs | 665 | case 0x2C:{// BIT abs |
666 | int addr = GET_ADDR(); | 666 | int addr = GET_ADDR(); |
667 | pc += 2; | 667 | pc += 2; |
668 | READ_PPU( addr, nz ); | 668 | READ_PPU( addr, nz ); |
669 | flags = (flags & ~v40) + (nz & v40); | 669 | flags = (flags & ~v40) + (nz & v40); |
670 | if ( a & nz ) | 670 | if ( a & nz ) |
671 | goto loop; | 671 | goto loop; |
672 | nz <<= 8; // result must be zero, even if N bit is set | 672 | nz <<= 8; // result must be zero, even if N bit is set |
673 | goto loop; | 673 | goto loop; |
674 | } | 674 | } |
675 | 675 | ||
676 | case 0x24: // BIT zp | 676 | case 0x24: // BIT zp |
677 | nz = READ_LOW( data ); | 677 | nz = READ_LOW( data ); |
678 | pc++; | 678 | pc++; |
679 | flags = (flags & ~v40) + (nz & v40); | 679 | flags = (flags & ~v40) + (nz & v40); |
680 | if ( a & nz ) | 680 | if ( a & nz ) |
681 | goto loop; // Z should be clear, and nz must be non-zero if nz & a is | 681 | goto loop; // Z should be clear, and nz must be non-zero if nz & a is |
682 | nz <<= 8; // set Z flag without affecting N flag | 682 | nz <<= 8; // set Z flag without affecting N flag |
683 | goto loop; | 683 | goto loop; |
684 | 684 | ||
685 | // Add/subtract | 685 | // Add/subtract |
686 | 686 | ||
687 | ARITH_ADDR_MODES( 0xE5 ) // SBC | 687 | ARITH_ADDR_MODES( 0xE5 ) // SBC |
688 | case 0xEB: // unofficial equivalent | 688 | case 0xEB: // unofficial equivalent |
689 | data ^= 0xFF; | 689 | data ^= 0xFF; |
690 | goto adc_imm; | 690 | goto adc_imm; |
691 | 691 | ||
692 | ARITH_ADDR_MODES( 0x65 ) // ADC | 692 | ARITH_ADDR_MODES( 0x65 ) // ADC |
693 | adc_imm: { | 693 | adc_imm: { |
694 | int carry = c >> 8 & 1; | 694 | int carry = c >> 8 & 1; |
695 | int ov = (a ^ 0x80) + carry + SBYTE( data ); | 695 | int ov = (a ^ 0x80) + carry + SBYTE( data ); |
696 | flags = (flags & ~v40) + (ov >> 2 & v40); | 696 | flags = (flags & ~v40) + (ov >> 2 & v40); |
697 | c = nz = a + data + carry; | 697 | c = nz = a + data + carry; |
698 | pc++; | 698 | pc++; |
699 | a = BYTE( nz ); | 699 | a = BYTE( nz ); |
700 | goto loop; | 700 | goto loop; |
701 | } | 701 | } |
702 | 702 | ||
703 | // Shift/rotate | 703 | // Shift/rotate |
704 | 704 | ||
705 | case 0x4A: // LSR A | 705 | case 0x4A: // LSR A |
706 | c = 0; | 706 | c = 0; |
707 | case 0x6A: // ROR A | 707 | case 0x6A: // ROR A |
708 | nz = c >> 1 & 0x80; | 708 | nz = c >> 1 & 0x80; |
709 | c = a << 8; | 709 | c = a << 8; |
710 | nz += a >> 1; | 710 | nz += a >> 1; |
711 | a = nz; | 711 | a = nz; |
712 | goto loop; | 712 | goto loop; |
713 | 713 | ||
714 | case 0x0A: // ASL A | 714 | case 0x0A: // ASL A |
715 | nz = a << 1; | 715 | nz = a << 1; |
716 | c = nz; | 716 | c = nz; |
717 | a = BYTE( nz ); | 717 | a = BYTE( nz ); |
718 | goto loop; | 718 | goto loop; |
719 | 719 | ||
720 | case 0x2A: { // ROL A | 720 | case 0x2A: { // ROL A |
721 | nz = a << 1; | 721 | nz = a << 1; |
722 | int temp = c >> 8 & 1; | 722 | int temp = c >> 8 & 1; |
723 | c = nz; | 723 | c = nz; |
724 | nz += temp; | 724 | nz += temp; |
725 | a = BYTE( nz ); | 725 | a = BYTE( nz ); |
726 | goto loop; | 726 | goto loop; |
727 | } | 727 | } |
728 | 728 | ||
729 | case 0x5E: // LSR abs,X | 729 | case 0x5E: // LSR abs,X |
730 | data += x; | 730 | data += x; |
731 | case 0x4E: // LSR abs | 731 | case 0x4E: // LSR abs |
732 | c = 0; | 732 | c = 0; |
733 | case 0x6E: // ROR abs | 733 | case 0x6E: // ROR abs |
734 | ror_abs: { | 734 | ror_abs: { |
735 | ADD_PAGE( data ); | 735 | ADD_PAGE( data ); |
736 | FLUSH_TIME(); | 736 | FLUSH_TIME(); |
737 | int temp = READ_MEM( data ); | 737 | int temp = READ_MEM( data ); |
738 | nz = (c >> 1 & 0x80) + (temp >> 1); | 738 | nz = (c >> 1 & 0x80) + (temp >> 1); |
739 | c = temp << 8; | 739 | c = temp << 8; |
740 | goto rotate_common; | 740 | goto rotate_common; |
741 | } | 741 | } |
742 | 742 | ||
743 | case 0x3E: // ROL abs,X | 743 | case 0x3E: // ROL abs,X |
744 | data += x; | 744 | data += x; |
745 | goto rol_abs; | 745 | goto rol_abs; |
746 | 746 | ||
747 | case 0x1E: // ASL abs,X | 747 | case 0x1E: // ASL abs,X |
748 | data += x; | 748 | data += x; |
749 | case 0x0E: // ASL abs | 749 | case 0x0E: // ASL abs |
750 | c = 0; | 750 | c = 0; |
751 | case 0x2E: // ROL abs | 751 | case 0x2E: // ROL abs |
752 | rol_abs: | 752 | rol_abs: |
753 | ADD_PAGE( data ); | 753 | ADD_PAGE( data ); |
754 | nz = c >> 8 & 1; | 754 | nz = c >> 8 & 1; |
755 | FLUSH_TIME(); | 755 | FLUSH_TIME(); |
756 | nz += (c = READ_MEM( data ) << 1); | 756 | nz += (c = READ_MEM( data ) << 1); |
757 | rotate_common: | 757 | rotate_common: |
758 | pc++; | 758 | pc++; |
759 | WRITE_MEM( data, BYTE( nz ) ); | 759 | WRITE_MEM( data, BYTE( nz ) ); |
760 | CACHE_TIME(); | 760 | CACHE_TIME(); |
761 | goto loop; | 761 | goto loop; |
762 | 762 | ||
763 | case 0x7E: // ROR abs,X | 763 | case 0x7E: // ROR abs,X |
764 | data += x; | 764 | data += x; |
765 | goto ror_abs; | 765 | goto ror_abs; |
766 | 766 | ||
767 | case 0x76: // ROR zp,x | 767 | case 0x76: // ROR zp,x |
768 | data = BYTE( data + x ); | 768 | data = BYTE( data + x ); |
769 | goto ror_zp; | 769 | goto ror_zp; |
770 | 770 | ||
771 | case 0x56: // LSR zp,x | 771 | case 0x56: // LSR zp,x |
772 | data = BYTE( data + x ); | 772 | data = BYTE( data + x ); |
773 | case 0x46: // LSR zp | 773 | case 0x46: // LSR zp |
774 | c = 0; | 774 | c = 0; |
775 | case 0x66: // ROR zp | 775 | case 0x66: // ROR zp |
776 | ror_zp: { | 776 | ror_zp: { |
777 | int temp = READ_LOW( data ); | 777 | int temp = READ_LOW( data ); |
778 | nz = (c >> 1 & 0x80) + (temp >> 1); | 778 | nz = (c >> 1 & 0x80) + (temp >> 1); |
779 | c = temp << 8; | 779 | c = temp << 8; |
780 | goto write_nz_zp; | 780 | goto write_nz_zp; |
781 | } | 781 | } |
782 | 782 | ||
783 | case 0x36: // ROL zp,x | 783 | case 0x36: // ROL zp,x |
784 | data = BYTE( data + x ); | 784 | data = BYTE( data + x ); |
785 | goto rol_zp; | 785 | goto rol_zp; |
786 | 786 | ||
787 | case 0x16: // ASL zp,x | 787 | case 0x16: // ASL zp,x |
788 | data = BYTE( data + x ); | 788 | data = BYTE( data + x ); |
789 | case 0x06: // ASL zp | 789 | case 0x06: // ASL zp |
790 | c = 0; | 790 | c = 0; |
791 | case 0x26: // ROL zp | 791 | case 0x26: // ROL zp |
792 | rol_zp: | 792 | rol_zp: |
793 | nz = c >> 8 & 1; | 793 | nz = c >> 8 & 1; |
794 | nz += (c = READ_LOW( data ) << 1); | 794 | nz += (c = READ_LOW( data ) << 1); |
795 | goto write_nz_zp; | 795 | goto write_nz_zp; |
796 | 796 | ||
797 | // Increment/decrement | 797 | // Increment/decrement |
798 | 798 | ||
799 | case 0xCA: // DEX | 799 | case 0xCA: // DEX |
800 | INC_DEC( x, -1 ) | 800 | INC_DEC( x, -1 ) |
801 | 801 | ||
802 | case 0x88: // DEY | 802 | case 0x88: // DEY |
803 | INC_DEC( y, -1 ) | 803 | INC_DEC( y, -1 ) |
804 | 804 | ||
805 | case 0xF6: // INC zp,x | 805 | case 0xF6: // INC zp,x |
806 | data = BYTE( data + x ); | 806 | data = BYTE( data + x ); |
807 | case 0xE6: // INC zp | 807 | case 0xE6: // INC zp |
808 | nz = 1; | 808 | nz = 1; |
809 | goto add_nz_zp; | 809 | goto add_nz_zp; |
810 | 810 | ||
811 | case 0xD6: // DEC zp,x | 811 | case 0xD6: // DEC zp,x |
812 | data = BYTE( data + x ); | 812 | data = BYTE( data + x ); |
813 | case 0xC6: // DEC zp | 813 | case 0xC6: // DEC zp |
814 | nz = -1; | 814 | nz = -1; |
815 | add_nz_zp: | 815 | add_nz_zp: |
816 | nz += READ_LOW( data ); | 816 | nz += READ_LOW( data ); |
817 | write_nz_zp: | 817 | write_nz_zp: |
818 | pc++; | 818 | pc++; |
819 | WRITE_LOW( data, nz ); | 819 | WRITE_LOW( data, nz ); |
820 | goto loop; | 820 | goto loop; |
821 | 821 | ||
822 | case 0xFE: // INC abs,x | 822 | case 0xFE: // INC abs,x |
823 | data = x + GET_ADDR(); | 823 | data = x + GET_ADDR(); |
824 | goto inc_ptr; | 824 | goto inc_ptr; |
825 | 825 | ||
826 | case 0xEE: // INC abs | 826 | case 0xEE: // INC abs |
827 | data = GET_ADDR(); | 827 | data = GET_ADDR(); |
828 | inc_ptr: | 828 | inc_ptr: |
829 | nz = 1; | 829 | nz = 1; |
830 | goto inc_common; | 830 | goto inc_common; |
831 | 831 | ||
832 | case 0xDE: // DEC abs,x | 832 | case 0xDE: // DEC abs,x |
833 | data = x + GET_ADDR(); | 833 | data = x + GET_ADDR(); |
834 | goto dec_ptr; | 834 | goto dec_ptr; |
835 | 835 | ||
836 | case 0xCE: // DEC abs | 836 | case 0xCE: // DEC abs |
837 | data = GET_ADDR(); | 837 | data = GET_ADDR(); |
838 | dec_ptr: | 838 | dec_ptr: |
839 | nz = -1; | 839 | nz = -1; |
840 | inc_common: | 840 | inc_common: |
841 | FLUSH_TIME(); | 841 | FLUSH_TIME(); |
842 | pc += 2; | 842 | pc += 2; |
843 | nz += READ_MEM( data ); | 843 | nz += READ_MEM( data ); |
844 | WRITE_MEM( data, BYTE( nz ) ); | 844 | WRITE_MEM( data, BYTE( nz ) ); |
845 | CACHE_TIME(); | 845 | CACHE_TIME(); |
846 | goto loop; | 846 | goto loop; |
847 | 847 | ||
848 | // Transfer | 848 | // Transfer |
849 | 849 | ||
850 | case 0xAA: // TAX | 850 | case 0xAA: // TAX |
851 | x = nz = a; | 851 | x = nz = a; |
852 | goto loop; | 852 | goto loop; |
853 | 853 | ||
854 | case 0x8A: // TXA | 854 | case 0x8A: // TXA |
855 | a = nz = x; | 855 | a = nz = x; |
856 | goto loop; | 856 | goto loop; |
857 | 857 | ||
858 | case 0x9A: // TXS | 858 | case 0x9A: // TXS |
859 | SET_SP( x ); // verified (no flag change) | 859 | SET_SP( x ); // verified (no flag change) |
860 | goto loop; | 860 | goto loop; |
861 | 861 | ||
862 | case 0xBA: // TSX | 862 | case 0xBA: // TSX |
863 | x = nz = GET_SP(); | 863 | x = nz = GET_SP(); |
864 | goto loop; | 864 | goto loop; |
865 | 865 | ||
866 | // Stack | 866 | // Stack |
867 | 867 | ||
868 | case 0x48: // PHA | 868 | case 0x48: // PHA |
869 | sp = SP( -1 ); | 869 | sp = SP( -1 ); |
870 | WRITE_STACK( sp, a ); | 870 | WRITE_STACK( sp, a ); |
871 | goto loop; | 871 | goto loop; |
872 | 872 | ||
873 | case 0x68: // PLA | 873 | case 0x68: // PLA |
874 | a = nz = READ_STACK( sp ); | 874 | a = nz = READ_STACK( sp ); |
875 | sp = SP( 1 ); | 875 | sp = SP( 1 ); |
876 | goto loop; | 876 | goto loop; |
877 | 877 | ||
878 | case 0x40:{// RTI | 878 | case 0x40:{// RTI |
879 | pc = READ_STACK( SP( 1 ) ); | 879 | pc = READ_STACK( SP( 1 ) ); |
880 | pc += READ_STACK( SP( 2 ) ) * 0x100; | 880 | pc += READ_STACK( SP( 2 ) ) * 0x100; |
881 | int temp = READ_STACK( sp ); | 881 | int temp = READ_STACK( sp ); |
882 | sp = SP( 3 ); | 882 | sp = SP( 3 ); |
883 | data = flags; | 883 | data = flags; |
884 | SET_FLAGS( temp ); | 884 | SET_FLAGS( temp ); |
885 | cpu->r.flags = flags; // update externally-visible I flag | 885 | cpu->r.flags = flags; // update externally-visible I flag |
886 | int delta = s.base - cpu->irq_time; | 886 | int delta = s.base - cpu->irq_time; |
887 | if ( delta <= 0 ) goto loop; // end_time < irq_time | 887 | if ( delta <= 0 ) goto loop; // end_time < irq_time |
888 | if ( flags & i04 ) goto loop; | 888 | if ( flags & i04 ) goto loop; |
889 | s_time += delta; | 889 | s_time += delta; |
890 | s.base = cpu->irq_time; | 890 | s.base = cpu->irq_time; |
891 | goto loop; | 891 | goto loop; |
892 | } | 892 | } |
893 | 893 | ||
894 | case 0x28:{// PLP | 894 | case 0x28:{// PLP |
895 | int temp = READ_STACK( sp ); | 895 | int temp = READ_STACK( sp ); |
896 | sp = SP( 1 ); | 896 | sp = SP( 1 ); |
897 | int changed = flags ^ temp; | 897 | int changed = flags ^ temp; |
898 | SET_FLAGS( temp ); | 898 | SET_FLAGS( temp ); |
899 | if ( !(changed & i04) ) | 899 | if ( !(changed & i04) ) |
900 | goto loop; // I flag didn't change | 900 | goto loop; // I flag didn't change |
901 | if ( flags & i04 ) | 901 | if ( flags & i04 ) |
902 | goto handle_sei; | 902 | goto handle_sei; |
903 | goto handle_cli; | 903 | goto handle_cli; |
904 | } | 904 | } |
905 | 905 | ||
906 | case 0x08:{// PHP | 906 | case 0x08:{// PHP |
907 | int temp; | 907 | int temp; |
908 | GET_FLAGS( temp ); | 908 | GET_FLAGS( temp ); |
909 | sp = SP( -1 ); | 909 | sp = SP( -1 ); |
910 | WRITE_STACK( sp, temp | (b10 | r20) ); | 910 | WRITE_STACK( sp, temp | (b10 | r20) ); |
911 | goto loop; | 911 | goto loop; |
912 | } | 912 | } |
913 | 913 | ||
914 | case 0x6C:{// JMP (ind) | 914 | case 0x6C:{// JMP (ind) |
915 | data = GET_ADDR(); | 915 | data = GET_ADDR(); |
916 | byte const* page = CODE_PAGE( data ); | 916 | byte const* page = CODE_PAGE( data ); |
917 | pc = page [CODE_OFFSET( data )]; | 917 | pc = page [CODE_OFFSET( data )]; |
918 | data = (data & 0xFF00) + ((data + 1) & 0xFF); | 918 | data = (data & 0xFF00) + ((data + 1) & 0xFF); |
919 | pc += page [CODE_OFFSET( data )] * 0x100; | 919 | pc += page [CODE_OFFSET( data )] * 0x100; |
920 | goto loop; | 920 | goto loop; |
921 | } | 921 | } |
922 | 922 | ||
923 | case 0x00: // BRK | 923 | case 0x00: // BRK |
924 | goto handle_brk; | 924 | goto handle_brk; |
925 | 925 | ||
926 | // Flags | 926 | // Flags |
927 | 927 | ||
928 | case 0x38: // SEC | 928 | case 0x38: // SEC |
929 | c = 0x100; | 929 | c = 0x100; |
930 | goto loop; | 930 | goto loop; |
931 | 931 | ||
932 | case 0x18: // CLC | 932 | case 0x18: // CLC |
933 | c = 0; | 933 | c = 0; |
934 | goto loop; | 934 | goto loop; |
935 | 935 | ||
936 | case 0xB8: // CLV | 936 | case 0xB8: // CLV |
937 | flags &= ~v40; | 937 | flags &= ~v40; |
938 | goto loop; | 938 | goto loop; |
939 | 939 | ||
940 | case 0xD8: // CLD | 940 | case 0xD8: // CLD |
941 | flags &= ~d08; | 941 | flags &= ~d08; |
942 | goto loop; | 942 | goto loop; |
943 | 943 | ||
944 | case 0xF8: // SED | 944 | case 0xF8: // SED |
945 | flags |= d08; | 945 | flags |= d08; |
946 | goto loop; | 946 | goto loop; |
947 | 947 | ||
948 | case 0x58: // CLI | 948 | case 0x58: // CLI |
949 | if ( !(flags & i04) ) | 949 | if ( !(flags & i04) ) |
950 | goto loop; | 950 | goto loop; |
951 | flags &= ~i04; | 951 | flags &= ~i04; |
952 | handle_cli: { | 952 | handle_cli: { |
953 | //dprintf( "CLI at %d\n", TIME ); | 953 | //dprintf( "CLI at %d\n", TIME ); |
954 | cpu->r.flags = flags; // update externally-visible I flag | 954 | cpu->r.flags = flags; // update externally-visible I flag |
955 | int delta = s.base - cpu->irq_time; | 955 | int delta = s.base - cpu->irq_time; |
956 | if ( delta <= 0 ) | 956 | if ( delta <= 0 ) |
957 | { | 957 | { |
958 | if ( TIME() < cpu->irq_time ) | 958 | if ( TIME() < cpu->irq_time ) |
959 | goto loop; | 959 | goto loop; |
960 | goto delayed_cli; | 960 | goto delayed_cli; |
961 | } | 961 | } |
962 | s.base = cpu->irq_time; | 962 | s.base = cpu->irq_time; |
963 | s_time += delta; | 963 | s_time += delta; |
964 | if ( s_time < 0 ) | 964 | if ( s_time < 0 ) |
965 | goto loop; | 965 | goto loop; |
966 | 966 | ||
967 | if ( delta >= s_time + 1 ) | 967 | if ( delta >= s_time + 1 ) |
968 | { | 968 | { |
969 | // delayed irq until after next instruction | 969 | // delayed irq until after next instruction |
970 | s.base += s_time + 1; | 970 | s.base += s_time + 1; |
971 | s_time = -1; | 971 | s_time = -1; |
972 | goto loop; | 972 | goto loop; |
973 | } | 973 | } |
974 | 974 | ||
975 | // TODO: implement | 975 | // TODO: implement |
976 | delayed_cli: | 976 | delayed_cli: |
977 | dprintf( "Delayed CLI not emulated\n" ); | 977 | dprintf( "Delayed CLI not emulated\n" ); |
978 | goto loop; | 978 | goto loop; |
979 | } | 979 | } |
980 | 980 | ||
981 | case 0x78: // SEI | 981 | case 0x78: // SEI |
982 | if ( flags & i04 ) | 982 | if ( flags & i04 ) |
983 | goto loop; | 983 | goto loop; |
984 | flags |= i04; | 984 | flags |= i04; |
985 | handle_sei: { | 985 | handle_sei: { |
986 | cpu->r.flags = flags; // update externally-visible I flag | 986 | cpu->r.flags = flags; // update externally-visible I flag |
987 | int delta = s.base - cpu->end_time; | 987 | int delta = s.base - cpu->end_time; |
988 | s.base = cpu->end_time; | 988 | s.base = cpu->end_time; |
989 | s_time += delta; | 989 | s_time += delta; |
990 | if ( s_time < 0 ) | 990 | if ( s_time < 0 ) |
991 | goto loop; | 991 | goto loop; |
992 | 992 | ||
993 | dprintf( "Delayed SEI not emulated\n" ); | 993 | dprintf( "Delayed SEI not emulated\n" ); |
994 | goto loop; | 994 | goto loop; |
995 | } | 995 | } |
996 | 996 | ||
997 | // Unofficial | 997 | // Unofficial |
998 | 998 | ||
999 | // SKW - skip word | 999 | // SKW - skip word |
1000 | case 0x1C: case 0x3C: case 0x5C: case 0x7C: case 0xDC: case 0xFC: | 1000 | case 0x1C: case 0x3C: case 0x5C: case 0x7C: case 0xDC: case 0xFC: |
1001 | PAGE_PENALTY( data + x ); | 1001 | PAGE_PENALTY( data + x ); |
1002 | case 0x0C: | 1002 | case 0x0C: |
1003 | pc++; | 1003 | pc++; |
1004 | // SKB - skip byte | 1004 | // SKB - skip byte |
1005 | case 0x74: case 0x04: case 0x14: case 0x34: case 0x44: case 0x54: case 0x64: | 1005 | case 0x74: case 0x04: case 0x14: case 0x34: case 0x44: case 0x54: case 0x64: |
1006 | case 0x80: case 0x82: case 0x89: case 0xC2: case 0xD4: case 0xE2: case 0xF4: | 1006 | case 0x80: case 0x82: case 0x89: case 0xC2: case 0xD4: case 0xE2: case 0xF4: |
1007 | pc++; | 1007 | pc++; |
1008 | goto loop; | 1008 | goto loop; |
1009 | 1009 | ||
1010 | // NOP | 1010 | // NOP |
1011 | case 0xEA: case 0x1A: case 0x3A: case 0x5A: case 0x7A: case 0xDA: case 0xFA: | 1011 | case 0xEA: case 0x1A: case 0x3A: case 0x5A: case 0x7A: case 0xDA: case 0xFA: |
1012 | goto loop; | 1012 | goto loop; |
1013 | 1013 | ||
1014 | case halt_opcode: // HLT - halt processor | 1014 | case halt_opcode: // HLT - halt processor |
1015 | if ( pc-- > 0x10000 ) | 1015 | if ( pc-- > 0x10000 ) |
1016 | { | 1016 | { |
1017 | // handle wrap-around (assumes caller has put page of HLT at 0x10000) | 1017 | // handle wrap-around (assumes caller has put page of HLT at 0x10000) |
1018 | pc = WORD( pc ); | 1018 | pc = WORD( pc ); |
1019 | goto loop; | 1019 | goto loop; |
1020 | } | 1020 | } |
1021 | case 0x02: case 0x12: case 0x32: case 0x42: case 0x52: | 1021 | case 0x02: case 0x12: case 0x32: case 0x42: case 0x52: |
1022 | case 0x62: case 0x72: case 0x92: case 0xB2: case 0xD2: case 0xF2: | 1022 | case 0x62: case 0x72: case 0x92: case 0xB2: case 0xD2: case 0xF2: |
1023 | goto stop; | 1023 | goto stop; |
1024 | 1024 | ||
1025 | // Unimplemented | 1025 | // Unimplemented |
1026 | 1026 | ||
1027 | case 0xFF: // force 256-entry jump table for optimization purposes | 1027 | case 0xFF: // force 256-entry jump table for optimization purposes |
1028 | c |= 1; // compiler doesn't know that this won't affect anything | 1028 | c |= 1; // compiler doesn't know that this won't affect anything |
1029 | default: | 1029 | default: |
1030 | check( (unsigned) opcode < 0x100 ); | 1030 | check( (unsigned) opcode < 0x100 ); |
1031 | 1031 | ||
1032 | #ifdef UNIMPL_INSTR | 1032 | #ifdef UNIMPL_INSTR |
1033 | UNIMPL_INSTR(); | 1033 | UNIMPL_INSTR(); |
1034 | #endif | 1034 | #endif |
1035 | 1035 | ||
1036 | // At least skip over proper number of bytes instruction uses | 1036 | // At least skip over proper number of bytes instruction uses |
1037 | static unsigned char const illop_lens [8] = { | 1037 | static unsigned char const illop_lens [8] = { |
1038 | 0x40, 0x40, 0x40, 0x80, 0x40, 0x40, 0x80, 0xA0 | 1038 | 0x40, 0x40, 0x40, 0x80, 0x40, 0x40, 0x80, 0xA0 |
1039 | }; | 1039 | }; |
1040 | int opcode = instr [-1]; | 1040 | int opcode = instr [-1]; |
1041 | int len = illop_lens [opcode >> 2 & 7] >> (opcode << 1 & 6) & 3; | 1041 | int len = illop_lens [opcode >> 2 & 7] >> (opcode << 1 & 6) & 3; |
1042 | if ( opcode == 0x9C ) | 1042 | if ( opcode == 0x9C ) |
1043 | len = 2; | 1043 | len = 2; |
1044 | pc += len; | 1044 | pc += len; |
1045 | 1045 | ||
1046 | // Account for extra clock | 1046 | // Account for extra clock |
1047 | if ( (opcode >> 4) == 0x0B ) | 1047 | if ( (opcode >> 4) == 0x0B ) |
1048 | { | 1048 | { |
1049 | if ( opcode == 0xB3 ) | 1049 | if ( opcode == 0xB3 ) |
1050 | data = READ_LOW( data ); | 1050 | data = READ_LOW( data ); |
1051 | if ( opcode != 0xB7 ) | 1051 | if ( opcode != 0xB7 ) |
1052 | PAGE_PENALTY( data + y ); | 1052 | PAGE_PENALTY( data + y ); |
1053 | } | 1053 | } |
1054 | goto loop; | 1054 | goto loop; |
1055 | } | 1055 | } |
1056 | assert( false ); // catch missing 'goto loop' or accidental 'break' | 1056 | assert( false ); // catch missing 'goto loop' or accidental 'break' |
1057 | 1057 | ||
1058 | int result_; | 1058 | int result_; |
1059 | handle_brk: | 1059 | handle_brk: |
1060 | pc++; | 1060 | pc++; |
1061 | result_ = b10 | 4; | 1061 | result_ = b10 | 4; |
1062 | 1062 | ||
1063 | #ifdef CPU_DONE | 1063 | #ifdef CPU_DONE |
1064 | interrupt: | 1064 | interrupt: |
1065 | #endif | 1065 | #endif |
1066 | { | 1066 | { |
1067 | s_time += 7; | 1067 | s_time += 7; |
1068 | 1068 | ||
1069 | // Save PC and read vector | 1069 | // Save PC and read vector |
1070 | WRITE_STACK( SP( -1 ), pc >> 8 ); | 1070 | WRITE_STACK( SP( -1 ), pc >> 8 ); |
1071 | WRITE_STACK( SP( -2 ), pc ); | 1071 | WRITE_STACK( SP( -2 ), pc ); |
1072 | pc = GET_LE16( &READ_CODE( 0xFFFA ) + (result_ & 4) ); | 1072 | pc = GET_LE16( &READ_CODE( 0xFFFA ) + (result_ & 4) ); |
1073 | 1073 | ||
1074 | // Save flags | 1074 | // Save flags |
1075 | int temp; | 1075 | int temp; |
1076 | GET_FLAGS( temp ); | 1076 | GET_FLAGS( temp ); |
1077 | temp |= r20 + (result_ & b10); // B flag set for BRK | 1077 | temp |= r20 + (result_ & b10); // B flag set for BRK |
1078 | sp = SP( -3 ); | 1078 | sp = SP( -3 ); |
1079 | WRITE_STACK( sp, temp ); | 1079 | WRITE_STACK( sp, temp ); |
1080 | 1080 | ||
1081 | // Update I flag in externally-visible flags | 1081 | // Update I flag in externally-visible flags |
1082 | cpu->r.flags = (flags |= i04); | 1082 | cpu->r.flags = (flags |= i04); |
1083 | 1083 | ||
1084 | // Update time | 1084 | // Update time |
1085 | int delta = s.base - cpu->end_time; | 1085 | int delta = s.base - cpu->end_time; |
1086 | if ( delta >= 0 ) | 1086 | if ( delta >= 0 ) |
1087 | goto loop; | 1087 | goto loop; |
1088 | s_time += delta; | 1088 | s_time += delta; |
1089 | s.base = cpu->end_time; | 1089 | s.base = cpu->end_time; |
1090 | goto loop; | 1090 | goto loop; |
1091 | } | 1091 | } |
1092 | 1092 | ||
1093 | out_of_time: | 1093 | out_of_time: |
1094 | pc--; | 1094 | pc--; |
1095 | 1095 | ||
1096 | // Optional action that triggers interrupt or changes irq/end time | 1096 | // Optional action that triggers interrupt or changes irq/end time |
1097 | #ifdef CPU_DONE | 1097 | #ifdef CPU_DONE |
1098 | { | 1098 | { |
1099 | CPU_DONE( result_ ); | 1099 | CPU_DONE( result_ ); |
1100 | if ( result_ >= 0 ) | 1100 | if ( result_ >= 0 ) |
1101 | goto interrupt; | 1101 | goto interrupt; |
1102 | if ( s_time < 0 ) | 1102 | if ( s_time < 0 ) |
1103 | goto loop; | 1103 | goto loop; |
1104 | } | 1104 | } |
1105 | #endif | 1105 | #endif |
1106 | stop: | 1106 | stop: |
1107 | 1107 | ||
1108 | // Flush cached state | 1108 | // Flush cached state |
1109 | cpu->r.pc = pc; | 1109 | cpu->r.pc = pc; |
1110 | cpu->r.sp = GET_SP(); | 1110 | cpu->r.sp = GET_SP(); |
1111 | cpu->r.a = a; | 1111 | cpu->r.a = a; |
1112 | cpu->r.x = x; | 1112 | cpu->r.x = x; |
1113 | cpu->r.y = y; | 1113 | cpu->r.y = y; |
1114 | 1114 | ||
1115 | int temp; | 1115 | int temp; |
1116 | GET_FLAGS( temp ); | 1116 | GET_FLAGS( temp ); |
1117 | cpu->r.flags = temp; | 1117 | cpu->r.flags = temp; |
1118 | 1118 | ||
1119 | cpu->cpu_state_.base = s.base; | 1119 | cpu->cpu_state_.base = s.base; |
1120 | cpu->cpu_state_.time = s_time; | 1120 | cpu->cpu_state_.time = s_time; |
1121 | cpu->cpu_state = &cpu->cpu_state_; | 1121 | cpu->cpu_state = &cpu->cpu_state_; |
1122 | } | 1122 | } |