1 /*****************************************************************************/
5 /* Instruction encoding for the ca65 macroassembler */
9 /* (C) 1998-2009, 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 { "ARR", 0x0800000, 0x6B, 0, PutAll }, /* X */
227 { "ASL", 0x000006e, 0x02, 1, PutAll },
228 { "AXS", 0x0800000, 0xCB, 0, PutAll }, /* X */
229 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
230 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
231 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
232 { "BIT", 0x000000C, 0x00, 2, PutAll },
233 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
234 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
235 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
236 { "BRK", 0x0000001, 0x00, 0, PutAll },
237 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
238 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
239 { "CLC", 0x0000001, 0x18, 0, PutAll },
240 { "CLD", 0x0000001, 0xd8, 0, PutAll },
241 { "CLI", 0x0000001, 0x58, 0, PutAll },
242 { "CLV", 0x0000001, 0xb8, 0, PutAll },
243 { "CMP", 0x080A26C, 0xc0, 0, PutAll },
244 { "CPX", 0x080000C, 0xe0, 1, PutAll },
245 { "CPY", 0x080000C, 0xc0, 1, PutAll },
246 { "DCP", 0x000A26C, 0xC3, 0, PutAll }, /* X */
247 { "DEC", 0x000006C, 0x00, 3, PutAll },
248 { "DEX", 0x0000001, 0xca, 0, PutAll },
249 { "DEY", 0x0000001, 0x88, 0, PutAll },
250 { "EOR", 0x080A26C, 0x40, 0, PutAll },
251 { "INC", 0x000006c, 0x00, 4, PutAll },
252 { "INX", 0x0000001, 0xe8, 0, PutAll },
253 { "INY", 0x0000001, 0xc8, 0, PutAll },
254 { "ISC", 0x000A26C, 0xE3, 0, PutAll }, /* X */
255 { "JAM", 0x0000001, 0x02, 0, PutAll }, /* X */
256 { "JMP", 0x0000808, 0x4c, 6, PutJMP },
257 { "JSR", 0x0000008, 0x20, 7, PutAll },
258 { "LAS", 0x0000200, 0xBB, 0, PutAll }, /* X */
259 { "LAX", 0x000A30C, 0xA3, 1, PutAll }, /* X */
260 { "LDA", 0x080A26C, 0xa0, 0, PutAll },
261 { "LDX", 0x080030C, 0xa2, 1, PutAll },
262 { "LDY", 0x080006C, 0xa0, 1, PutAll },
263 { "LSR", 0x000006F, 0x42, 1, PutAll },
264 { "NOP", 0x0000001, 0xea, 0, PutAll },
265 { "ORA", 0x080A26C, 0x00, 0, PutAll },
266 { "PHA", 0x0000001, 0x48, 0, PutAll },
267 { "PHP", 0x0000001, 0x08, 0, PutAll },
268 { "PLA", 0x0000001, 0x68, 0, PutAll },
269 { "PLP", 0x0000001, 0x28, 0, PutAll },
270 { "RLA", 0x000A26C, 0x23, 0, PutAll }, /* X */
271 { "ROL", 0x000006F, 0x22, 1, PutAll },
272 { "ROR", 0x000006F, 0x62, 1, PutAll },
273 { "RRA", 0x000A26C, 0x63, 0, PutAll }, /* X */
274 { "RTI", 0x0000001, 0x40, 0, PutAll },
275 { "RTS", 0x0000001, 0x60, 0, PutAll },
276 { "SAX", 0x000810C, 0x83, 1, PutAll }, /* X */
277 { "SBC", 0x080A26C, 0xe0, 0, PutAll },
278 { "SEC", 0x0000001, 0x38, 0, PutAll },
279 { "SED", 0x0000001, 0xf8, 0, PutAll },
280 { "SEI", 0x0000001, 0x78, 0, PutAll },
281 { "SLO", 0x000A26C, 0x03, 0, PutAll }, /* X */
282 { "SRE", 0x000A26C, 0x43, 0, PutAll }, /* X */
283 { "STA", 0x000A26C, 0x80, 0, PutAll },
284 { "STX", 0x000010c, 0x82, 1, PutAll },
285 { "STY", 0x000002c, 0x80, 1, PutAll },
286 { "TAX", 0x0000001, 0xaa, 0, PutAll },
287 { "TAY", 0x0000001, 0xa8, 0, PutAll },
288 { "TSX", 0x0000001, 0xba, 0, PutAll },
289 { "TXA", 0x0000001, 0x8a, 0, PutAll },
290 { "TXS", 0x0000001, 0x9a, 0, PutAll },
291 { "TYA", 0x0000001, 0x98, 0, PutAll }
295 /* Instruction table for the 65SC02 */
296 static const struct {
300 sizeof (InsTab65SC02.Ins) / sizeof (InsTab65SC02.Ins[0]),
302 { "ADC", 0x080A66C, 0x60, 0, PutAll },
303 { "AND", 0x080A66C, 0x20, 0, PutAll },
304 { "ASL", 0x000006e, 0x02, 1, PutAll },
305 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
306 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
307 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
308 { "BIT", 0x0A0006C, 0x00, 2, PutAll },
309 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
310 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
311 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
312 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
313 { "BRK", 0x0000001, 0x00, 0, PutAll },
314 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
315 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
316 { "CLC", 0x0000001, 0x18, 0, PutAll },
317 { "CLD", 0x0000001, 0xd8, 0, PutAll },
318 { "CLI", 0x0000001, 0x58, 0, PutAll },
319 { "CLV", 0x0000001, 0xb8, 0, PutAll },
320 { "CMP", 0x080A66C, 0xc0, 0, PutAll },
321 { "CPX", 0x080000C, 0xe0, 1, PutAll },
322 { "CPY", 0x080000C, 0xc0, 1, PutAll },
323 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
324 { "DEC", 0x000006F, 0x00, 3, PutAll },
325 { "DEX", 0x0000001, 0xca, 0, PutAll },
326 { "DEY", 0x0000001, 0x88, 0, PutAll },
327 { "EOR", 0x080A66C, 0x40, 0, PutAll },
328 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
329 { "INC", 0x000006f, 0x00, 4, PutAll },
330 { "INX", 0x0000001, 0xe8, 0, PutAll },
331 { "INY", 0x0000001, 0xc8, 0, PutAll },
332 { "JMP", 0x0010808, 0x4c, 6, PutAll },
333 { "JSR", 0x0000008, 0x20, 7, PutAll },
334 { "LDA", 0x080A66C, 0xa0, 0, PutAll },
335 { "LDX", 0x080030C, 0xa2, 1, PutAll },
336 { "LDY", 0x080006C, 0xa0, 1, PutAll },
337 { "LSR", 0x000006F, 0x42, 1, PutAll },
338 { "NOP", 0x0000001, 0xea, 0, PutAll },
339 { "ORA", 0x080A66C, 0x00, 0, PutAll },
340 { "PHA", 0x0000001, 0x48, 0, PutAll },
341 { "PHP", 0x0000001, 0x08, 0, PutAll },
342 { "PHX", 0x0000001, 0xda, 0, PutAll },
343 { "PHY", 0x0000001, 0x5a, 0, PutAll },
344 { "PLA", 0x0000001, 0x68, 0, PutAll },
345 { "PLP", 0x0000001, 0x28, 0, PutAll },
346 { "PLX", 0x0000001, 0xfa, 0, PutAll },
347 { "PLY", 0x0000001, 0x7a, 0, PutAll },
348 { "ROL", 0x000006F, 0x22, 1, PutAll },
349 { "ROR", 0x000006F, 0x62, 1, PutAll },
350 { "RTI", 0x0000001, 0x40, 0, PutAll },
351 { "RTS", 0x0000001, 0x60, 0, PutAll },
352 { "SBC", 0x080A66C, 0xe0, 0, PutAll },
353 { "SEC", 0x0000001, 0x38, 0, PutAll },
354 { "SED", 0x0000001, 0xf8, 0, PutAll },
355 { "SEI", 0x0000001, 0x78, 0, PutAll },
356 { "STA", 0x000A66C, 0x80, 0, PutAll },
357 { "STX", 0x000010c, 0x82, 1, PutAll },
358 { "STY", 0x000002c, 0x80, 1, PutAll },
359 { "STZ", 0x000006c, 0x04, 5, PutAll },
360 { "TAX", 0x0000001, 0xaa, 0, PutAll },
361 { "TAY", 0x0000001, 0xa8, 0, PutAll },
362 { "TRB", 0x000000c, 0x10, 1, PutAll },
363 { "TSB", 0x000000c, 0x00, 1, PutAll },
364 { "TSX", 0x0000001, 0xba, 0, PutAll },
365 { "TXA", 0x0000001, 0x8a, 0, PutAll },
366 { "TXS", 0x0000001, 0x9a, 0, PutAll },
367 { "TYA", 0x0000001, 0x98, 0, PutAll }
371 /* Instruction table for the 65C02 */
372 static const struct {
376 sizeof (InsTab65C02.Ins) / sizeof (InsTab65C02.Ins[0]),
378 { "ADC", 0x080A66C, 0x60, 0, PutAll },
379 { "AND", 0x080A66C, 0x20, 0, PutAll },
380 { "ASL", 0x000006e, 0x02, 1, PutAll },
381 { "BBR0", 0x0000000, 0x0F, 0, PutBitBranch },
382 { "BBR1", 0x0000000, 0x1F, 0, PutBitBranch },
383 { "BBR2", 0x0000000, 0x2F, 0, PutBitBranch },
384 { "BBR3", 0x0000000, 0x3F, 0, PutBitBranch },
385 { "BBR4", 0x0000000, 0x4F, 0, PutBitBranch },
386 { "BBR5", 0x0000000, 0x5F, 0, PutBitBranch },
387 { "BBR6", 0x0000000, 0x6F, 0, PutBitBranch },
388 { "BBR7", 0x0000000, 0x7F, 0, PutBitBranch },
389 { "BBS0", 0x0000000, 0x8F, 0, PutBitBranch },
390 { "BBS1", 0x0000000, 0x9F, 0, PutBitBranch },
391 { "BBS2", 0x0000000, 0xAF, 0, PutBitBranch },
392 { "BBS3", 0x0000000, 0xBF, 0, PutBitBranch },
393 { "BBS4", 0x0000000, 0xCF, 0, PutBitBranch },
394 { "BBS5", 0x0000000, 0xDF, 0, PutBitBranch },
395 { "BBS6", 0x0000000, 0xEF, 0, PutBitBranch },
396 { "BBS7", 0x0000000, 0xFF, 0, PutBitBranch },
397 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
398 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
399 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
400 { "BIT", 0x0A0006C, 0x00, 2, PutAll },
401 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
402 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
403 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
404 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
405 { "BRK", 0x0000001, 0x00, 0, PutAll },
406 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
407 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
408 { "CLC", 0x0000001, 0x18, 0, PutAll },
409 { "CLD", 0x0000001, 0xd8, 0, PutAll },
410 { "CLI", 0x0000001, 0x58, 0, PutAll },
411 { "CLV", 0x0000001, 0xb8, 0, PutAll },
412 { "CMP", 0x080A66C, 0xc0, 0, PutAll },
413 { "CPX", 0x080000C, 0xe0, 1, PutAll },
414 { "CPY", 0x080000C, 0xc0, 1, PutAll },
415 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
416 { "DEC", 0x000006F, 0x00, 3, PutAll },
417 { "DEX", 0x0000001, 0xca, 0, PutAll },
418 { "DEY", 0x0000001, 0x88, 0, PutAll },
419 { "EOR", 0x080A66C, 0x40, 0, PutAll },
420 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
421 { "INC", 0x000006f, 0x00, 4, PutAll },
422 { "INX", 0x0000001, 0xe8, 0, PutAll },
423 { "INY", 0x0000001, 0xc8, 0, PutAll },
424 { "JMP", 0x0010808, 0x4c, 6, PutAll },
425 { "JSR", 0x0000008, 0x20, 7, PutAll },
426 { "LDA", 0x080A66C, 0xa0, 0, PutAll },
427 { "LDX", 0x080030C, 0xa2, 1, PutAll },
428 { "LDY", 0x080006C, 0xa0, 1, PutAll },
429 { "LSR", 0x000006F, 0x42, 1, PutAll },
430 { "NOP", 0x0000001, 0xea, 0, PutAll },
431 { "ORA", 0x080A66C, 0x00, 0, PutAll },
432 { "PHA", 0x0000001, 0x48, 0, PutAll },
433 { "PHP", 0x0000001, 0x08, 0, PutAll },
434 { "PHX", 0x0000001, 0xda, 0, PutAll },
435 { "PHY", 0x0000001, 0x5a, 0, PutAll },
436 { "PLA", 0x0000001, 0x68, 0, PutAll },
437 { "PLP", 0x0000001, 0x28, 0, PutAll },
438 { "PLX", 0x0000001, 0xfa, 0, PutAll },
439 { "PLY", 0x0000001, 0x7a, 0, PutAll },
440 { "RMB0", 0x0000004, 0x07, 1, PutAll },
441 { "RMB1", 0x0000004, 0x17, 1, PutAll },
442 { "RMB2", 0x0000004, 0x27, 1, PutAll },
443 { "RMB3", 0x0000004, 0x37, 1, PutAll },
444 { "RMB4", 0x0000004, 0x47, 1, PutAll },
445 { "RMB5", 0x0000004, 0x57, 1, PutAll },
446 { "RMB6", 0x0000004, 0x67, 1, PutAll },
447 { "RMB7", 0x0000004, 0x77, 1, PutAll },
448 { "ROL", 0x000006F, 0x22, 1, PutAll },
449 { "ROR", 0x000006F, 0x62, 1, PutAll },
450 { "RTI", 0x0000001, 0x40, 0, PutAll },
451 { "RTS", 0x0000001, 0x60, 0, PutAll },
452 { "SBC", 0x080A66C, 0xe0, 0, PutAll },
453 { "SEC", 0x0000001, 0x38, 0, PutAll },
454 { "SED", 0x0000001, 0xf8, 0, PutAll },
455 { "SEI", 0x0000001, 0x78, 0, PutAll },
456 { "SMB0", 0x0000004, 0x87, 1, PutAll },
457 { "SMB1", 0x0000004, 0x97, 1, PutAll },
458 { "SMB2", 0x0000004, 0xA7, 1, PutAll },
459 { "SMB3", 0x0000004, 0xB7, 1, PutAll },
460 { "SMB4", 0x0000004, 0xC7, 1, PutAll },
461 { "SMB5", 0x0000004, 0xD7, 1, PutAll },
462 { "SMB6", 0x0000004, 0xE7, 1, PutAll },
463 { "SMB7", 0x0000004, 0xF7, 1, PutAll },
464 { "STA", 0x000A66C, 0x80, 0, PutAll },
465 { "STX", 0x000010c, 0x82, 1, PutAll },
466 { "STY", 0x000002c, 0x80, 1, PutAll },
467 { "STZ", 0x000006c, 0x04, 5, PutAll },
468 { "TAX", 0x0000001, 0xaa, 0, PutAll },
469 { "TAY", 0x0000001, 0xa8, 0, PutAll },
470 { "TRB", 0x000000c, 0x10, 1, PutAll },
471 { "TSB", 0x000000c, 0x00, 1, PutAll },
472 { "TSX", 0x0000001, 0xba, 0, PutAll },
473 { "TXA", 0x0000001, 0x8a, 0, PutAll },
474 { "TXS", 0x0000001, 0x9a, 0, PutAll },
475 { "TYA", 0x0000001, 0x98, 0, PutAll }
479 /* Instruction table for the 65816 */
480 static const struct {
484 sizeof (InsTab65816.Ins) / sizeof (InsTab65816.Ins[0]),
486 { "ADC", 0x0b8f6fc, 0x60, 0, PutAll },
487 { "AND", 0x0b8f6fc, 0x20, 0, PutAll },
488 { "ASL", 0x000006e, 0x02, 1, PutAll },
489 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
490 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
491 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
492 { "BIT", 0x0a0006c, 0x00, 2, PutAll },
493 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
494 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
495 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
496 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
497 { "BRK", 0x0000001, 0x00, 0, PutAll },
498 { "BRL", 0x0040000, 0x82, 0, PutPCRel16 },
499 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
500 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
501 { "CLC", 0x0000001, 0x18, 0, PutAll },
502 { "CLD", 0x0000001, 0xd8, 0, PutAll },
503 { "CLI", 0x0000001, 0x58, 0, PutAll },
504 { "CLV", 0x0000001, 0xb8, 0, PutAll },
505 { "CMP", 0x0b8f6fc, 0xc0, 0, PutAll },
506 { "COP", 0x0000004, 0x02, 6, PutAll },
507 { "CPA", 0x0b8f6fc, 0xc0, 0, PutAll }, /* == CMP */
508 { "CPX", 0x0c0000c, 0xe0, 1, PutAll },
509 { "CPY", 0x0c0000c, 0xc0, 1, PutAll },
510 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
511 { "DEC", 0x000006F, 0x00, 3, PutAll },
512 { "DEX", 0x0000001, 0xca, 0, PutAll },
513 { "DEY", 0x0000001, 0x88, 0, PutAll },
514 { "EOR", 0x0b8f6fc, 0x40, 0, PutAll },
515 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
516 { "INC", 0x000006F, 0x00, 4, PutAll },
517 { "INX", 0x0000001, 0xe8, 0, PutAll },
518 { "INY", 0x0000001, 0xc8, 0, PutAll },
519 { "JML", 0x0000810, 0x5c, 1, PutAll },
520 { "JMP", 0x0010818, 0x4c, 6, PutAll },
521 { "JSL", 0x0000010, 0x20, 7, PutAll },
522 { "JSR", 0x0010018, 0x20, 7, PutAll },
523 { "LDA", 0x0b8f6fc, 0xa0, 0, PutAll },
524 { "LDX", 0x0c0030c, 0xa2, 1, PutAll },
525 { "LDY", 0x0c0006c, 0xa0, 1, PutAll },
526 { "LSR", 0x000006F, 0x42, 1, PutAll },
527 { "MVN", 0x1000000, 0x54, 0, PutBlockMove },
528 { "MVP", 0x1000000, 0x44, 0, PutBlockMove },
529 { "NOP", 0x0000001, 0xea, 0, PutAll },
530 { "ORA", 0x0b8f6fc, 0x00, 0, PutAll },
531 { "PEA", 0x0000008, 0xf4, 6, PutAll },
532 { "PEI", 0x0000400, 0xd4, 1, PutAll },
533 { "PER", 0x0040000, 0x62, 0, PutPCRel16 },
534 { "PHA", 0x0000001, 0x48, 0, PutAll },
535 { "PHB", 0x0000001, 0x8b, 0, PutAll },
536 { "PHD", 0x0000001, 0x0b, 0, PutAll },
537 { "PHK", 0x0000001, 0x4b, 0, PutAll },
538 { "PHP", 0x0000001, 0x08, 0, PutAll },
539 { "PHX", 0x0000001, 0xda, 0, PutAll },
540 { "PHY", 0x0000001, 0x5a, 0, PutAll },
541 { "PLA", 0x0000001, 0x68, 0, PutAll },
542 { "PLB", 0x0000001, 0xab, 0, PutAll },
543 { "PLD", 0x0000001, 0x2b, 0, PutAll },
544 { "PLP", 0x0000001, 0x28, 0, PutAll },
545 { "PLX", 0x0000001, 0xfa, 0, PutAll },
546 { "PLY", 0x0000001, 0x7a, 0, PutAll },
547 { "REP", 0x0800000, 0xc2, 1, PutREP },
548 { "ROL", 0x000006F, 0x22, 1, PutAll },
549 { "ROR", 0x000006F, 0x62, 1, PutAll },
550 { "RTI", 0x0000001, 0x40, 0, PutAll },
551 { "RTL", 0x0000001, 0x6b, 0, PutAll },
552 { "RTS", 0x0000001, 0x60, 0, PutRTS },
553 { "SBC", 0x0b8f6fc, 0xe0, 0, PutAll },
554 { "SEC", 0x0000001, 0x38, 0, PutAll },
555 { "SED", 0x0000001, 0xf8, 0, PutAll },
556 { "SEI", 0x0000001, 0x78, 0, PutAll },
557 { "SEP", 0x0800000, 0xe2, 1, PutSEP },
558 { "STA", 0x018f6fc, 0x80, 0, PutAll },
559 { "STP", 0x0000001, 0xdb, 0, PutAll },
560 { "STX", 0x000010c, 0x82, 1, PutAll },
561 { "STY", 0x000002c, 0x80, 1, PutAll },
562 { "STZ", 0x000006c, 0x04, 5, PutAll },
563 { "SWA", 0x0000001, 0xeb, 0, PutAll }, /* == XBA */
564 { "TAD", 0x0000001, 0x5b, 0, PutAll }, /* == TCD */
565 { "TAS", 0x0000001, 0x1b, 0, PutAll }, /* == TCS */
566 { "TAX", 0x0000001, 0xaa, 0, PutAll },
567 { "TAY", 0x0000001, 0xa8, 0, PutAll },
568 { "TCD", 0x0000001, 0x5b, 0, PutAll },
569 { "TCS", 0x0000001, 0x1b, 0, PutAll },
570 { "TDA", 0x0000001, 0x7b, 0, PutAll }, /* == TDC */
571 { "TDC", 0x0000001, 0x7b, 0, PutAll },
572 { "TRB", 0x000000c, 0x10, 1, PutAll },
573 { "TSA", 0x0000001, 0x3b, 0, PutAll }, /* == TSC */
574 { "TSB", 0x000000c, 0x00, 1, PutAll },
575 { "TSC", 0x0000001, 0x3b, 0, PutAll },
576 { "TSX", 0x0000001, 0xba, 0, PutAll },
577 { "TXA", 0x0000001, 0x8a, 0, PutAll },
578 { "TXS", 0x0000001, 0x9a, 0, PutAll },
579 { "TXY", 0x0000001, 0x9b, 0, PutAll },
580 { "TYA", 0x0000001, 0x98, 0, PutAll },
581 { "TYX", 0x0000001, 0xbb, 0, PutAll },
582 { "WAI", 0x0000001, 0xcb, 0, PutAll },
583 { "XBA", 0x0000001, 0xeb, 0, PutAll },
584 { "XCE", 0x0000001, 0xfb, 0, PutAll }
589 /* Table for the SUNPLUS CPU */
590 #include "sunplus.inc"
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 { "SBC", 0x080A66C, 0xe0, 0, PutAll },
717 { "SAX", 0x0000001, 0x22, 0, PutAll },
718 { "SAY", 0x0000001, 0x42, 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,
785 (const InsTable*) &InsTabSunPlus,
789 (const InsTable*) &InsTabSweet16,
790 (const InsTable*) &InsTabHuC6280,
792 const InsTable* InsTab = (const InsTable*) &InsTab6502;
794 /* Table to build the effective 65xx opcode from a base opcode and an
797 static unsigned char EATab[10][AM65I_COUNT] = {
799 0x00, 0x00, 0x05, 0x0D, 0x0F, 0x15, 0x1D, 0x1F,
800 0x00, 0x19, 0x12, 0x00, 0x07, 0x11, 0x17, 0x01,
801 0x00, 0x00, 0x00, 0x03, 0x13, 0x09, 0x00, 0x09,
805 0x08, 0x08, 0x04, 0x0C, 0x00, 0x14, 0x1C, 0x00,
806 0x14, 0x1C, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00,
807 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
811 0x00, 0x00, 0x24, 0x2C, 0x0F, 0x34, 0x3C, 0x00,
812 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
813 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00,
817 0x3A, 0x3A, 0xC6, 0xCE, 0x00, 0xD6, 0xDE, 0x00,
818 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
819 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
823 0x1A, 0x1A, 0xE6, 0xEE, 0x00, 0xF6, 0xFE, 0x00,
824 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
825 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
829 0x00, 0x00, 0x60, 0x98, 0x00, 0x70, 0x9E, 0x00,
830 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
831 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
835 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
836 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
837 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
841 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
842 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
843 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
847 0x00, 0x40, 0x01, 0x41, 0x00, 0x09, 0x49, 0x00,
848 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00,
849 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
853 0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x30, 0x00,
854 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
855 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
860 /* Table to build the effective SWEET16 opcode from a base opcode and an
863 static unsigned char Sweet16EATab[2][AMSW16I_COUNT] = {
865 0x00, 0x00, 0x00, 0x00, 0x00,
868 0x00, 0x00, 0x00, 0x40, 0x20,
872 /* Table that encodes the additional bytes for each 65xx instruction */
873 unsigned char ExtBytes[AM65I_COUNT] = {
878 3, /* Absolute long */
881 3, /* Absolute long,X */
890 2, /* (Absolute,X) */
891 1, /* Relative short */
892 2, /* Relative long */
895 1, /* Immidiate accu */
896 1, /* Immidiate index */
897 1, /* Immidiate byte */
898 2, /* Blockmove (65816) */
899 7, /* Block transfer (HuC6280) */
902 /* Table that encodes the additional bytes for each SWEET16 instruction */
903 static unsigned char Sweet16ExtBytes[AMSW16I_COUNT] = {
913 /*****************************************************************************/
914 /* Handler functions for 6502 derivates */
915 /*****************************************************************************/
919 static int EvalEA (const InsDesc* Ins, EffAddr* A)
920 /* Evaluate the effective address. All fields in A will be valid after calling
921 * this function. The function returns true on success and false on errors.
924 /* Get the set of possible addressing modes */
927 /* From the possible addressing modes, remove the ones that are invalid
928 * for this instruction or CPU.
930 A->AddrModeSet &= Ins->AddrMode;
932 /* If we have an expression, check it and remove any addressing modes that
933 * are too small for the expression size. Since we have to study the
934 * expression anyway, do also replace it by a simpler one if possible.
940 /* Study the expression */
941 StudyExpr (A->Expr, &ED);
943 /* Simplify it if possible */
944 A->Expr = SimplifyExpr (A->Expr, &ED);
946 if (ED.AddrSize == ADDR_SIZE_DEFAULT) {
947 /* If we don't know how big the expression is, assume the
948 * default address size for data. If this default address
949 * size is unequal to zero page addressing, but zero page
950 * addressing is allowed by the instruction, mark all symbols
951 * in the expression tree. This mark will be checked at end
952 * of assembly, and a warning is issued, if a zero page symbol
953 * was guessed wrong here.
955 ED.AddrSize = DataAddrSize;
956 if (ED.AddrSize > ADDR_SIZE_ZP && (A->AddrModeSet & AM65_SET_ZP)) {
957 ExprGuessedAddrSize (A->Expr, ADDR_SIZE_ZP);
962 switch (ED.AddrSize) {
965 A->AddrModeSet &= ~AM65_SET_ZP;
969 A->AddrModeSet &= ~(AM65_SET_ZP | AM65_SET_ABS);
973 /* Free any resource associated with the expression desc */
977 /* Check if we have any adressing modes left */
978 if (A->AddrModeSet == 0) {
979 Error ("Illegal addressing mode");
982 A->AddrMode = BitFind (A->AddrModeSet);
983 A->AddrModeBit = (0x01UL << A->AddrMode);
985 /* If the instruction has a one byte operand and immediate addressing is
986 * allowed but not used, check for an operand expression in the form
987 * <label or >label, where label is a far or absolute label. If found,
988 * emit a warning. This warning protects against a typo, where the '#'
989 * for the immediate operand is omitted.
991 if (A->Expr && (Ins->AddrMode & AM65_IMM) &&
992 (A->AddrModeSet & (AM65_DIR | AM65_ABS | AM65_ABS_LONG)) &&
993 ExtBytes[A->AddrMode] == 1) {
995 /* Found, check the expression */
996 ExprNode* Left = A->Expr->Left;
997 if ((A->Expr->Op == EXPR_BYTE0 || A->Expr->Op == EXPR_BYTE1) &&
998 Left->Op == EXPR_SYMBOL &&
999 GetSymAddrSize (Left->V.Sym) != ADDR_SIZE_ZP) {
1001 /* Output a warning */
1002 Warning (1, "Suspicious address expression");
1006 /* Build the opcode */
1007 A->Opcode = Ins->BaseCode | EATab[Ins->ExtCode][A->AddrMode];
1015 static void EmitCode (EffAddr* A)
1016 /* Output code for the data in A */
1018 /* Check how many extension bytes are needed and output the instruction */
1019 switch (ExtBytes[A->AddrMode]) {
1026 Emit1 (A->Opcode, A->Expr);
1030 if (CPU == CPU_65816 && (A->AddrModeBit & (AM65_ABS | AM65_ABS_X | AM65_ABS_Y))) {
1031 /* This is a 16 bit mode that uses an address. If in 65816,
1032 * mode, force this address into 16 bit range to allow
1033 * addressing inside a 64K segment.
1035 Emit2 (A->Opcode, GenWordExpr (A->Expr));
1037 Emit2 (A->Opcode, A->Expr);
1043 Emit3 (A->Opcode, A->Expr);
1047 Internal ("Invalid operand byte count: %u", ExtBytes[A->AddrMode]);
1054 static long PutImmed8 (const InsDesc* Ins)
1055 /* Parse and emit an immediate 8 bit instruction. Return the value of the
1056 * operand if it's available and const.
1062 /* Evaluate the addressing mode */
1063 if (EvalEA (Ins, &A) == 0) {
1064 /* An error occurred */
1068 /* If we have an expression and it's const, get it's value */
1070 (void) IsConstExpr (A.Expr, &Val);
1073 /* Check how many extension bytes are needed and output the instruction */
1074 switch (ExtBytes[A.AddrMode]) {
1077 Emit1 (A.Opcode, A.Expr);
1081 Internal ("Invalid operand byte count: %u", ExtBytes[A.AddrMode]);
1084 /* Return the expression value */
1090 static void PutPCRel8 (const InsDesc* Ins)
1091 /* Handle branches with a 8 bit distance */
1093 EmitPCRel (Ins->BaseCode, GenBranchExpr (2), 1);
1098 static void PutPCRel16 (const InsDesc* Ins)
1099 /* Handle branches with an 16 bit distance and PER */
1101 EmitPCRel (Ins->BaseCode, GenBranchExpr (3), 2);
1106 static void PutBlockMove (const InsDesc* Ins)
1107 /* Handle the blockmove instructions (65816) */
1109 Emit0 (Ins->BaseCode);
1110 EmitByte (Expression ());
1112 EmitByte (Expression ());
1117 static void PutBlockTransfer (const InsDesc* Ins)
1118 /* Handle the block transfer instructions (HuC6280) */
1120 Emit0 (Ins->BaseCode);
1121 EmitWord (Expression ());
1123 EmitWord (Expression ());
1125 EmitWord (Expression ());
1130 static void PutBitBranch (const InsDesc* Ins)
1131 /* Handle 65C02 branch on bit condition */
1133 Emit0 (Ins->BaseCode);
1134 EmitByte (Expression ());
1136 EmitSigned (GenBranchExpr (1), 1);
1141 static void PutREP (const InsDesc* Ins)
1142 /* Emit a REP instruction, track register sizes */
1144 /* Use the generic handler */
1145 long Val = PutImmed8 (Ins);
1147 /* We track the status only for the 816 CPU and in smart mode */
1148 if (CPU == CPU_65816 && SmartMode) {
1150 /* Check the range for Val. */
1152 /* We had an error */
1153 Warning (1, "Cannot track processor status byte");
1156 /* Index registers to 16 bit */
1157 ExtBytes[AM65I_IMM_INDEX] = 2;
1160 /* Accu to 16 bit */
1161 ExtBytes[AM65I_IMM_ACCU] = 2;
1169 static void PutSEP (const InsDesc* Ins)
1170 /* Emit a SEP instruction (65816), track register sizes */
1172 /* Use the generic handler */
1173 long Val = PutImmed8 (Ins);
1175 /* We track the status only for the 816 CPU and in smart mode */
1176 if (CPU == CPU_65816 && SmartMode) {
1178 /* Check the range for Val. */
1180 /* We had an error */
1181 Warning (1, "Cannot track processor status byte");
1184 /* Index registers to 8 bit */
1185 ExtBytes[AM65I_IMM_INDEX] = 1;
1189 ExtBytes[AM65I_IMM_ACCU] = 1;
1197 static void PutTAMn (const InsDesc* Ins)
1198 /* Emit a TAMn instruction (HuC6280). Since this is a two byte instruction with
1199 * implicit addressing mode, the opcode byte in the table is actually the
1200 * second operand byte. The TAM instruction is the more generic form, it takes
1201 * an immediate argument.
1204 /* Emit the TAM opcode itself */
1207 /* Emit the argument, which is the opcode from the table */
1208 Emit0 (Ins->BaseCode);
1213 static void PutTMA (const InsDesc* Ins)
1214 /* Emit a TMA instruction (HuC6280) with an immediate argument. Only one bit
1215 * in the argument byte may be set.
1218 /* Use the generic handler */
1219 long Val = PutImmed8 (Ins);
1221 /* Check the range for Val. */
1223 /* We had an error */
1224 Warning (1, "Cannot check argument of TMA instruction");
1226 /* Make sure just one bit is set */
1227 if ((Val & (Val - 1)) != 0) {
1228 Error ("Argument to TAM must be a power of two");
1235 static void PutTMAn (const InsDesc* Ins)
1236 /* Emit a TMAn instruction (HuC6280). Since this is a two byte instruction with
1237 * implicit addressing mode, the opcode byte in the table is actually the
1238 * second operand byte. The TAM instruction is the more generic form, it takes
1239 * an immediate argument.
1242 /* Emit the TMA opcode itself */
1245 /* Emit the argument, which is the opcode from the table */
1246 Emit0 (Ins->BaseCode);
1251 static void PutTST (const InsDesc* Ins)
1252 /* Emit a TST instruction (HuC6280). */
1257 /* The first argument is always an immediate byte */
1258 if (Tok != TOK_HASH) {
1259 ErrorSkip ("Invalid addressing mode");
1263 Arg1 = Expression ();
1265 /* Second argument follows */
1268 /* For the second argument, we use the standard function */
1269 if (EvalEA (Ins, &A)) {
1271 /* No error, output code */
1272 Emit1 (A.Opcode, Arg1);
1274 /* Check how many extension bytes are needed and output the instruction */
1275 switch (ExtBytes[A.AddrMode]) {
1290 static void PutJMP (const InsDesc* Ins)
1291 /* Handle the jump instruction for the 6502. Problem is that these chips have
1292 * a bug: If the address crosses a page, the upper byte gets not corrected and
1293 * the instruction will fail. The PutJmp function will add a linker assertion
1294 * to check for this case and is otherwise identical to PutAll.
1299 /* Evaluate the addressing mode used */
1300 if (EvalEA (Ins, &A)) {
1302 /* Check for indirect addressing */
1303 if (A.AddrModeBit & AM65_ABS_IND) {
1305 /* Compare the low byte of the expression to 0xFF to check for
1306 * a page cross. Be sure to use a copy of the expression otherwise
1307 * things will go weird later.
1309 ExprNode* E = GenNE (GenByteExpr (CloneExpr (A.Expr)), 0xFF);
1311 /* Generate the message */
1312 unsigned Msg = GetStringId ("\"jmp (abs)\" across page border");
1314 /* Generate the assertion */
1315 AddAssertion (E, ASSERT_ACT_WARN, Msg);
1318 /* No error, output code */
1325 static void PutRTS (const InsDesc* Ins attribute ((unused)))
1326 /* Handle the RTS instruction for the 816. In smart mode emit a RTL opcode if
1327 * the enclosing scope is FAR.
1330 if (SmartMode && CurrentScope->AddrSize == ADDR_SIZE_FAR) {
1331 Emit0 (0x6B); /* RTL */
1333 Emit0 (0x60); /* RTS */
1339 static void PutAll (const InsDesc* Ins)
1340 /* Handle all other instructions */
1344 /* Evaluate the addressing mode used */
1345 if (EvalEA (Ins, &A)) {
1346 /* No error, output code */
1353 /*****************************************************************************/
1354 /* Handler functions for SWEET16 */
1355 /*****************************************************************************/
1359 static void PutSweet16 (const InsDesc* Ins)
1360 /* Handle a generic sweet16 instruction */
1364 /* Evaluate the addressing mode used */
1367 /* From the possible addressing modes, remove the ones that are invalid
1368 * for this instruction or CPU.
1370 A.AddrModeSet &= Ins->AddrMode;
1372 /* Check if we have any adressing modes left */
1373 if (A.AddrModeSet == 0) {
1374 Error ("Illegal addressing mode");
1377 A.AddrMode = BitFind (A.AddrModeSet);
1378 A.AddrModeBit = (0x01UL << A.AddrMode);
1380 /* Build the opcode */
1381 A.Opcode = Ins->BaseCode | Sweet16EATab[Ins->ExtCode][A.AddrMode] | A.Reg;
1383 /* Check how many extension bytes are needed and output the instruction */
1384 switch (Sweet16ExtBytes[A.AddrMode]) {
1391 Emit1 (A.Opcode, A.Expr);
1395 Emit2 (A.Opcode, A.Expr);
1399 Internal ("Invalid operand byte count: %u", Sweet16ExtBytes[A.AddrMode]);
1406 static void PutSweet16Branch (const InsDesc* Ins)
1407 /* Handle a sweet16 branch instruction */
1409 EmitPCRel (Ins->BaseCode, GenBranchExpr (2), 1);
1414 /*****************************************************************************/
1416 /*****************************************************************************/
1420 static int CmpName (const void* Key, const void* Instr)
1421 /* Compare function for bsearch */
1423 return strcmp ((const char*)Key, ((const InsDesc*) Instr)->Mnemonic);
1428 void SetCPU (cpu_t NewCPU)
1431 /* Make sure the parameter is correct */
1432 CHECK (NewCPU < CPU_COUNT);
1434 /* Check if we have support for the new CPU, if so, use it */
1435 if (NewCPU != CPU_UNKNOWN && InsTabs[NewCPU]) {
1437 InsTab = InsTabs[CPU];
1439 Error ("CPU not supported");
1446 /* Return the current CPU */
1453 int FindInstruction (const StrBuf* Ident)
1454 /* Check if Ident is a valid mnemonic. If so, return the index in the
1455 * instruction table. If not, return -1.
1460 char Key[sizeof (ID->Mnemonic)];
1462 /* Shortcut for the "none" CPU: If there are no instructions to search
1463 * for, bail out early.
1465 if (InsTab->Count == 0) {
1470 /* Make a copy, and uppercase that copy */
1472 while (I < SB_GetLen (Ident)) {
1473 /* If the identifier is longer than the longest mnemonic, it cannot
1476 if (I >= sizeof (Key) - 1) {
1477 /* Not found, no need for further action */
1480 Key[I] = toupper ((unsigned char)SB_AtUnchecked (Ident, I));
1485 /* Search for the key */
1486 ID = bsearch (Key, InsTab->Ins, InsTab->Count, sizeof (InsDesc), CmpName);
1491 /* Found, return the entry */
1492 return ID - InsTab->Ins;
1498 void HandleInstruction (unsigned Index)
1499 /* Handle the mnemonic with the given index */
1502 PRECONDITION (Index < InsTab->Count);
1504 /* Skip the mnemonic token */
1507 /* Call the handler */
1508 InsTab->Ins[Index].Emit (&InsTab->Ins[Index]);