1 /*****************************************************************************/
5 /* Instruction encoding for the ca65 macroassembler */
9 /* (C) 1998-2012, Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
59 #include "studyexpr.h"
64 /*****************************************************************************/
66 /*****************************************************************************/
70 static void PutPCRel8 (const InsDesc* Ins);
71 /* Handle branches with a 8 bit distance */
73 static void PutPCRel16 (const InsDesc* Ins);
74 /* Handle branches with an 16 bit distance and PER */
76 static void PutBlockMove (const InsDesc* Ins);
77 /* Handle the blockmove instructions (65816) */
79 static void PutBlockTransfer (const InsDesc* Ins);
80 /* Handle the block transfer instructions (HuC6280) */
82 static void PutBitBranch (const InsDesc* Ins);
83 /* Handle 65C02 branch on bit condition */
85 static void PutREP (const InsDesc* Ins);
86 /* Emit a REP instruction, track register sizes */
88 static void PutSEP (const InsDesc* Ins);
89 /* Emit a SEP instruction (65816), track register sizes */
91 static void PutTAMn (const InsDesc* Ins);
92 /* Emit a TAMn instruction (HuC6280). Since this is a two byte instruction with
93 ** implicit addressing mode, the opcode byte in the table is actually the
94 ** second operand byte. The TAM instruction is the more generic form, it takes
95 ** an immediate argument.
98 static void PutTMA (const InsDesc* Ins);
99 /* Emit a TMA instruction (HuC6280) with an immediate argument. Only one bit
100 ** in the argument byte may be set.
103 static void PutTMAn (const InsDesc* Ins);
104 /* Emit a TMAn instruction (HuC6280). Since this is a two byte instruction with
105 ** implicit addressing mode, the opcode byte in the table is actually the
106 ** second operand byte. The TAM instruction is the more generic form, it takes
107 ** an immediate argument.
110 static void PutTST (const InsDesc* Ins);
111 /* Emit a TST instruction (HuC6280). */
113 static void PutJMP (const InsDesc* Ins);
114 /* Handle the jump instruction for the 6502. Problem is that these chips have
115 ** a bug: If the address crosses a page, the upper byte gets not corrected and
116 ** the instruction will fail. The PutJmp function will add a linker assertion
117 ** to check for this case and is otherwise identical to PutAll.
120 static void PutRTS (const InsDesc* Ins attribute ((unused)));
121 /* Handle the RTS instruction for the 816. In smart mode emit a RTL opcode if
122 ** the enclosing scope is FAR.
125 static void PutAll (const InsDesc* Ins);
126 /* Handle all other instructions */
128 static void PutSweet16 (const InsDesc* Ins);
129 /* Handle a generic sweet16 instruction */
131 static void PutSweet16Branch (const InsDesc* Ins);
132 /* Handle a sweet16 branch instruction */
136 /*****************************************************************************/
138 /*****************************************************************************/
142 /* Empty instruction table */
143 static const struct {
149 /* Instruction table for the 6502 */
150 static const struct {
154 sizeof (InsTab6502.Ins) / sizeof (InsTab6502.Ins[0]),
156 { "ADC", 0x080A26C, 0x60, 0, PutAll },
157 { "AND", 0x080A26C, 0x20, 0, PutAll },
158 { "ASL", 0x000006e, 0x02, 1, PutAll },
159 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
160 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
161 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
162 { "BIT", 0x000000C, 0x00, 2, PutAll },
163 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
164 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
165 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
166 { "BRK", 0x0000001, 0x00, 0, PutAll },
167 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
168 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
169 { "CLC", 0x0000001, 0x18, 0, PutAll },
170 { "CLD", 0x0000001, 0xd8, 0, PutAll },
171 { "CLI", 0x0000001, 0x58, 0, PutAll },
172 { "CLV", 0x0000001, 0xb8, 0, PutAll },
173 { "CMP", 0x080A26C, 0xc0, 0, PutAll },
174 { "CPX", 0x080000C, 0xe0, 1, PutAll },
175 { "CPY", 0x080000C, 0xc0, 1, PutAll },
176 { "DEC", 0x000006C, 0x00, 3, PutAll },
177 { "DEX", 0x0000001, 0xca, 0, PutAll },
178 { "DEY", 0x0000001, 0x88, 0, PutAll },
179 { "EOR", 0x080A26C, 0x40, 0, PutAll },
180 { "INC", 0x000006c, 0x00, 4, PutAll },
181 { "INX", 0x0000001, 0xe8, 0, PutAll },
182 { "INY", 0x0000001, 0xc8, 0, PutAll },
183 { "JMP", 0x0000808, 0x4c, 6, PutJMP },
184 { "JSR", 0x0000008, 0x20, 7, PutAll },
185 { "LDA", 0x080A26C, 0xa0, 0, PutAll },
186 { "LDX", 0x080030C, 0xa2, 1, PutAll },
187 { "LDY", 0x080006C, 0xa0, 1, PutAll },
188 { "LSR", 0x000006F, 0x42, 1, PutAll },
189 { "NOP", 0x0000001, 0xea, 0, PutAll },
190 { "ORA", 0x080A26C, 0x00, 0, PutAll },
191 { "PHA", 0x0000001, 0x48, 0, PutAll },
192 { "PHP", 0x0000001, 0x08, 0, PutAll },
193 { "PLA", 0x0000001, 0x68, 0, PutAll },
194 { "PLP", 0x0000001, 0x28, 0, PutAll },
195 { "ROL", 0x000006F, 0x22, 1, PutAll },
196 { "ROR", 0x000006F, 0x62, 1, PutAll },
197 { "RTI", 0x0000001, 0x40, 0, PutAll },
198 { "RTS", 0x0000001, 0x60, 0, PutAll },
199 { "SBC", 0x080A26C, 0xe0, 0, PutAll },
200 { "SEC", 0x0000001, 0x38, 0, PutAll },
201 { "SED", 0x0000001, 0xf8, 0, PutAll },
202 { "SEI", 0x0000001, 0x78, 0, PutAll },
203 { "STA", 0x000A26C, 0x80, 0, PutAll },
204 { "STX", 0x000010c, 0x82, 1, PutAll },
205 { "STY", 0x000002c, 0x80, 1, PutAll },
206 { "TAX", 0x0000001, 0xaa, 0, PutAll },
207 { "TAY", 0x0000001, 0xa8, 0, PutAll },
208 { "TSX", 0x0000001, 0xba, 0, PutAll },
209 { "TXA", 0x0000001, 0x8a, 0, PutAll },
210 { "TXS", 0x0000001, 0x9a, 0, PutAll },
211 { "TYA", 0x0000001, 0x98, 0, PutAll }
215 /* Instruction table for the 6502 with illegal instructions */
216 static const struct {
220 sizeof (InsTab6502X.Ins) / sizeof (InsTab6502X.Ins[0]),
222 { "ADC", 0x080A26C, 0x60, 0, PutAll },
223 { "ALR", 0x0800000, 0x4B, 0, PutAll }, /* X */
224 { "ANC", 0x0800000, 0x0B, 0, PutAll }, /* X */
225 { "AND", 0x080A26C, 0x20, 0, PutAll },
226 { "ANE", 0x0800000, 0x8B, 0, PutAll }, /* X */
227 { "ARR", 0x0800000, 0x6B, 0, PutAll }, /* X */
228 { "ASL", 0x000006e, 0x02, 1, PutAll },
229 { "AXS", 0x0800000, 0xCB, 0, PutAll }, /* X */
230 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
231 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
232 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
233 { "BIT", 0x000000C, 0x00, 2, PutAll },
234 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
235 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
236 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
237 { "BRK", 0x0000001, 0x00, 0, PutAll },
238 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
239 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
240 { "CLC", 0x0000001, 0x18, 0, PutAll },
241 { "CLD", 0x0000001, 0xd8, 0, PutAll },
242 { "CLI", 0x0000001, 0x58, 0, PutAll },
243 { "CLV", 0x0000001, 0xb8, 0, PutAll },
244 { "CMP", 0x080A26C, 0xc0, 0, PutAll },
245 { "CPX", 0x080000C, 0xe0, 1, PutAll },
246 { "CPY", 0x080000C, 0xc0, 1, PutAll },
247 { "DCP", 0x000A26C, 0xC3, 0, PutAll }, /* X */
248 { "DEC", 0x000006C, 0x00, 3, PutAll },
249 { "DEX", 0x0000001, 0xca, 0, PutAll },
250 { "DEY", 0x0000001, 0x88, 0, PutAll },
251 { "EOR", 0x080A26C, 0x40, 0, PutAll },
252 { "INC", 0x000006c, 0x00, 4, PutAll },
253 { "INX", 0x0000001, 0xe8, 0, PutAll },
254 { "INY", 0x0000001, 0xc8, 0, PutAll },
255 { "ISC", 0x000A26C, 0xE3, 0, PutAll }, /* X */
256 { "JAM", 0x0000001, 0x02, 0, PutAll }, /* X */
257 { "JMP", 0x0000808, 0x4c, 6, PutJMP },
258 { "JSR", 0x0000008, 0x20, 7, PutAll },
259 { "LAS", 0x0000200, 0xBB, 0, PutAll }, /* X */
260 { "LAX", 0x080A30C, 0xA3, 11, PutAll }, /* X */
261 { "LDA", 0x080A26C, 0xa0, 0, PutAll },
262 { "LDX", 0x080030C, 0xa2, 1, PutAll },
263 { "LDY", 0x080006C, 0xa0, 1, PutAll },
264 { "LSR", 0x000006F, 0x42, 1, PutAll },
265 { "NOP", 0x080006D, 0x00, 10, PutAll }, /* X */
266 { "ORA", 0x080A26C, 0x00, 0, PutAll },
267 { "PHA", 0x0000001, 0x48, 0, PutAll },
268 { "PHP", 0x0000001, 0x08, 0, PutAll },
269 { "PLA", 0x0000001, 0x68, 0, PutAll },
270 { "PLP", 0x0000001, 0x28, 0, PutAll },
271 { "RLA", 0x000A26C, 0x23, 0, PutAll }, /* X */
272 { "ROL", 0x000006F, 0x22, 1, PutAll },
273 { "ROR", 0x000006F, 0x62, 1, PutAll },
274 { "RRA", 0x000A26C, 0x63, 0, PutAll }, /* X */
275 { "RTI", 0x0000001, 0x40, 0, PutAll },
276 { "RTS", 0x0000001, 0x60, 0, PutAll },
277 { "SAX", 0x000810C, 0x83, 1, PutAll }, /* X */
278 { "SBC", 0x080A26C, 0xe0, 0, PutAll },
279 { "SEC", 0x0000001, 0x38, 0, PutAll },
280 { "SED", 0x0000001, 0xf8, 0, PutAll },
281 { "SEI", 0x0000001, 0x78, 0, PutAll },
282 { "SHA", 0x0002200, 0x93, 1, PutAll }, /* X */
283 { "SHX", 0x0000200, 0x9e, 1, PutAll }, /* X */
284 { "SHY", 0x0000040, 0x9c, 1, PutAll }, /* X */
285 { "SLO", 0x000A26C, 0x03, 0, PutAll }, /* X */
286 { "SRE", 0x000A26C, 0x43, 0, PutAll }, /* X */
287 { "STA", 0x000A26C, 0x80, 0, PutAll },
288 { "STX", 0x000010c, 0x82, 1, PutAll },
289 { "STY", 0x000002c, 0x80, 1, PutAll },
290 { "TAS", 0x0000200, 0x9b, 0, PutAll }, /* X */
291 { "TAX", 0x0000001, 0xaa, 0, PutAll },
292 { "TAY", 0x0000001, 0xa8, 0, PutAll },
293 { "TSX", 0x0000001, 0xba, 0, PutAll },
294 { "TXA", 0x0000001, 0x8a, 0, PutAll },
295 { "TXS", 0x0000001, 0x9a, 0, PutAll },
296 { "TYA", 0x0000001, 0x98, 0, PutAll }
300 /* Instruction table for the 65SC02 */
301 static const struct {
305 sizeof (InsTab65SC02.Ins) / sizeof (InsTab65SC02.Ins[0]),
307 { "ADC", 0x080A66C, 0x60, 0, PutAll },
308 { "AND", 0x080A66C, 0x20, 0, PutAll },
309 { "ASL", 0x000006e, 0x02, 1, PutAll },
310 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
311 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
312 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
313 { "BIT", 0x0A0006C, 0x00, 2, PutAll },
314 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
315 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
316 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
317 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
318 { "BRK", 0x0000001, 0x00, 0, PutAll },
319 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
320 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
321 { "CLC", 0x0000001, 0x18, 0, PutAll },
322 { "CLD", 0x0000001, 0xd8, 0, PutAll },
323 { "CLI", 0x0000001, 0x58, 0, PutAll },
324 { "CLV", 0x0000001, 0xb8, 0, PutAll },
325 { "CMP", 0x080A66C, 0xc0, 0, PutAll },
326 { "CPX", 0x080000C, 0xe0, 1, PutAll },
327 { "CPY", 0x080000C, 0xc0, 1, PutAll },
328 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
329 { "DEC", 0x000006F, 0x00, 3, PutAll },
330 { "DEX", 0x0000001, 0xca, 0, PutAll },
331 { "DEY", 0x0000001, 0x88, 0, PutAll },
332 { "EOR", 0x080A66C, 0x40, 0, PutAll },
333 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
334 { "INC", 0x000006f, 0x00, 4, PutAll },
335 { "INX", 0x0000001, 0xe8, 0, PutAll },
336 { "INY", 0x0000001, 0xc8, 0, PutAll },
337 { "JMP", 0x0010808, 0x4c, 6, PutAll },
338 { "JSR", 0x0000008, 0x20, 7, PutAll },
339 { "LDA", 0x080A66C, 0xa0, 0, PutAll },
340 { "LDX", 0x080030C, 0xa2, 1, PutAll },
341 { "LDY", 0x080006C, 0xa0, 1, PutAll },
342 { "LSR", 0x000006F, 0x42, 1, PutAll },
343 { "NOP", 0x0000001, 0xea, 0, PutAll },
344 { "ORA", 0x080A66C, 0x00, 0, PutAll },
345 { "PHA", 0x0000001, 0x48, 0, PutAll },
346 { "PHP", 0x0000001, 0x08, 0, PutAll },
347 { "PHX", 0x0000001, 0xda, 0, PutAll },
348 { "PHY", 0x0000001, 0x5a, 0, PutAll },
349 { "PLA", 0x0000001, 0x68, 0, PutAll },
350 { "PLP", 0x0000001, 0x28, 0, PutAll },
351 { "PLX", 0x0000001, 0xfa, 0, PutAll },
352 { "PLY", 0x0000001, 0x7a, 0, PutAll },
353 { "ROL", 0x000006F, 0x22, 1, PutAll },
354 { "ROR", 0x000006F, 0x62, 1, PutAll },
355 { "RTI", 0x0000001, 0x40, 0, PutAll },
356 { "RTS", 0x0000001, 0x60, 0, PutAll },
357 { "SBC", 0x080A66C, 0xe0, 0, PutAll },
358 { "SEC", 0x0000001, 0x38, 0, PutAll },
359 { "SED", 0x0000001, 0xf8, 0, PutAll },
360 { "SEI", 0x0000001, 0x78, 0, PutAll },
361 { "STA", 0x000A66C, 0x80, 0, PutAll },
362 { "STX", 0x000010c, 0x82, 1, PutAll },
363 { "STY", 0x000002c, 0x80, 1, PutAll },
364 { "STZ", 0x000006c, 0x04, 5, PutAll },
365 { "TAX", 0x0000001, 0xaa, 0, PutAll },
366 { "TAY", 0x0000001, 0xa8, 0, PutAll },
367 { "TRB", 0x000000c, 0x10, 1, PutAll },
368 { "TSB", 0x000000c, 0x00, 1, PutAll },
369 { "TSX", 0x0000001, 0xba, 0, PutAll },
370 { "TXA", 0x0000001, 0x8a, 0, PutAll },
371 { "TXS", 0x0000001, 0x9a, 0, PutAll },
372 { "TYA", 0x0000001, 0x98, 0, PutAll }
376 /* Instruction table for the 65C02 */
377 static const struct {
381 sizeof (InsTab65C02.Ins) / sizeof (InsTab65C02.Ins[0]),
383 { "ADC", 0x080A66C, 0x60, 0, PutAll },
384 { "AND", 0x080A66C, 0x20, 0, PutAll },
385 { "ASL", 0x000006e, 0x02, 1, PutAll },
386 { "BBR0", 0x0000000, 0x0F, 0, PutBitBranch },
387 { "BBR1", 0x0000000, 0x1F, 0, PutBitBranch },
388 { "BBR2", 0x0000000, 0x2F, 0, PutBitBranch },
389 { "BBR3", 0x0000000, 0x3F, 0, PutBitBranch },
390 { "BBR4", 0x0000000, 0x4F, 0, PutBitBranch },
391 { "BBR5", 0x0000000, 0x5F, 0, PutBitBranch },
392 { "BBR6", 0x0000000, 0x6F, 0, PutBitBranch },
393 { "BBR7", 0x0000000, 0x7F, 0, PutBitBranch },
394 { "BBS0", 0x0000000, 0x8F, 0, PutBitBranch },
395 { "BBS1", 0x0000000, 0x9F, 0, PutBitBranch },
396 { "BBS2", 0x0000000, 0xAF, 0, PutBitBranch },
397 { "BBS3", 0x0000000, 0xBF, 0, PutBitBranch },
398 { "BBS4", 0x0000000, 0xCF, 0, PutBitBranch },
399 { "BBS5", 0x0000000, 0xDF, 0, PutBitBranch },
400 { "BBS6", 0x0000000, 0xEF, 0, PutBitBranch },
401 { "BBS7", 0x0000000, 0xFF, 0, PutBitBranch },
402 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
403 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
404 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
405 { "BIT", 0x0A0006C, 0x00, 2, PutAll },
406 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
407 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
408 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
409 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
410 { "BRK", 0x0000001, 0x00, 0, PutAll },
411 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
412 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
413 { "CLC", 0x0000001, 0x18, 0, PutAll },
414 { "CLD", 0x0000001, 0xd8, 0, PutAll },
415 { "CLI", 0x0000001, 0x58, 0, PutAll },
416 { "CLV", 0x0000001, 0xb8, 0, PutAll },
417 { "CMP", 0x080A66C, 0xc0, 0, PutAll },
418 { "CPX", 0x080000C, 0xe0, 1, PutAll },
419 { "CPY", 0x080000C, 0xc0, 1, PutAll },
420 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
421 { "DEC", 0x000006F, 0x00, 3, PutAll },
422 { "DEX", 0x0000001, 0xca, 0, PutAll },
423 { "DEY", 0x0000001, 0x88, 0, PutAll },
424 { "EOR", 0x080A66C, 0x40, 0, PutAll },
425 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
426 { "INC", 0x000006f, 0x00, 4, PutAll },
427 { "INX", 0x0000001, 0xe8, 0, PutAll },
428 { "INY", 0x0000001, 0xc8, 0, PutAll },
429 { "JMP", 0x0010808, 0x4c, 6, PutAll },
430 { "JSR", 0x0000008, 0x20, 7, PutAll },
431 { "LDA", 0x080A66C, 0xa0, 0, PutAll },
432 { "LDX", 0x080030C, 0xa2, 1, PutAll },
433 { "LDY", 0x080006C, 0xa0, 1, PutAll },
434 { "LSR", 0x000006F, 0x42, 1, PutAll },
435 { "NOP", 0x0000001, 0xea, 0, PutAll },
436 { "ORA", 0x080A66C, 0x00, 0, PutAll },
437 { "PHA", 0x0000001, 0x48, 0, PutAll },
438 { "PHP", 0x0000001, 0x08, 0, PutAll },
439 { "PHX", 0x0000001, 0xda, 0, PutAll },
440 { "PHY", 0x0000001, 0x5a, 0, PutAll },
441 { "PLA", 0x0000001, 0x68, 0, PutAll },
442 { "PLP", 0x0000001, 0x28, 0, PutAll },
443 { "PLX", 0x0000001, 0xfa, 0, PutAll },
444 { "PLY", 0x0000001, 0x7a, 0, PutAll },
445 { "RMB0", 0x0000004, 0x07, 1, PutAll },
446 { "RMB1", 0x0000004, 0x17, 1, PutAll },
447 { "RMB2", 0x0000004, 0x27, 1, PutAll },
448 { "RMB3", 0x0000004, 0x37, 1, PutAll },
449 { "RMB4", 0x0000004, 0x47, 1, PutAll },
450 { "RMB5", 0x0000004, 0x57, 1, PutAll },
451 { "RMB6", 0x0000004, 0x67, 1, PutAll },
452 { "RMB7", 0x0000004, 0x77, 1, PutAll },
453 { "ROL", 0x000006F, 0x22, 1, PutAll },
454 { "ROR", 0x000006F, 0x62, 1, PutAll },
455 { "RTI", 0x0000001, 0x40, 0, PutAll },
456 { "RTS", 0x0000001, 0x60, 0, PutAll },
457 { "SBC", 0x080A66C, 0xe0, 0, PutAll },
458 { "SEC", 0x0000001, 0x38, 0, PutAll },
459 { "SED", 0x0000001, 0xf8, 0, PutAll },
460 { "SEI", 0x0000001, 0x78, 0, PutAll },
461 { "SMB0", 0x0000004, 0x87, 1, PutAll },
462 { "SMB1", 0x0000004, 0x97, 1, PutAll },
463 { "SMB2", 0x0000004, 0xA7, 1, PutAll },
464 { "SMB3", 0x0000004, 0xB7, 1, PutAll },
465 { "SMB4", 0x0000004, 0xC7, 1, PutAll },
466 { "SMB5", 0x0000004, 0xD7, 1, PutAll },
467 { "SMB6", 0x0000004, 0xE7, 1, PutAll },
468 { "SMB7", 0x0000004, 0xF7, 1, PutAll },
469 { "STA", 0x000A66C, 0x80, 0, PutAll },
470 { "STX", 0x000010c, 0x82, 1, PutAll },
471 { "STY", 0x000002c, 0x80, 1, PutAll },
472 { "STZ", 0x000006c, 0x04, 5, PutAll },
473 { "TAX", 0x0000001, 0xaa, 0, PutAll },
474 { "TAY", 0x0000001, 0xa8, 0, PutAll },
475 { "TRB", 0x000000c, 0x10, 1, PutAll },
476 { "TSB", 0x000000c, 0x00, 1, PutAll },
477 { "TSX", 0x0000001, 0xba, 0, PutAll },
478 { "TXA", 0x0000001, 0x8a, 0, PutAll },
479 { "TXS", 0x0000001, 0x9a, 0, PutAll },
480 { "TYA", 0x0000001, 0x98, 0, PutAll }
484 /* Instruction table for the 65816 */
485 static const struct {
489 sizeof (InsTab65816.Ins) / sizeof (InsTab65816.Ins[0]),
491 { "ADC", 0x0b8f6fc, 0x60, 0, PutAll },
492 { "AND", 0x0b8f6fc, 0x20, 0, PutAll },
493 { "ASL", 0x000006e, 0x02, 1, PutAll },
494 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
495 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
496 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
497 { "BIT", 0x0a0006c, 0x00, 2, PutAll },
498 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
499 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
500 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
501 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
502 { "BRK", 0x0000001, 0x00, 0, PutAll },
503 { "BRL", 0x0040000, 0x82, 0, PutPCRel16 },
504 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
505 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
506 { "CLC", 0x0000001, 0x18, 0, PutAll },
507 { "CLD", 0x0000001, 0xd8, 0, PutAll },
508 { "CLI", 0x0000001, 0x58, 0, PutAll },
509 { "CLV", 0x0000001, 0xb8, 0, PutAll },
510 { "CMP", 0x0b8f6fc, 0xc0, 0, PutAll },
511 { "COP", 0x0000004, 0x02, 6, PutAll },
512 { "CPA", 0x0b8f6fc, 0xc0, 0, PutAll }, /* == CMP */
513 { "CPX", 0x0c0000c, 0xe0, 1, PutAll },
514 { "CPY", 0x0c0000c, 0xc0, 1, PutAll },
515 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
516 { "DEC", 0x000006F, 0x00, 3, PutAll },
517 { "DEX", 0x0000001, 0xca, 0, PutAll },
518 { "DEY", 0x0000001, 0x88, 0, PutAll },
519 { "EOR", 0x0b8f6fc, 0x40, 0, PutAll },
520 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
521 { "INC", 0x000006F, 0x00, 4, PutAll },
522 { "INX", 0x0000001, 0xe8, 0, PutAll },
523 { "INY", 0x0000001, 0xc8, 0, PutAll },
524 { "JML", 0x4000010, 0x5c, 1, PutAll },
525 { "JMP", 0x4010818, 0x4c, 6, PutAll },
526 { "JSL", 0x0000010, 0x20, 7, PutAll },
527 { "JSR", 0x0010018, 0x20, 7, PutAll },
528 { "LDA", 0x0b8f6fc, 0xa0, 0, PutAll },
529 { "LDX", 0x0c0030c, 0xa2, 1, PutAll },
530 { "LDY", 0x0c0006c, 0xa0, 1, PutAll },
531 { "LSR", 0x000006F, 0x42, 1, PutAll },
532 { "MVN", 0x1000000, 0x54, 0, PutBlockMove },
533 { "MVP", 0x1000000, 0x44, 0, PutBlockMove },
534 { "NOP", 0x0000001, 0xea, 0, PutAll },
535 { "ORA", 0x0b8f6fc, 0x00, 0, PutAll },
536 { "PEA", 0x0000008, 0xf4, 6, PutAll },
537 { "PEI", 0x0000400, 0xd4, 1, PutAll },
538 { "PER", 0x0040000, 0x62, 0, PutPCRel16 },
539 { "PHA", 0x0000001, 0x48, 0, PutAll },
540 { "PHB", 0x0000001, 0x8b, 0, PutAll },
541 { "PHD", 0x0000001, 0x0b, 0, PutAll },
542 { "PHK", 0x0000001, 0x4b, 0, PutAll },
543 { "PHP", 0x0000001, 0x08, 0, PutAll },
544 { "PHX", 0x0000001, 0xda, 0, PutAll },
545 { "PHY", 0x0000001, 0x5a, 0, PutAll },
546 { "PLA", 0x0000001, 0x68, 0, PutAll },
547 { "PLB", 0x0000001, 0xab, 0, PutAll },
548 { "PLD", 0x0000001, 0x2b, 0, PutAll },
549 { "PLP", 0x0000001, 0x28, 0, PutAll },
550 { "PLX", 0x0000001, 0xfa, 0, PutAll },
551 { "PLY", 0x0000001, 0x7a, 0, PutAll },
552 { "REP", 0x0800000, 0xc2, 1, PutREP },
553 { "ROL", 0x000006F, 0x22, 1, PutAll },
554 { "ROR", 0x000006F, 0x62, 1, PutAll },
555 { "RTI", 0x0000001, 0x40, 0, PutAll },
556 { "RTL", 0x0000001, 0x6b, 0, PutAll },
557 { "RTS", 0x0000001, 0x60, 0, PutRTS },
558 { "SBC", 0x0b8f6fc, 0xe0, 0, PutAll },
559 { "SEC", 0x0000001, 0x38, 0, PutAll },
560 { "SED", 0x0000001, 0xf8, 0, PutAll },
561 { "SEI", 0x0000001, 0x78, 0, PutAll },
562 { "SEP", 0x0800000, 0xe2, 1, PutSEP },
563 { "STA", 0x018f6fc, 0x80, 0, PutAll },
564 { "STP", 0x0000001, 0xdb, 0, PutAll },
565 { "STX", 0x000010c, 0x82, 1, PutAll },
566 { "STY", 0x000002c, 0x80, 1, PutAll },
567 { "STZ", 0x000006c, 0x04, 5, PutAll },
568 { "SWA", 0x0000001, 0xeb, 0, PutAll }, /* == XBA */
569 { "TAD", 0x0000001, 0x5b, 0, PutAll }, /* == TCD */
570 { "TAS", 0x0000001, 0x1b, 0, PutAll }, /* == TCS */
571 { "TAX", 0x0000001, 0xaa, 0, PutAll },
572 { "TAY", 0x0000001, 0xa8, 0, PutAll },
573 { "TCD", 0x0000001, 0x5b, 0, PutAll },
574 { "TCS", 0x0000001, 0x1b, 0, PutAll },
575 { "TDA", 0x0000001, 0x7b, 0, PutAll }, /* == TDC */
576 { "TDC", 0x0000001, 0x7b, 0, PutAll },
577 { "TRB", 0x000000c, 0x10, 1, PutAll },
578 { "TSA", 0x0000001, 0x3b, 0, PutAll }, /* == TSC */
579 { "TSB", 0x000000c, 0x00, 1, PutAll },
580 { "TSC", 0x0000001, 0x3b, 0, PutAll },
581 { "TSX", 0x0000001, 0xba, 0, PutAll },
582 { "TXA", 0x0000001, 0x8a, 0, PutAll },
583 { "TXS", 0x0000001, 0x9a, 0, PutAll },
584 { "TXY", 0x0000001, 0x9b, 0, PutAll },
585 { "TYA", 0x0000001, 0x98, 0, PutAll },
586 { "TYX", 0x0000001, 0xbb, 0, PutAll },
587 { "WAI", 0x0000001, 0xcb, 0, PutAll },
588 { "XBA", 0x0000001, 0xeb, 0, PutAll },
589 { "XCE", 0x0000001, 0xfb, 0, PutAll }
593 /* Instruction table for the SWEET16 pseudo CPU */
594 static const struct {
598 sizeof (InsTabSweet16.Ins) / sizeof (InsTabSweet16.Ins[0]),
600 { "ADD", AMSW16_REG, 0xA0, 0, PutSweet16 },
601 { "BC", AMSW16_BRA, 0x03, 0, PutSweet16Branch },
602 { "BK", AMSW16_IMP, 0x0A, 0, PutSweet16 },
603 { "BM", AMSW16_BRA, 0x05, 0, PutSweet16Branch },
604 { "BM1", AMSW16_BRA, 0x08, 0, PutSweet16Branch },
605 { "BNC", AMSW16_BRA, 0x02, 0, PutSweet16Branch },
606 { "BNM1", AMSW16_BRA, 0x09, 0, PutSweet16Branch },
607 { "BNZ", AMSW16_BRA, 0x07, 0, PutSweet16Branch },
608 { "BP", AMSW16_BRA, 0x04, 0, PutSweet16Branch },
609 { "BR", AMSW16_BRA, 0x01, 0, PutSweet16Branch },
610 { "BS", AMSW16_BRA, 0x0B, 0, PutSweet16Branch },
611 { "BZ", AMSW16_BRA, 0x06, 0, PutSweet16Branch },
612 { "CPR", AMSW16_REG, 0xD0, 0, PutSweet16 },
613 { "DCR", AMSW16_REG, 0xF0, 0, PutSweet16 },
614 { "INR", AMSW16_REG, 0xE0, 0, PutSweet16 },
615 { "LD", AMSW16_REG | AMSW16_IND, 0x00, 1, PutSweet16 },
616 { "LDD", AMSW16_IND, 0x60, 0, PutSweet16 },
617 { "POP", AMSW16_IND, 0x80, 0, PutSweet16 },
618 { "POPD", AMSW16_IND, 0xC0, 0, PutSweet16 },
619 { "RS", AMSW16_IMP, 0x0B, 0, PutSweet16 },
620 { "RTN", AMSW16_IMP, 0x00, 0, PutSweet16 },
621 { "SET", AMSW16_IMM, 0x10, 0, PutSweet16 },
622 { "ST", AMSW16_REG | AMSW16_IND, 0x10, 1, PutSweet16 },
623 { "STD", AMSW16_IND, 0x70, 0, PutSweet16 },
624 { "STP", AMSW16_IND, 0x90, 0, PutSweet16 },
625 { "SUB", AMSW16_REG, 0xB0, 0, PutSweet16 },
629 /* Instruction table for the HuC6280 (the CPU used in the PC engine) */
630 static const struct {
634 sizeof (InsTabHuC6280.Ins) / sizeof (InsTabHuC6280.Ins[0]),
636 { "ADC", 0x080A66C, 0x60, 0, PutAll },
637 { "AND", 0x080A66C, 0x20, 0, PutAll },
638 { "ASL", 0x000006e, 0x02, 1, PutAll },
639 { "BBR0", 0x0000000, 0x0F, 0, PutBitBranch },
640 { "BBR1", 0x0000000, 0x1F, 0, PutBitBranch },
641 { "BBR2", 0x0000000, 0x2F, 0, PutBitBranch },
642 { "BBR3", 0x0000000, 0x3F, 0, PutBitBranch },
643 { "BBR4", 0x0000000, 0x4F, 0, PutBitBranch },
644 { "BBR5", 0x0000000, 0x5F, 0, PutBitBranch },
645 { "BBR6", 0x0000000, 0x6F, 0, PutBitBranch },
646 { "BBR7", 0x0000000, 0x7F, 0, PutBitBranch },
647 { "BBS0", 0x0000000, 0x8F, 0, PutBitBranch },
648 { "BBS1", 0x0000000, 0x9F, 0, PutBitBranch },
649 { "BBS2", 0x0000000, 0xAF, 0, PutBitBranch },
650 { "BBS3", 0x0000000, 0xBF, 0, PutBitBranch },
651 { "BBS4", 0x0000000, 0xCF, 0, PutBitBranch },
652 { "BBS5", 0x0000000, 0xDF, 0, PutBitBranch },
653 { "BBS6", 0x0000000, 0xEF, 0, PutBitBranch },
654 { "BBS7", 0x0000000, 0xFF, 0, PutBitBranch },
655 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
656 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
657 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
658 { "BIT", 0x0A0006C, 0x00, 2, PutAll },
659 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
660 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
661 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
662 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
663 { "BRK", 0x0000001, 0x00, 0, PutAll },
664 { "BSR", 0x0020000, 0x44, 0, PutPCRel8 },
665 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
666 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
667 { "CLA", 0x0000001, 0x62, 0, PutAll },
668 { "CLC", 0x0000001, 0x18, 0, PutAll },
669 { "CLD", 0x0000001, 0xd8, 0, PutAll },
670 { "CLI", 0x0000001, 0x58, 0, PutAll },
671 { "CLV", 0x0000001, 0xb8, 0, PutAll },
672 { "CLX", 0x0000001, 0x82, 0, PutAll },
673 { "CLY", 0x0000001, 0xc2, 0, PutAll },
674 { "CMP", 0x080A66C, 0xc0, 0, PutAll },
675 { "CPX", 0x080000C, 0xe0, 1, PutAll },
676 { "CPY", 0x080000C, 0xc0, 1, PutAll },
677 { "CSH", 0x0000001, 0xd4, 0, PutAll },
678 { "CSL", 0x0000001, 0x54, 0, PutAll },
679 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
680 { "DEC", 0x000006F, 0x00, 3, PutAll },
681 { "DEX", 0x0000001, 0xca, 0, PutAll },
682 { "DEY", 0x0000001, 0x88, 0, PutAll },
683 { "EOR", 0x080A66C, 0x40, 0, PutAll },
684 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
685 { "INC", 0x000006f, 0x00, 4, PutAll },
686 { "INX", 0x0000001, 0xe8, 0, PutAll },
687 { "INY", 0x0000001, 0xc8, 0, PutAll },
688 { "JMP", 0x0010808, 0x4c, 6, PutAll },
689 { "JSR", 0x0000008, 0x20, 7, PutAll },
690 { "LDA", 0x080A66C, 0xa0, 0, PutAll },
691 { "LDX", 0x080030C, 0xa2, 1, PutAll },
692 { "LDY", 0x080006C, 0xa0, 1, PutAll },
693 { "LSR", 0x000006F, 0x42, 1, PutAll },
694 { "NOP", 0x0000001, 0xea, 0, PutAll },
695 { "ORA", 0x080A66C, 0x00, 0, PutAll },
696 { "PHA", 0x0000001, 0x48, 0, PutAll },
697 { "PHP", 0x0000001, 0x08, 0, PutAll },
698 { "PHX", 0x0000001, 0xda, 0, PutAll },
699 { "PHY", 0x0000001, 0x5a, 0, PutAll },
700 { "PLA", 0x0000001, 0x68, 0, PutAll },
701 { "PLP", 0x0000001, 0x28, 0, PutAll },
702 { "PLX", 0x0000001, 0xfa, 0, PutAll },
703 { "PLY", 0x0000001, 0x7a, 0, PutAll },
704 { "RMB0", 0x0000004, 0x07, 1, PutAll },
705 { "RMB1", 0x0000004, 0x17, 1, PutAll },
706 { "RMB2", 0x0000004, 0x27, 1, PutAll },
707 { "RMB3", 0x0000004, 0x37, 1, PutAll },
708 { "RMB4", 0x0000004, 0x47, 1, PutAll },
709 { "RMB5", 0x0000004, 0x57, 1, PutAll },
710 { "RMB6", 0x0000004, 0x67, 1, PutAll },
711 { "RMB7", 0x0000004, 0x77, 1, PutAll },
712 { "ROL", 0x000006F, 0x22, 1, PutAll },
713 { "ROR", 0x000006F, 0x62, 1, PutAll },
714 { "RTI", 0x0000001, 0x40, 0, PutAll },
715 { "RTS", 0x0000001, 0x60, 0, PutAll },
716 { "SAX", 0x0000001, 0x22, 0, PutAll },
717 { "SAY", 0x0000001, 0x42, 0, PutAll },
718 { "SBC", 0x080A66C, 0xe0, 0, PutAll },
719 { "SEC", 0x0000001, 0x38, 0, PutAll },
720 { "SED", 0x0000001, 0xf8, 0, PutAll },
721 { "SEI", 0x0000001, 0x78, 0, PutAll },
722 { "SET", 0x0000001, 0xf4, 0, PutAll },
723 { "SMB0", 0x0000004, 0x87, 1, PutAll },
724 { "SMB1", 0x0000004, 0x97, 1, PutAll },
725 { "SMB2", 0x0000004, 0xA7, 1, PutAll },
726 { "SMB3", 0x0000004, 0xB7, 1, PutAll },
727 { "SMB4", 0x0000004, 0xC7, 1, PutAll },
728 { "SMB5", 0x0000004, 0xD7, 1, PutAll },
729 { "SMB6", 0x0000004, 0xE7, 1, PutAll },
730 { "SMB7", 0x0000004, 0xF7, 1, PutAll },
731 { "ST0", 0x0800000, 0x03, 1, PutAll },
732 { "ST1", 0x0800000, 0x13, 1, PutAll },
733 { "ST2", 0x0800000, 0x23, 1, PutAll },
734 { "STA", 0x000A66C, 0x80, 0, PutAll },
735 { "STX", 0x000010c, 0x82, 1, PutAll },
736 { "STY", 0x000002c, 0x80, 1, PutAll },
737 { "STZ", 0x000006c, 0x04, 5, PutAll },
738 { "SXY", 0x0000001, 0x02, 0, PutAll },
739 { "TAI", 0x2000000, 0xf3, 0, PutBlockTransfer },
740 { "TAM", 0x0800000, 0x53, 1, PutAll },
741 { "TAM0", 0x0000001, 0x01, 0, PutTAMn},
742 { "TAM1", 0x0000001, 0x02, 0, PutTAMn},
743 { "TAM2", 0x0000001, 0x04, 0, PutTAMn},
744 { "TAM3", 0x0000001, 0x08, 0, PutTAMn},
745 { "TAM4", 0x0000001, 0x10, 0, PutTAMn},
746 { "TAM5", 0x0000001, 0x20, 0, PutTAMn},
747 { "TAM6", 0x0000001, 0x40, 0, PutTAMn},
748 { "TAM7", 0x0000001, 0x80, 0, PutTAMn},
749 { "TAX", 0x0000001, 0xaa, 0, PutAll },
750 { "TAY", 0x0000001, 0xa8, 0, PutAll },
751 { "TDD", 0x2000000, 0xc3, 0, PutBlockTransfer },
752 { "TIA", 0x2000000, 0xe3, 0, PutBlockTransfer },
753 { "TII", 0x2000000, 0x73, 0, PutBlockTransfer },
754 { "TIN", 0x2000000, 0xD3, 0, PutBlockTransfer },
755 { "TMA", 0x0800000, 0x43, 1, PutTMA },
756 { "TMA0", 0x0000001, 0x01, 0, PutTMAn},
757 { "TMA1", 0x0000001, 0x02, 0, PutTMAn},
758 { "TMA2", 0x0000001, 0x04, 0, PutTMAn},
759 { "TMA3", 0x0000001, 0x08, 0, PutTMAn},
760 { "TMA4", 0x0000001, 0x10, 0, PutTMAn},
761 { "TMA5", 0x0000001, 0x20, 0, PutTMAn},
762 { "TMA6", 0x0000001, 0x40, 0, PutTMAn},
763 { "TMA7", 0x0000001, 0x80, 0, PutTMAn},
764 { "TRB", 0x000000c, 0x10, 1, PutAll },
765 { "TSB", 0x000000c, 0x00, 1, PutAll },
766 { "TST", 0x000006c, 0x83, 9, PutTST },
767 { "TSX", 0x0000001, 0xba, 0, PutAll },
768 { "TXA", 0x0000001, 0x8a, 0, PutAll },
769 { "TXS", 0x0000001, 0x9a, 0, PutAll },
770 { "TYA", 0x0000001, 0x98, 0, PutAll }
776 /* An array with instruction tables */
777 static const InsTable* InsTabs[CPU_COUNT] = {
778 (const InsTable*) &InsTabNone,
779 (const InsTable*) &InsTab6502,
780 (const InsTable*) &InsTab6502X,
781 (const InsTable*) &InsTab65SC02,
782 (const InsTable*) &InsTab65C02,
783 (const InsTable*) &InsTab65816,
784 (const InsTable*) &InsTabSweet16,
785 (const InsTable*) &InsTabHuC6280,
786 0, /* Mitsubishi 740 */
788 const InsTable* InsTab = (const InsTable*) &InsTab6502;
790 /* Table to build the effective 65xx opcode from a base opcode and an
791 ** addressing mode. (The value in the table is ORed with the base opcode)
793 static unsigned char EATab[12][AM65I_COUNT] = {
795 0x00, 0x00, 0x05, 0x0D, 0x0F, 0x15, 0x1D, 0x1F,
796 0x00, 0x19, 0x12, 0x00, 0x07, 0x11, 0x17, 0x01,
797 0x00, 0x00, 0x00, 0x03, 0x13, 0x09, 0x00, 0x09,
801 0x08, 0x08, 0x04, 0x0C, 0x00, 0x14, 0x1C, 0x00,
802 0x14, 0x1C, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00,
803 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
807 0x00, 0x00, 0x24, 0x2C, 0x0F, 0x34, 0x3C, 0x00,
808 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
809 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00,
813 0x3A, 0x3A, 0xC6, 0xCE, 0x00, 0xD6, 0xDE, 0x00,
814 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
815 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
819 0x1A, 0x1A, 0xE6, 0xEE, 0x00, 0xF6, 0xFE, 0x00,
820 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
821 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
825 0x00, 0x00, 0x60, 0x98, 0x00, 0x70, 0x9E, 0x00,
826 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
827 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
831 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
832 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
833 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
837 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
838 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
839 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
843 0x00, 0x40, 0x01, 0x41, 0x00, 0x09, 0x49, 0x00,
844 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00,
845 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
849 0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x30, 0x00,
850 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
851 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
854 { /* Table 10 (NOPs) */
855 0xea, 0x00, 0x04, 0x0c, 0x00, 0x14, 0x1c, 0x00,
856 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
857 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
860 { /* Table 11 (LAX) */
861 0x08, 0x08, 0x04, 0x0C, 0x00, 0x14, 0x1C, 0x00,
862 0x14, 0x1C, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00,
863 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
868 /* Table to build the effective SWEET16 opcode from a base opcode and an
871 static unsigned char Sweet16EATab[2][AMSW16I_COUNT] = {
873 0x00, 0x00, 0x00, 0x00, 0x00,
876 0x00, 0x00, 0x00, 0x40, 0x20,
880 /* Table that encodes the additional bytes for each 65xx instruction */
881 unsigned char ExtBytes[AM65I_COUNT] = {
886 3, /* Absolute long */
889 3, /* Absolute long,X */
898 2, /* (Absolute,X) */
899 1, /* Relative short */
900 2, /* Relative long */
903 1, /* Immidiate accu */
904 1, /* Immidiate index */
905 1, /* Immidiate byte */
906 2, /* Blockmove (65816) */
907 7, /* Block transfer (HuC6280) */
908 2, /* Absolute Indirect long */
911 /* Table that encodes the additional bytes for each SWEET16 instruction */
912 static unsigned char Sweet16ExtBytes[AMSW16I_COUNT] = {
922 /*****************************************************************************/
923 /* Handler functions for 6502 derivates */
924 /*****************************************************************************/
928 static int EvalEA (const InsDesc* Ins, EffAddr* A)
929 /* Evaluate the effective address. All fields in A will be valid after calling
930 ** this function. The function returns true on success and false on errors.
933 /* Get the set of possible addressing modes */
936 /* From the possible addressing modes, remove the ones that are invalid
937 ** for this instruction or CPU.
939 A->AddrModeSet &= Ins->AddrMode;
941 /* If we have an expression, check it and remove any addressing modes that
942 ** are too small for the expression size. Since we have to study the
943 ** expression anyway, do also replace it by a simpler one if possible.
949 /* Study the expression */
950 StudyExpr (A->Expr, &ED);
952 /* Simplify it if possible */
953 A->Expr = SimplifyExpr (A->Expr, &ED);
955 if (ED.AddrSize == ADDR_SIZE_DEFAULT) {
956 /* We don't know how big the expression is. If the instruction
957 ** allows just one addressing mode, assume this as address size
958 ** for the expression. Otherwise assume the default address size
961 if ((A->AddrModeSet & ~AM65_ALL_ZP) == 0) {
962 ED.AddrSize = ADDR_SIZE_ZP;
963 } else if ((A->AddrModeSet & ~AM65_ALL_ABS) == 0) {
964 ED.AddrSize = ADDR_SIZE_ABS;
965 } else if ((A->AddrModeSet & ~AM65_ALL_FAR) == 0) {
966 ED.AddrSize = ADDR_SIZE_FAR;
968 ED.AddrSize = DataAddrSize;
969 /* If the default address size of the data segment is unequal
970 ** to zero page addressing, but zero page addressing is
971 ** allowed by the instruction, mark all symbols in the
972 ** expression tree. This mark will be checked at end of
973 ** assembly, and a warning is issued, if a zero page symbol
974 ** was guessed wrong here.
976 if (ED.AddrSize > ADDR_SIZE_ZP && (A->AddrModeSet & AM65_SET_ZP)) {
977 ExprGuessedAddrSize (A->Expr, ADDR_SIZE_ZP);
983 switch (ED.AddrSize) {
986 A->AddrModeSet &= ~AM65_SET_ZP;
990 A->AddrModeSet &= ~(AM65_SET_ZP | AM65_SET_ABS);
994 /* Free any resource associated with the expression desc */
998 /* Check if we have any adressing modes left */
999 if (A->AddrModeSet == 0) {
1000 Error ("Illegal addressing mode");
1003 A->AddrMode = BitFind (A->AddrModeSet);
1004 A->AddrModeBit = (0x01UL << A->AddrMode);
1006 /* If the instruction has a one byte operand and immediate addressing is
1007 ** allowed but not used, check for an operand expression in the form
1008 ** <label or >label, where label is a far or absolute label. If found,
1009 ** emit a warning. This warning protects against a typo, where the '#'
1010 ** for the immediate operand is omitted.
1012 if (A->Expr && (Ins->AddrMode & AM65_ALL_IMM) &&
1013 (A->AddrModeSet & (AM65_DIR | AM65_ABS | AM65_ABS_LONG)) &&
1014 ExtBytes[A->AddrMode] == 1) {
1016 /* Found, check the expression */
1017 ExprNode* Left = A->Expr->Left;
1018 if ((A->Expr->Op == EXPR_BYTE0 || A->Expr->Op == EXPR_BYTE1) &&
1019 Left->Op == EXPR_SYMBOL &&
1020 GetSymAddrSize (Left->V.Sym) != ADDR_SIZE_ZP) {
1022 /* Output a warning */
1023 Warning (1, "Suspicious address expression");
1027 /* Build the opcode */
1028 A->Opcode = Ins->BaseCode | EATab[Ins->ExtCode][A->AddrMode];
1030 /* If feature force_range is active, and we have immediate addressing mode,
1031 ** limit the expression to the maximum possible value.
1033 if (A->AddrMode == AM65I_IMM_ACCU || A->AddrMode == AM65I_IMM_INDEX ||
1034 A->AddrMode == AM65I_IMM_IMPLICIT) {
1035 if (ForceRange && A->Expr) {
1036 A->Expr = MakeBoundedExpr (A->Expr, ExtBytes[A->AddrMode]);
1046 static void EmitCode (EffAddr* A)
1047 /* Output code for the data in A */
1049 /* Check how many extension bytes are needed and output the instruction */
1050 switch (ExtBytes[A->AddrMode]) {
1057 Emit1 (A->Opcode, A->Expr);
1061 if (CPU == CPU_65816 && (A->AddrModeBit & (AM65_ABS | AM65_ABS_X | AM65_ABS_Y))) {
1062 /* This is a 16 bit mode that uses an address. If in 65816,
1063 ** mode, force this address into 16 bit range to allow
1064 ** addressing inside a 64K segment.
1066 Emit2 (A->Opcode, GenWordExpr (A->Expr));
1068 Emit2 (A->Opcode, A->Expr);
1074 Emit3 (A->Opcode, A->Expr);
1078 Internal ("Invalid operand byte count: %u", ExtBytes[A->AddrMode]);
1085 static long PutImmed8 (const InsDesc* Ins)
1086 /* Parse and emit an immediate 8 bit instruction. Return the value of the
1087 ** operand if it's available and const.
1093 /* Evaluate the addressing mode */
1094 if (EvalEA (Ins, &A) == 0) {
1095 /* An error occurred */
1099 /* If we have an expression and it's const, get it's value */
1101 (void) IsConstExpr (A.Expr, &Val);
1104 /* Check how many extension bytes are needed and output the instruction */
1105 switch (ExtBytes[A.AddrMode]) {
1108 Emit1 (A.Opcode, A.Expr);
1112 Internal ("Invalid operand byte count: %u", ExtBytes[A.AddrMode]);
1115 /* Return the expression value */
1121 static void PutPCRel8 (const InsDesc* Ins)
1122 /* Handle branches with a 8 bit distance */
1124 EmitPCRel (Ins->BaseCode, GenBranchExpr (2), 1);
1129 static void PutPCRel16 (const InsDesc* Ins)
1130 /* Handle branches with an 16 bit distance and PER */
1132 EmitPCRel (Ins->BaseCode, GenBranchExpr (3), 2);
1137 static void PutBlockMove (const InsDesc* Ins)
1138 /* Handle the blockmove instructions (65816) */
1140 Emit0 (Ins->BaseCode);
1141 EmitByte (Expression ());
1143 EmitByte (Expression ());
1148 static void PutBlockTransfer (const InsDesc* Ins)
1149 /* Handle the block transfer instructions (HuC6280) */
1151 Emit0 (Ins->BaseCode);
1152 EmitWord (Expression ());
1154 EmitWord (Expression ());
1156 EmitWord (Expression ());
1161 static void PutBitBranch (const InsDesc* Ins)
1162 /* Handle 65C02 branch on bit condition */
1164 Emit0 (Ins->BaseCode);
1165 EmitByte (Expression ());
1167 EmitSigned (GenBranchExpr (1), 1);
1172 static void PutREP (const InsDesc* Ins)
1173 /* Emit a REP instruction, track register sizes */
1175 /* Use the generic handler */
1176 long Val = PutImmed8 (Ins);
1178 /* We track the status only for the 816 CPU and in smart mode */
1179 if (CPU == CPU_65816 && SmartMode) {
1181 /* Check the range for Val. */
1183 /* We had an error */
1184 Warning (1, "Cannot track processor status byte");
1187 /* Index registers to 16 bit */
1188 ExtBytes[AM65I_IMM_INDEX] = 2;
1191 /* Accu to 16 bit */
1192 ExtBytes[AM65I_IMM_ACCU] = 2;
1200 static void PutSEP (const InsDesc* Ins)
1201 /* Emit a SEP instruction (65816), track register sizes */
1203 /* Use the generic handler */
1204 long Val = PutImmed8 (Ins);
1206 /* We track the status only for the 816 CPU and in smart mode */
1207 if (CPU == CPU_65816 && SmartMode) {
1209 /* Check the range for Val. */
1211 /* We had an error */
1212 Warning (1, "Cannot track processor status byte");
1215 /* Index registers to 8 bit */
1216 ExtBytes[AM65I_IMM_INDEX] = 1;
1220 ExtBytes[AM65I_IMM_ACCU] = 1;
1228 static void PutTAMn (const InsDesc* Ins)
1229 /* Emit a TAMn instruction (HuC6280). Since this is a two byte instruction with
1230 ** implicit addressing mode, the opcode byte in the table is actually the
1231 ** second operand byte. The TAM instruction is the more generic form, it takes
1232 ** an immediate argument.
1235 /* Emit the TAM opcode itself */
1238 /* Emit the argument, which is the opcode from the table */
1239 Emit0 (Ins->BaseCode);
1244 static void PutTMA (const InsDesc* Ins)
1245 /* Emit a TMA instruction (HuC6280) with an immediate argument. Only one bit
1246 ** in the argument byte may be set.
1249 /* Use the generic handler */
1250 long Val = PutImmed8 (Ins);
1252 /* Check the range for Val. */
1254 /* We had an error */
1255 Warning (1, "Cannot check argument of TMA instruction");
1257 /* Make sure just one bit is set */
1258 if ((Val & (Val - 1)) != 0) {
1259 Error ("Argument to TAM must be a power of two");
1266 static void PutTMAn (const InsDesc* Ins)
1267 /* Emit a TMAn instruction (HuC6280). Since this is a two byte instruction with
1268 ** implicit addressing mode, the opcode byte in the table is actually the
1269 ** second operand byte. The TAM instruction is the more generic form, it takes
1270 ** an immediate argument.
1273 /* Emit the TMA opcode itself */
1276 /* Emit the argument, which is the opcode from the table */
1277 Emit0 (Ins->BaseCode);
1282 static void PutTST (const InsDesc* Ins)
1283 /* Emit a TST instruction (HuC6280). */
1288 /* The first argument is always an immediate byte */
1289 if (CurTok.Tok != TOK_HASH) {
1290 ErrorSkip ("Invalid addressing mode");
1294 Arg1 = Expression ();
1296 /* Second argument follows */
1299 /* For the second argument, we use the standard function */
1300 if (EvalEA (Ins, &A)) {
1302 /* No error, output code */
1303 Emit1 (A.Opcode, Arg1);
1305 /* Check how many extension bytes are needed and output the instruction */
1306 switch (ExtBytes[A.AddrMode]) {
1321 static void PutJMP (const InsDesc* Ins)
1322 /* Handle the jump instruction for the 6502. Problem is that these chips have
1323 ** a bug: If the address crosses a page, the upper byte gets not corrected and
1324 ** the instruction will fail. The PutJmp function will add a linker assertion
1325 ** to check for this case and is otherwise identical to PutAll.
1330 /* Evaluate the addressing mode used */
1331 if (EvalEA (Ins, &A)) {
1333 /* Check for indirect addressing */
1334 if (A.AddrModeBit & AM65_ABS_IND) {
1336 /* Compare the low byte of the expression to 0xFF to check for
1337 ** a page cross. Be sure to use a copy of the expression otherwise
1338 ** things will go weird later.
1340 ExprNode* E = GenNE (GenByteExpr (CloneExpr (A.Expr)), 0xFF);
1342 /* Generate the message */
1343 unsigned Msg = GetStringId ("\"jmp (abs)\" across page border");
1345 /* Generate the assertion */
1346 AddAssertion (E, ASSERT_ACT_WARN, Msg);
1349 /* No error, output code */
1356 static void PutRTS (const InsDesc* Ins attribute ((unused)))
1357 /* Handle the RTS instruction for the 816. In smart mode emit a RTL opcode if
1358 ** the enclosing scope is FAR.
1361 if (SmartMode && CurrentScope->AddrSize == ADDR_SIZE_FAR) {
1362 Emit0 (0x6B); /* RTL */
1364 Emit0 (0x60); /* RTS */
1370 static void PutAll (const InsDesc* Ins)
1371 /* Handle all other instructions */
1375 /* Evaluate the addressing mode used */
1376 if (EvalEA (Ins, &A)) {
1377 /* No error, output code */
1384 /*****************************************************************************/
1385 /* Handler functions for SWEET16 */
1386 /*****************************************************************************/
1390 static void PutSweet16 (const InsDesc* Ins)
1391 /* Handle a generic sweet16 instruction */
1395 /* Evaluate the addressing mode used */
1398 /* From the possible addressing modes, remove the ones that are invalid
1399 ** for this instruction or CPU.
1401 A.AddrModeSet &= Ins->AddrMode;
1403 /* Check if we have any adressing modes left */
1404 if (A.AddrModeSet == 0) {
1405 Error ("Illegal addressing mode");
1408 A.AddrMode = BitFind (A.AddrModeSet);
1409 A.AddrModeBit = (0x01UL << A.AddrMode);
1411 /* Build the opcode */
1412 A.Opcode = Ins->BaseCode | Sweet16EATab[Ins->ExtCode][A.AddrMode] | A.Reg;
1414 /* Check how many extension bytes are needed and output the instruction */
1415 switch (Sweet16ExtBytes[A.AddrMode]) {
1422 Emit1 (A.Opcode, A.Expr);
1426 Emit2 (A.Opcode, A.Expr);
1430 Internal ("Invalid operand byte count: %u", Sweet16ExtBytes[A.AddrMode]);
1437 static void PutSweet16Branch (const InsDesc* Ins)
1438 /* Handle a sweet16 branch instruction */
1440 EmitPCRel (Ins->BaseCode, GenBranchExpr (2), 1);
1445 /*****************************************************************************/
1447 /*****************************************************************************/
1451 static int CmpName (const void* Key, const void* Instr)
1452 /* Compare function for bsearch */
1454 return strcmp ((const char*)Key, ((const InsDesc*) Instr)->Mnemonic);
1459 void SetCPU (cpu_t NewCPU)
1462 /* Make sure the parameter is correct */
1463 CHECK (NewCPU < CPU_COUNT);
1465 /* Check if we have support for the new CPU, if so, use it */
1466 if (NewCPU != CPU_UNKNOWN && InsTabs[NewCPU]) {
1468 InsTab = InsTabs[CPU];
1470 Error ("CPU not supported");
1477 /* Return the current CPU */
1484 int FindInstruction (const StrBuf* Ident)
1485 /* Check if Ident is a valid mnemonic. If so, return the index in the
1486 ** instruction table. If not, return -1.
1491 char Key[sizeof (ID->Mnemonic)];
1493 /* Shortcut for the "none" CPU: If there are no instructions to search
1494 ** for, bail out early.
1496 if (InsTab->Count == 0) {
1501 /* Make a copy, and uppercase that copy */
1503 while (I < SB_GetLen (Ident)) {
1504 /* If the identifier is longer than the longest mnemonic, it cannot
1507 if (I >= sizeof (Key) - 1) {
1508 /* Not found, no need for further action */
1511 Key[I] = toupper ((unsigned char)SB_AtUnchecked (Ident, I));
1516 /* Search for the key */
1517 ID = bsearch (Key, InsTab->Ins, InsTab->Count, sizeof (InsDesc), CmpName);
1522 /* Found, return the entry */
1523 return ID - InsTab->Ins;
1529 void HandleInstruction (unsigned Index)
1530 /* Handle the mnemonic with the given index */
1533 PRECONDITION (Index < InsTab->Count);
1535 /* Skip the mnemonic token */
1538 /* Call the handler */
1539 InsTab->Ins[Index].Emit (&InsTab->Ins[Index]);