]> git.sur5r.net Git - cc65/blob - src/ca65/instr.c
Added the remaining HuC6280 instructions
[cc65] / src / ca65 / instr.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  instr.c                                  */
4 /*                                                                           */
5 /*             Instruction encoding for the ca65 macroassembler              */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2004 Ullrich von Bassewitz                                       */
10 /*               Römerstraße 52                                              */
11 /*               D-70794 Filderstadt                                         */
12 /* EMail:        uz@cc65.org                                                 */
13 /*                                                                           */
14 /*                                                                           */
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.                                    */
18 /*                                                                           */
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:                            */
22 /*                                                                           */
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              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdlib.h>
37 #include <string.h>
38 #include <ctype.h>
39
40 /* common */
41 #include "addrsize.h"
42 #include "assertdefs.h"
43 #include "attrib.h"
44 #include "bitops.h"
45 #include "check.h"
46 #include "mmodel.h"
47
48 /* ca65 */
49 #include "asserts.h"
50 #include "ea.h"
51 #include "ea65.h"
52 #include "easw16.h"
53 #include "error.h"
54 #include "expr.h"
55 #include "global.h"
56 #include "instr.h"
57 #include "nexttok.h"
58 #include "objcode.h"
59 #include "spool.h"
60 #include "studyexpr.h"
61 #include "symtab.h"
62
63
64
65 /*****************************************************************************/
66 /*                                 Forwards                                  */
67 /*****************************************************************************/
68
69
70
71 static void PutPCRel8 (const InsDesc* Ins);
72 /* Handle branches with a 8 bit distance */
73
74 static void PutPCRel16 (const InsDesc* Ins);
75 /* Handle branches with an 16 bit distance and PER */
76
77 static void PutBlockMove (const InsDesc* Ins);
78 /* Handle the blockmove instructions (65816) */
79
80 static void PutBlockTransfer (const InsDesc* Ins);
81 /* Handle the block transfer instructions (HuC6280) */
82
83 static void PutBitBranch (const InsDesc* Ins);
84 /* Handle 65C02 branch on bit condition */
85
86 static void PutREP (const InsDesc* Ins);
87 /* Emit a REP instruction, track register sizes */
88
89 static void PutSEP (const InsDesc* Ins);
90 /* Emit a SEP instruction (65816), track register sizes */
91
92 static void PutTAMn (const InsDesc* Ins);
93 /* Emit a TAMn instruction (HuC6280). Since this is a two byte instruction with
94  * implicit addressing mode, the opcode byte in the table is actually the
95  * second operand byte. The TAM instruction is the more generic form, it takes
96  * an immediate argument.
97  */
98
99 static void PutTMA (const InsDesc* Ins);
100 /* Emit a TMA instruction (HuC6280) with an immediate argument. Only one bit
101  * in the argument byte may be set.
102  */
103
104 static void PutTMAn (const InsDesc* Ins);
105 /* Emit a TMAn instruction (HuC6280). Since this is a two byte instruction with
106  * implicit addressing mode, the opcode byte in the table is actually the
107  * second operand byte. The TAM instruction is the more generic form, it takes
108  * an immediate argument.
109  */
110
111 static void PutTST (const InsDesc* Ins);
112 /* Emit a TST instruction (HuC6280). */
113
114 static void PutJMP (const InsDesc* Ins);
115 /* Handle the jump instruction for the 6502. Problem is that these chips have
116  * a bug: If the address crosses a page, the upper byte gets not corrected and
117  * the instruction will fail. The PutJmp function will add a linker assertion
118  * to check for this case and is otherwise identical to PutAll.
119  */
120
121 static void PutRTS (const InsDesc* Ins attribute ((unused)));
122 /* Handle the RTS instruction for the 816. In smart mode emit a RTL opcode if
123  * the enclosing scope is FAR.
124  */
125
126 static void PutAll (const InsDesc* Ins);
127 /* Handle all other instructions */
128
129 static void PutSweet16 (const InsDesc* Ins);
130 /* Handle a generic sweet16 instruction */
131
132 static void PutSweet16Branch (const InsDesc* Ins);
133 /* Handle a sweet16 branch instruction */
134
135
136
137 /*****************************************************************************/
138 /*                                   Data                                    */
139 /*****************************************************************************/
140
141
142
143 /* Empty instruction table */
144 static const struct {
145     unsigned Count;
146 } InsTabNone = {
147     0
148 };
149
150 /* Instruction table for the 6502 */
151 static const struct {
152     unsigned Count;
153     InsDesc  Ins[56];
154 } InsTab6502 = {
155     sizeof (InsTab6502.Ins) / sizeof (InsTab6502.Ins[0]),
156     {
157         { "ADC",  0x080A26C, 0x60, 0, PutAll },
158         { "AND",  0x080A26C, 0x20, 0, PutAll },
159         { "ASL",  0x000006e, 0x02, 1, PutAll },
160         { "BCC",  0x0020000, 0x90, 0, PutPCRel8 },
161         { "BCS",  0x0020000, 0xb0, 0, PutPCRel8 },
162         { "BEQ",  0x0020000, 0xf0, 0, PutPCRel8 },
163         { "BIT",  0x000000C, 0x00, 2, PutAll },
164         { "BMI",  0x0020000, 0x30, 0, PutPCRel8 },
165         { "BNE",  0x0020000, 0xd0, 0, PutPCRel8 },
166         { "BPL",  0x0020000, 0x10, 0, PutPCRel8 },
167         { "BRK",  0x0000001, 0x00, 0, PutAll },
168         { "BVC",  0x0020000, 0x50, 0, PutPCRel8 },
169         { "BVS",  0x0020000, 0x70, 0, PutPCRel8 },
170         { "CLC",  0x0000001, 0x18, 0, PutAll },
171         { "CLD",  0x0000001, 0xd8, 0, PutAll },
172         { "CLI",  0x0000001, 0x58, 0, PutAll },
173         { "CLV",  0x0000001, 0xb8, 0, PutAll },
174         { "CMP",  0x080A26C, 0xc0, 0, PutAll },
175         { "CPX",  0x080000C, 0xe0, 1, PutAll },
176         { "CPY",  0x080000C, 0xc0, 1, PutAll },
177         { "DEC",  0x000006C, 0x00, 3, PutAll },
178         { "DEX",  0x0000001, 0xca, 0, PutAll },
179         { "DEY",  0x0000001, 0x88, 0, PutAll },
180         { "EOR",  0x080A26C, 0x40, 0, PutAll },
181         { "INC",  0x000006c, 0x00, 4, PutAll },
182         { "INX",  0x0000001, 0xe8, 0, PutAll },
183         { "INY",  0x0000001, 0xc8, 0, PutAll },
184         { "JMP",  0x0000808, 0x4c, 6, PutJMP },
185         { "JSR",  0x0000008, 0x20, 7, PutAll },
186         { "LDA",  0x080A26C, 0xa0, 0, PutAll },
187         { "LDX",  0x080030C, 0xa2, 1, PutAll },
188         { "LDY",  0x080006C, 0xa0, 1, PutAll },
189         { "LSR",  0x000006F, 0x42, 1, PutAll },
190         { "NOP",  0x0000001, 0xea, 0, PutAll },
191         { "ORA",  0x080A26C, 0x00, 0, PutAll },
192         { "PHA",  0x0000001, 0x48, 0, PutAll },
193         { "PHP",  0x0000001, 0x08, 0, PutAll },
194         { "PLA",  0x0000001, 0x68, 0, PutAll },
195         { "PLP",  0x0000001, 0x28, 0, PutAll },
196         { "ROL",  0x000006F, 0x22, 1, PutAll },
197         { "ROR",  0x000006F, 0x62, 1, PutAll },
198         { "RTI",  0x0000001, 0x40, 0, PutAll },
199         { "RTS",  0x0000001, 0x60, 0, PutAll },
200         { "SBC",  0x080A26C, 0xe0, 0, PutAll },
201         { "SEC",  0x0000001, 0x38, 0, PutAll },
202         { "SED",  0x0000001, 0xf8, 0, PutAll },
203         { "SEI",  0x0000001, 0x78, 0, PutAll },
204         { "STA",  0x000A26C, 0x80, 0, PutAll },
205         { "STX",  0x000010c, 0x82, 1, PutAll },
206         { "STY",  0x000002c, 0x80, 1, PutAll },
207         { "TAX",  0x0000001, 0xaa, 0, PutAll },
208         { "TAY",  0x0000001, 0xa8, 0, PutAll },
209         { "TSX",  0x0000001, 0xba, 0, PutAll },
210         { "TXA",  0x0000001, 0x8a, 0, PutAll },
211         { "TXS",  0x0000001, 0x9a, 0, PutAll },
212         { "TYA",  0x0000001, 0x98, 0, PutAll }
213     }
214 };
215
216 /* Instruction table for the 6502 with illegal instructions */
217 static const struct {
218     unsigned Count;
219     InsDesc  Ins[70];
220 } InsTab6502X = {
221     sizeof (InsTab6502X.Ins) / sizeof (InsTab6502X.Ins[0]),
222     {
223         { "ADC",  0x080A26C, 0x60, 0, PutAll },
224         { "ALR",  0x0800000, 0x4B, 0, PutAll },         /* X */
225         { "ANC",  0x0800000, 0x0B, 0, PutAll },         /* X */
226         { "AND",  0x080A26C, 0x20, 0, PutAll },
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",  0x000A30C, 0xA3, 1, 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",  0x0000001, 0xea, 0, PutAll },
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         { "SLO",  0x000A26C, 0x03, 0, PutAll },         /* X */
283         { "SRE",  0x000A26C, 0x43, 0, PutAll },         /* X */
284         { "STA",  0x000A26C, 0x80, 0, PutAll },
285         { "STX",  0x000010c, 0x82, 1, PutAll },
286         { "STY",  0x000002c, 0x80, 1, PutAll },
287         { "TAX",  0x0000001, 0xaa, 0, PutAll },
288         { "TAY",  0x0000001, 0xa8, 0, PutAll },
289         { "TSX",  0x0000001, 0xba, 0, PutAll },
290         { "TXA",  0x0000001, 0x8a, 0, PutAll },
291         { "TXS",  0x0000001, 0x9a, 0, PutAll },
292         { "TYA",  0x0000001, 0x98, 0, PutAll }
293     }
294 };
295
296 /* Instruction table for the 65SC02 */
297 static const struct {
298     unsigned Count;
299     InsDesc  Ins[66];
300 } InsTab65SC02 = {
301     sizeof (InsTab65SC02.Ins) / sizeof (InsTab65SC02.Ins[0]),
302     {
303         { "ADC",  0x080A66C, 0x60, 0, PutAll },
304         { "AND",  0x080A66C, 0x20, 0, PutAll },
305         { "ASL",  0x000006e, 0x02, 1, PutAll },
306         { "BCC",  0x0020000, 0x90, 0, PutPCRel8 },
307         { "BCS",  0x0020000, 0xb0, 0, PutPCRel8 },
308         { "BEQ",  0x0020000, 0xf0, 0, PutPCRel8 },
309         { "BIT",  0x0A0006C, 0x00, 2, PutAll },
310         { "BMI",  0x0020000, 0x30, 0, PutPCRel8 },
311         { "BNE",  0x0020000, 0xd0, 0, PutPCRel8 },
312         { "BPL",  0x0020000, 0x10, 0, PutPCRel8 },
313         { "BRA",  0x0020000, 0x80, 0, PutPCRel8 },
314         { "BRK",  0x0000001, 0x00, 0, PutAll },
315         { "BVC",  0x0020000, 0x50, 0, PutPCRel8 },
316         { "BVS",  0x0020000, 0x70, 0, PutPCRel8 },
317         { "CLC",  0x0000001, 0x18, 0, PutAll },
318         { "CLD",  0x0000001, 0xd8, 0, PutAll },
319         { "CLI",  0x0000001, 0x58, 0, PutAll },
320         { "CLV",  0x0000001, 0xb8, 0, PutAll },
321         { "CMP",  0x080A66C, 0xc0, 0, PutAll },
322         { "CPX",  0x080000C, 0xe0, 1, PutAll },
323         { "CPY",  0x080000C, 0xc0, 1, PutAll },
324         { "DEA",  0x0000001, 0x00, 3, PutAll },   /* == DEC */
325         { "DEC",  0x000006F, 0x00, 3, PutAll },
326         { "DEX",  0x0000001, 0xca, 0, PutAll },
327         { "DEY",  0x0000001, 0x88, 0, PutAll },
328         { "EOR",  0x080A66C, 0x40, 0, PutAll },
329         { "INA",  0x0000001, 0x00, 4, PutAll },   /* == INC */
330         { "INC",  0x000006f, 0x00, 4, PutAll },
331         { "INX",  0x0000001, 0xe8, 0, PutAll },
332         { "INY",  0x0000001, 0xc8, 0, PutAll },
333         { "JMP",  0x0010808, 0x4c, 6, PutAll },
334         { "JSR",  0x0000008, 0x20, 7, PutAll },
335         { "LDA",  0x080A66C, 0xa0, 0, PutAll },
336         { "LDX",  0x080030C, 0xa2, 1, PutAll },
337         { "LDY",  0x080006C, 0xa0, 1, PutAll },
338         { "LSR",  0x000006F, 0x42, 1, PutAll },
339         { "NOP",  0x0000001, 0xea, 0, PutAll },
340         { "ORA",  0x080A66C, 0x00, 0, PutAll },
341         { "PHA",  0x0000001, 0x48, 0, PutAll },
342         { "PHP",  0x0000001, 0x08, 0, PutAll },
343         { "PHX",  0x0000001, 0xda, 0, PutAll },
344         { "PHY",  0x0000001, 0x5a, 0, PutAll },
345         { "PLA",  0x0000001, 0x68, 0, PutAll },
346         { "PLP",  0x0000001, 0x28, 0, PutAll },
347         { "PLX",  0x0000001, 0xfa, 0, PutAll },
348         { "PLY",  0x0000001, 0x7a, 0, PutAll },
349         { "ROL",  0x000006F, 0x22, 1, PutAll },
350         { "ROR",  0x000006F, 0x62, 1, PutAll },
351         { "RTI",  0x0000001, 0x40, 0, PutAll },
352         { "RTS",  0x0000001, 0x60, 0, PutAll },
353         { "SBC",  0x080A66C, 0xe0, 0, PutAll },
354         { "SEC",  0x0000001, 0x38, 0, PutAll },
355         { "SED",  0x0000001, 0xf8, 0, PutAll },
356         { "SEI",  0x0000001, 0x78, 0, PutAll },
357         { "STA",  0x000A66C, 0x80, 0, PutAll },
358         { "STX",  0x000010c, 0x82, 1, PutAll },
359         { "STY",  0x000002c, 0x80, 1, PutAll },
360         { "STZ",  0x000006c, 0x04, 5, PutAll },
361         { "TAX",  0x0000001, 0xaa, 0, PutAll },
362         { "TAY",  0x0000001, 0xa8, 0, PutAll },
363         { "TRB",  0x000000c, 0x10, 1, PutAll },
364         { "TSB",  0x000000c, 0x00, 1, PutAll },
365         { "TSX",  0x0000001, 0xba, 0, PutAll },
366         { "TXA",  0x0000001, 0x8a, 0, PutAll },
367         { "TXS",  0x0000001, 0x9a, 0, PutAll },
368         { "TYA",  0x0000001, 0x98, 0, PutAll }
369     }
370 };
371
372 /* Instruction table for the 65C02 */
373 static const struct {
374     unsigned Count;
375     InsDesc  Ins[98];
376 } InsTab65C02 = {
377     sizeof (InsTab65C02.Ins) / sizeof (InsTab65C02.Ins[0]),
378     {
379         { "ADC",  0x080A66C, 0x60, 0, PutAll },
380         { "AND",  0x080A66C, 0x20, 0, PutAll },
381         { "ASL",  0x000006e, 0x02, 1, PutAll },
382         { "BBR0", 0x0000000, 0x0F, 0, PutBitBranch },
383         { "BBR1", 0x0000000, 0x1F, 0, PutBitBranch },
384         { "BBR2", 0x0000000, 0x2F, 0, PutBitBranch },
385         { "BBR3", 0x0000000, 0x3F, 0, PutBitBranch },
386         { "BBR4", 0x0000000, 0x4F, 0, PutBitBranch },
387         { "BBR5", 0x0000000, 0x5F, 0, PutBitBranch },
388         { "BBR6", 0x0000000, 0x6F, 0, PutBitBranch },
389         { "BBR7", 0x0000000, 0x7F, 0, PutBitBranch },
390         { "BBS0", 0x0000000, 0x8F, 0, PutBitBranch },
391         { "BBS1", 0x0000000, 0x9F, 0, PutBitBranch },
392         { "BBS2", 0x0000000, 0xAF, 0, PutBitBranch },
393         { "BBS3", 0x0000000, 0xBF, 0, PutBitBranch },
394         { "BBS4", 0x0000000, 0xCF, 0, PutBitBranch },
395         { "BBS5", 0x0000000, 0xDF, 0, PutBitBranch },
396         { "BBS6", 0x0000000, 0xEF, 0, PutBitBranch },
397         { "BBS7", 0x0000000, 0xFF, 0, PutBitBranch },
398         { "BCC",  0x0020000, 0x90, 0, PutPCRel8 },
399         { "BCS",  0x0020000, 0xb0, 0, PutPCRel8 },
400         { "BEQ",  0x0020000, 0xf0, 0, PutPCRel8 },
401         { "BIT",  0x0A0006C, 0x00, 2, PutAll },
402         { "BMI",  0x0020000, 0x30, 0, PutPCRel8 },
403         { "BNE",  0x0020000, 0xd0, 0, PutPCRel8 },
404         { "BPL",  0x0020000, 0x10, 0, PutPCRel8 },
405         { "BRA",  0x0020000, 0x80, 0, PutPCRel8 },
406         { "BRK",  0x0000001, 0x00, 0, PutAll },
407         { "BVC",  0x0020000, 0x50, 0, PutPCRel8 },
408         { "BVS",  0x0020000, 0x70, 0, PutPCRel8 },
409         { "CLC",  0x0000001, 0x18, 0, PutAll },
410         { "CLD",  0x0000001, 0xd8, 0, PutAll },
411         { "CLI",  0x0000001, 0x58, 0, PutAll },
412         { "CLV",  0x0000001, 0xb8, 0, PutAll },
413         { "CMP",  0x080A66C, 0xc0, 0, PutAll },
414         { "CPX",  0x080000C, 0xe0, 1, PutAll },
415         { "CPY",  0x080000C, 0xc0, 1, PutAll },
416         { "DEA",  0x0000001, 0x00, 3, PutAll },   /* == DEC */
417         { "DEC",  0x000006F, 0x00, 3, PutAll },
418         { "DEX",  0x0000001, 0xca, 0, PutAll },
419         { "DEY",  0x0000001, 0x88, 0, PutAll },
420         { "EOR",  0x080A66C, 0x40, 0, PutAll },
421         { "INA",  0x0000001, 0x00, 4, PutAll },   /* == INC */
422         { "INC",  0x000006f, 0x00, 4, PutAll },
423         { "INX",  0x0000001, 0xe8, 0, PutAll },
424         { "INY",  0x0000001, 0xc8, 0, PutAll },
425         { "JMP",  0x0010808, 0x4c, 6, PutAll },
426         { "JSR",  0x0000008, 0x20, 7, PutAll },
427         { "LDA",  0x080A66C, 0xa0, 0, PutAll },
428         { "LDX",  0x080030C, 0xa2, 1, PutAll },
429         { "LDY",  0x080006C, 0xa0, 1, PutAll },
430         { "LSR",  0x000006F, 0x42, 1, PutAll },
431         { "NOP",  0x0000001, 0xea, 0, PutAll },
432         { "ORA",  0x080A66C, 0x00, 0, PutAll },
433         { "PHA",  0x0000001, 0x48, 0, PutAll },
434         { "PHP",  0x0000001, 0x08, 0, PutAll },
435         { "PHX",  0x0000001, 0xda, 0, PutAll },
436         { "PHY",  0x0000001, 0x5a, 0, PutAll },
437         { "PLA",  0x0000001, 0x68, 0, PutAll },
438         { "PLP",  0x0000001, 0x28, 0, PutAll },
439         { "PLX",  0x0000001, 0xfa, 0, PutAll },
440         { "PLY",  0x0000001, 0x7a, 0, PutAll },
441         { "RMB0", 0x0000004, 0x07, 1, PutAll },
442         { "RMB1", 0x0000004, 0x17, 1, PutAll },
443         { "RMB2", 0x0000004, 0x27, 1, PutAll },
444         { "RMB3", 0x0000004, 0x37, 1, PutAll },
445         { "RMB4", 0x0000004, 0x47, 1, PutAll },
446         { "RMB5", 0x0000004, 0x57, 1, PutAll },
447         { "RMB6", 0x0000004, 0x67, 1, PutAll },
448         { "RMB7", 0x0000004, 0x77, 1, PutAll },
449         { "ROL",  0x000006F, 0x22, 1, PutAll },
450         { "ROR",  0x000006F, 0x62, 1, PutAll },
451         { "RTI",  0x0000001, 0x40, 0, PutAll },
452         { "RTS",  0x0000001, 0x60, 0, PutAll },
453         { "SBC",  0x080A66C, 0xe0, 0, PutAll },
454         { "SEC",  0x0000001, 0x38, 0, PutAll },
455         { "SED",  0x0000001, 0xf8, 0, PutAll },
456         { "SEI",  0x0000001, 0x78, 0, PutAll },
457         { "SMB0", 0x0000004, 0x87, 1, PutAll },
458         { "SMB1", 0x0000004, 0x97, 1, PutAll },
459         { "SMB2", 0x0000004, 0xA7, 1, PutAll },
460         { "SMB3", 0x0000004, 0xB7, 1, PutAll },
461         { "SMB4", 0x0000004, 0xC7, 1, PutAll },
462         { "SMB5", 0x0000004, 0xD7, 1, PutAll },
463         { "SMB6", 0x0000004, 0xE7, 1, PutAll },
464         { "SMB7", 0x0000004, 0xF7, 1, PutAll },
465         { "STA",  0x000A66C, 0x80, 0, PutAll },
466         { "STX",  0x000010c, 0x82, 1, PutAll },
467         { "STY",  0x000002c, 0x80, 1, PutAll },
468         { "STZ",  0x000006c, 0x04, 5, PutAll },
469         { "TAX",  0x0000001, 0xaa, 0, PutAll },
470         { "TAY",  0x0000001, 0xa8, 0, PutAll },
471         { "TRB",  0x000000c, 0x10, 1, PutAll },
472         { "TSB",  0x000000c, 0x00, 1, PutAll },
473         { "TSX",  0x0000001, 0xba, 0, PutAll },
474         { "TXA",  0x0000001, 0x8a, 0, PutAll },
475         { "TXS",  0x0000001, 0x9a, 0, PutAll },
476         { "TYA",  0x0000001, 0x98, 0, PutAll }
477     }
478 };
479
480 /* Instruction table for the 65816 */
481 static const struct {
482     unsigned Count;
483     InsDesc  Ins[101];
484 } InsTab65816 = {
485     sizeof (InsTab65816.Ins) / sizeof (InsTab65816.Ins[0]),
486     {
487         { "ADC",  0x0b8f6fc, 0x60, 0, PutAll },
488         { "AND",  0x0b8f6fc, 0x20, 0, PutAll },
489         { "ASL",  0x000006e, 0x02, 1, PutAll },
490         { "BCC",  0x0020000, 0x90, 0, PutPCRel8 },
491         { "BCS",  0x0020000, 0xb0, 0, PutPCRel8 },
492         { "BEQ",  0x0020000, 0xf0, 0, PutPCRel8 },
493         { "BGE",  0x0020000, 0xb0, 0, PutPCRel8 },   /* == BCS */
494         { "BIT",  0x0a0006c, 0x00, 2, PutAll },
495         { "BLT",  0x0020000, 0x90, 0, PutPCRel8 },   /* == BCC */
496         { "BMI",  0x0020000, 0x30, 0, PutPCRel8 },
497         { "BNE",  0x0020000, 0xd0, 0, PutPCRel8 },
498         { "BPL",  0x0020000, 0x10, 0, PutPCRel8 },
499         { "BRA",  0x0020000, 0x80, 0, PutPCRel8 },
500         { "BRK",  0x0000001, 0x00, 0, PutAll },
501         { "BRL",  0x0040000, 0x82, 0, PutPCRel16 },
502         { "BVC",  0x0020000, 0x50, 0, PutPCRel8 },
503         { "BVS",  0x0020000, 0x70, 0, PutPCRel8 },
504         { "CLC",  0x0000001, 0x18, 0, PutAll },
505         { "CLD",  0x0000001, 0xd8, 0, PutAll },
506         { "CLI",  0x0000001, 0x58, 0, PutAll },
507         { "CLV",  0x0000001, 0xb8, 0, PutAll },
508         { "CMP",  0x0b8f6fc, 0xc0, 0, PutAll },
509         { "COP",  0x0000004, 0x02, 6, PutAll },
510         { "CPA",  0x0b8f6fc, 0xc0, 0, PutAll },   /* == CMP */
511         { "CPX",  0x0c0000c, 0xe0, 1, PutAll },
512         { "CPY",  0x0c0000c, 0xc0, 1, PutAll },
513         { "DEA",  0x0000001, 0x00, 3, PutAll },   /* == DEC */
514         { "DEC",  0x000006F, 0x00, 3, PutAll },
515         { "DEX",  0x0000001, 0xca, 0, PutAll },
516         { "DEY",  0x0000001, 0x88, 0, PutAll },
517         { "EOR",  0x0b8f6fc, 0x40, 0, PutAll },
518         { "INA",  0x0000001, 0x00, 4, PutAll },   /* == INC */
519         { "INC",  0x000006F, 0x00, 4, PutAll },
520         { "INX",  0x0000001, 0xe8, 0, PutAll },
521         { "INY",  0x0000001, 0xc8, 0, PutAll },
522         { "JML",  0x0000810, 0x5c, 1, PutAll },
523         { "JMP",  0x0010818, 0x4c, 6, PutAll },
524         { "JSL",  0x0000010, 0x20, 7, PutAll },
525         { "JSR",  0x0010018, 0x20, 7, PutAll },
526         { "LDA",  0x0b8f6fc, 0xa0, 0, PutAll },
527         { "LDX",  0x0c0030c, 0xa2, 1, PutAll },
528         { "LDY",  0x0c0006c, 0xa0, 1, PutAll },
529         { "LSR",  0x000006F, 0x42, 1, PutAll },
530         { "MVN",  0x1000000, 0x54, 0, PutBlockMove },
531         { "MVP",  0x1000000, 0x44, 0, PutBlockMove },
532         { "NOP",  0x0000001, 0xea, 0, PutAll },
533         { "ORA",  0x0b8f6fc, 0x00, 0, PutAll },
534         { "PEA",  0x0000008, 0xf4, 6, PutAll },
535         { "PEI",  0x0000400, 0xd4, 1, PutAll },
536         { "PER",  0x0040000, 0x62, 0, PutPCRel16 },
537         { "PHA",  0x0000001, 0x48, 0, PutAll },
538         { "PHB",  0x0000001, 0x8b, 0, PutAll },
539         { "PHD",  0x0000001, 0x0b, 0, PutAll },
540         { "PHK",  0x0000001, 0x4b, 0, PutAll },
541         { "PHP",  0x0000001, 0x08, 0, PutAll },
542         { "PHX",  0x0000001, 0xda, 0, PutAll },
543         { "PHY",  0x0000001, 0x5a, 0, PutAll },
544         { "PLA",  0x0000001, 0x68, 0, PutAll },
545         { "PLB",  0x0000001, 0xab, 0, PutAll },
546         { "PLD",  0x0000001, 0x2b, 0, PutAll },
547         { "PLP",  0x0000001, 0x28, 0, PutAll },
548         { "PLX",  0x0000001, 0xfa, 0, PutAll },
549         { "PLY",  0x0000001, 0x7a, 0, PutAll },
550         { "REP",  0x0800000, 0xc2, 1, PutREP },
551         { "ROL",  0x000006F, 0x22, 1, PutAll },
552         { "ROR",  0x000006F, 0x62, 1, PutAll },
553         { "RTI",  0x0000001, 0x40, 0, PutAll },
554         { "RTL",  0x0000001, 0x6b, 0, PutAll },
555         { "RTS",  0x0000001, 0x60, 0, PutRTS },
556         { "SBC",  0x0b8f6fc, 0xe0, 0, PutAll },
557         { "SEC",  0x0000001, 0x38, 0, PutAll },
558         { "SED",  0x0000001, 0xf8, 0, PutAll },
559         { "SEI",  0x0000001, 0x78, 0, PutAll },
560         { "SEP",  0x0800000, 0xe2, 1, PutSEP },
561         { "STA",  0x018f6fc, 0x80, 0, PutAll },
562         { "STP",  0x0000001, 0xdb, 0, PutAll },
563         { "STX",  0x000010c, 0x82, 1, PutAll },
564         { "STY",  0x000002c, 0x80, 1, PutAll },
565         { "STZ",  0x000006c, 0x04, 5, PutAll },
566         { "SWA",  0x0000001, 0xeb, 0, PutAll },   /* == XBA */
567         { "TAD",  0x0000001, 0x5b, 0, PutAll },   /* == TCD */
568         { "TAS",  0x0000001, 0x1b, 0, PutAll },   /* == TCS */
569         { "TAX",  0x0000001, 0xaa, 0, PutAll },
570         { "TAY",  0x0000001, 0xa8, 0, PutAll },
571         { "TCD",  0x0000001, 0x5b, 0, PutAll },
572         { "TCS",  0x0000001, 0x1b, 0, PutAll },
573         { "TDA",  0x0000001, 0x7b, 0, PutAll },   /* == TDC */
574         { "TDC",  0x0000001, 0x7b, 0, PutAll },
575         { "TRB",  0x000000c, 0x10, 1, PutAll },
576         { "TSA",  0x0000001, 0x3b, 0, PutAll },   /* == TSC */
577         { "TSB",  0x000000c, 0x00, 1, PutAll },
578         { "TSC",  0x0000001, 0x3b, 0, PutAll },
579         { "TSX",  0x0000001, 0xba, 0, PutAll },
580         { "TXA",  0x0000001, 0x8a, 0, PutAll },
581         { "TXS",  0x0000001, 0x9a, 0, PutAll },
582         { "TXY",  0x0000001, 0x9b, 0, PutAll },
583         { "TYA",  0x0000001, 0x98, 0, PutAll },
584         { "TYX",  0x0000001, 0xbb, 0, PutAll },
585         { "WAI",  0x0000001, 0xcb, 0, PutAll },
586         { "XBA",  0x0000001, 0xeb, 0, PutAll },
587         { "XCE",  0x0000001, 0xfb, 0, PutAll }
588     }
589 };
590
591 #ifdef SUNPLUS
592 /* Table for the SUNPLUS CPU */
593 #include "sunplus.inc"
594 #endif
595
596 /* Instruction table for the SWEET16 pseudo CPU */
597 static const struct {
598     unsigned Count;
599     InsDesc  Ins[27];
600 } InsTabSweet16 = {
601     sizeof (InsTabSweet16.Ins) / sizeof (InsTabSweet16.Ins[0]),
602     {
603         { "ADD",  AMSW16_REG,              0xA0, 0, PutSweet16 },
604         { "BC",   AMSW16_BRA,              0x03, 0, PutSweet16Branch },
605         { "BK",   AMSW16_IMP,              0x0A, 0, PutSweet16 },
606         { "BM",   AMSW16_BRA,              0x05, 0, PutSweet16Branch },
607         { "BM1",  AMSW16_BRA,              0x08, 0, PutSweet16Branch },
608         { "BNC",  AMSW16_BRA,              0x02, 0, PutSweet16Branch },
609         { "BNM1", AMSW16_BRA,              0x09, 0, PutSweet16Branch },
610         { "BNZ",  AMSW16_BRA,              0x07, 0, PutSweet16Branch },
611         { "BP",   AMSW16_BRA,              0x04, 0, PutSweet16Branch },
612         { "BR",   AMSW16_BRA,              0x01, 0, PutSweet16Branch },
613         { "BS",   AMSW16_BRA,              0x0B, 0, PutSweet16Branch },
614         { "BZ",   AMSW16_BRA,              0x06, 0, PutSweet16Branch },
615         { "CPR",  AMSW16_REG,              0xD0, 0, PutSweet16 },
616         { "DCR",  AMSW16_REG,              0xF0, 0, PutSweet16 },
617         { "INR",  AMSW16_REG,              0xE0, 0, PutSweet16 },
618         { "LD",   AMSW16_REG | AMSW16_IND, 0x00, 1, PutSweet16 },
619         { "LDD",  AMSW16_IND,              0x60, 0, PutSweet16 },
620         { "POP",  AMSW16_IND,              0x80, 0, PutSweet16 },
621         { "POPD", AMSW16_IND,              0xC0, 0, PutSweet16 },
622         { "RS",   AMSW16_IMP,              0x0B, 0, PutSweet16 },
623         { "RTN",  AMSW16_IMP,              0x00, 0, PutSweet16 },
624         { "SET",  AMSW16_IMM,              0x10, 0, PutSweet16 },
625         { "ST",   AMSW16_REG | AMSW16_IND, 0x10, 1, PutSweet16 },
626         { "STD",  AMSW16_IND,              0x70, 0, PutSweet16 },
627         { "STP",  AMSW16_IND,              0x90, 0, PutSweet16 },
628         { "SUB",  AMSW16_IMM,              0xB0, 0, PutSweet16 },
629     }
630 };
631
632 /* Instruction table for the HuC6280 (the CPU used in the PC engine) */
633 static const struct {
634     unsigned Count;
635     InsDesc  Ins[135];
636 } InsTabHuC6280 = {
637     sizeof (InsTabHuC6280.Ins) / sizeof (InsTabHuC6280.Ins[0]),
638     {
639         { "ADC",  0x080A66C, 0x60, 0, PutAll },
640         { "AND",  0x080A66C, 0x20, 0, PutAll },
641         { "ASL",  0x000006e, 0x02, 1, PutAll },
642         { "BBR0", 0x0000000, 0x0F, 0, PutBitBranch },
643         { "BBR1", 0x0000000, 0x1F, 0, PutBitBranch },
644         { "BBR2", 0x0000000, 0x2F, 0, PutBitBranch },
645         { "BBR3", 0x0000000, 0x3F, 0, PutBitBranch },
646         { "BBR4", 0x0000000, 0x4F, 0, PutBitBranch },
647         { "BBR5", 0x0000000, 0x5F, 0, PutBitBranch },
648         { "BBR6", 0x0000000, 0x6F, 0, PutBitBranch },
649         { "BBR7", 0x0000000, 0x7F, 0, PutBitBranch },
650         { "BBS0", 0x0000000, 0x8F, 0, PutBitBranch },
651         { "BBS1", 0x0000000, 0x9F, 0, PutBitBranch },
652         { "BBS2", 0x0000000, 0xAF, 0, PutBitBranch },
653         { "BBS3", 0x0000000, 0xBF, 0, PutBitBranch },
654         { "BBS4", 0x0000000, 0xCF, 0, PutBitBranch },
655         { "BBS5", 0x0000000, 0xDF, 0, PutBitBranch },
656         { "BBS6", 0x0000000, 0xEF, 0, PutBitBranch },
657         { "BBS7", 0x0000000, 0xFF, 0, PutBitBranch },
658         { "BCC",  0x0020000, 0x90, 0, PutPCRel8 },
659         { "BCS",  0x0020000, 0xb0, 0, PutPCRel8 },
660         { "BEQ",  0x0020000, 0xf0, 0, PutPCRel8 },
661         { "BIT",  0x0A0006C, 0x00, 2, PutAll },
662         { "BMI",  0x0020000, 0x30, 0, PutPCRel8 },
663         { "BNE",  0x0020000, 0xd0, 0, PutPCRel8 },
664         { "BPL",  0x0020000, 0x10, 0, PutPCRel8 },
665         { "BRA",  0x0020000, 0x80, 0, PutPCRel8 },
666         { "BRK",  0x0000001, 0x00, 0, PutAll },
667         { "BSR",  0x0020000, 0x44, 0, PutPCRel8 },
668         { "BVC",  0x0020000, 0x50, 0, PutPCRel8 },
669         { "BVS",  0x0020000, 0x70, 0, PutPCRel8 },
670         { "CLA",  0x0000001, 0x62, 0, PutAll },
671         { "CLC",  0x0000001, 0x18, 0, PutAll },
672         { "CLD",  0x0000001, 0xd8, 0, PutAll },
673         { "CLI",  0x0000001, 0x58, 0, PutAll },
674         { "CLV",  0x0000001, 0xb8, 0, PutAll },
675         { "CLX",  0x0000001, 0x82, 0, PutAll },
676         { "CLY",  0x0000001, 0xc2, 0, PutAll },
677         { "CMP",  0x080A66C, 0xc0, 0, PutAll },
678         { "CPX",  0x080000C, 0xe0, 1, PutAll },
679         { "CPY",  0x080000C, 0xc0, 1, PutAll },
680         { "CSH",  0x0000001, 0xd4, 0, PutAll },
681         { "CSL",  0x0000001, 0x54, 0, PutAll },
682         { "DEA",  0x0000001, 0x00, 3, PutAll },   /* == DEC */
683         { "DEC",  0x000006F, 0x00, 3, PutAll },
684         { "DEX",  0x0000001, 0xca, 0, PutAll },
685         { "DEY",  0x0000001, 0x88, 0, PutAll },
686         { "EOR",  0x080A66C, 0x40, 0, PutAll },
687         { "INA",  0x0000001, 0x00, 4, PutAll },   /* == INC */
688         { "INC",  0x000006f, 0x00, 4, PutAll },
689         { "INX",  0x0000001, 0xe8, 0, PutAll },
690         { "INY",  0x0000001, 0xc8, 0, PutAll },
691         { "JMP",  0x0010808, 0x4c, 6, PutAll },
692         { "JSR",  0x0000008, 0x20, 7, PutAll },
693         { "LDA",  0x080A66C, 0xa0, 0, PutAll },
694         { "LDX",  0x080030C, 0xa2, 1, PutAll },
695         { "LDY",  0x080006C, 0xa0, 1, PutAll },
696         { "LSR",  0x000006F, 0x42, 1, PutAll },
697         { "NOP",  0x0000001, 0xea, 0, PutAll },
698         { "ORA",  0x080A66C, 0x00, 0, PutAll },
699         { "PHA",  0x0000001, 0x48, 0, PutAll },
700         { "PHP",  0x0000001, 0x08, 0, PutAll },
701         { "PHX",  0x0000001, 0xda, 0, PutAll },
702         { "PHY",  0x0000001, 0x5a, 0, PutAll },
703         { "PLA",  0x0000001, 0x68, 0, PutAll },
704         { "PLP",  0x0000001, 0x28, 0, PutAll },
705         { "PLX",  0x0000001, 0xfa, 0, PutAll },
706         { "PLY",  0x0000001, 0x7a, 0, PutAll },
707         { "RMB0", 0x0000004, 0x07, 1, PutAll },
708         { "RMB1", 0x0000004, 0x17, 1, PutAll },
709         { "RMB2", 0x0000004, 0x27, 1, PutAll },
710         { "RMB3", 0x0000004, 0x37, 1, PutAll },
711         { "RMB4", 0x0000004, 0x47, 1, PutAll },
712         { "RMB5", 0x0000004, 0x57, 1, PutAll },
713         { "RMB6", 0x0000004, 0x67, 1, PutAll },
714         { "RMB7", 0x0000004, 0x77, 1, PutAll },
715         { "ROL",  0x000006F, 0x22, 1, PutAll },
716         { "ROR",  0x000006F, 0x62, 1, PutAll },
717         { "RTI",  0x0000001, 0x40, 0, PutAll },
718         { "RTS",  0x0000001, 0x60, 0, PutAll },
719         { "SBC",  0x080A66C, 0xe0, 0, PutAll },
720         { "SAX",  0x0000001, 0x22, 0, PutAll },
721         { "SAY",  0x0000001, 0x42, 0, PutAll },
722         { "SEC",  0x0000001, 0x38, 0, PutAll },
723         { "SED",  0x0000001, 0xf8, 0, PutAll },
724         { "SEI",  0x0000001, 0x78, 0, PutAll },
725         { "SET",  0x0000001, 0xf4, 0, PutAll },
726         { "SMB0", 0x0000004, 0x87, 1, PutAll },
727         { "SMB1", 0x0000004, 0x97, 1, PutAll },
728         { "SMB2", 0x0000004, 0xA7, 1, PutAll },
729         { "SMB3", 0x0000004, 0xB7, 1, PutAll },
730         { "SMB4", 0x0000004, 0xC7, 1, PutAll },
731         { "SMB5", 0x0000004, 0xD7, 1, PutAll },
732         { "SMB6", 0x0000004, 0xE7, 1, PutAll },
733         { "SMB7", 0x0000004, 0xF7, 1, PutAll },
734         { "ST0",  0x0800000, 0x03, 1, PutAll },
735         { "ST1",  0x0800000, 0x13, 1, PutAll },
736         { "ST2",  0x0800000, 0x23, 1, PutAll },
737         { "STA",  0x000A66C, 0x80, 0, PutAll },
738         { "STX",  0x000010c, 0x82, 1, PutAll },
739         { "STY",  0x000002c, 0x80, 1, PutAll },
740         { "STZ",  0x000006c, 0x04, 5, PutAll },
741         { "SXY",  0x0000001, 0x02, 0, PutAll },
742         { "TAI",  0x2000000, 0xf3, 0, PutBlockTransfer },
743         { "TAM",  0x0800000, 0x53, 1, PutAll },
744         { "TAM0", 0x0000001, 0x01, 0, PutTAMn},
745         { "TAM1", 0x0000001, 0x02, 0, PutTAMn},
746         { "TAM2", 0x0000001, 0x04, 0, PutTAMn},
747         { "TAM3", 0x0000001, 0x08, 0, PutTAMn},
748         { "TAM4", 0x0000001, 0x10, 0, PutTAMn},
749         { "TAM5", 0x0000001, 0x20, 0, PutTAMn},
750         { "TAM6", 0x0000001, 0x40, 0, PutTAMn},
751         { "TAM7", 0x0000001, 0x80, 0, PutTAMn},
752         { "TAX",  0x0000001, 0xaa, 0, PutAll },
753         { "TAY",  0x0000001, 0xa8, 0, PutAll },
754         { "TDD",  0x2000000, 0xc3, 0, PutBlockTransfer },
755         { "TIA",  0x2000000, 0xe3, 0, PutBlockTransfer },
756         { "TII",  0x2000000, 0x73, 0, PutBlockTransfer },
757         { "TIN",  0x2000000, 0xD3, 0, PutBlockTransfer },
758         { "TMA",  0x0800000, 0x43, 1, PutTMA },
759         { "TMA0", 0x0000001, 0x01, 0, PutTMAn},
760         { "TMA1", 0x0000001, 0x02, 0, PutTMAn},
761         { "TMA2", 0x0000001, 0x04, 0, PutTMAn},
762         { "TMA3", 0x0000001, 0x08, 0, PutTMAn},
763         { "TMA4", 0x0000001, 0x10, 0, PutTMAn},
764         { "TMA5", 0x0000001, 0x20, 0, PutTMAn},
765         { "TMA6", 0x0000001, 0x40, 0, PutTMAn},
766         { "TMA7", 0x0000001, 0x80, 0, PutTMAn},
767         { "TRB",  0x000000c, 0x10, 1, PutAll },
768         { "TSB",  0x000000c, 0x00, 1, PutAll },
769         { "TST",  0x000006c, 0x83, 9, PutTST },
770         { "TSX",  0x0000001, 0xba, 0, PutAll },
771         { "TXA",  0x0000001, 0x8a, 0, PutAll },
772         { "TXS",  0x0000001, 0x9a, 0, PutAll },
773         { "TYA",  0x0000001, 0x98, 0, PutAll }
774     }
775 };
776
777
778
779 /* An array with instruction tables */
780 static const InsTable* InsTabs[CPU_COUNT] = {
781     (const InsTable*) &InsTabNone,
782     (const InsTable*) &InsTab6502,
783     (const InsTable*) &InsTab6502X,
784     (const InsTable*) &InsTab65SC02,
785     (const InsTable*) &InsTab65C02,
786     (const InsTable*) &InsTab65816,
787 #ifdef SUNPLUS
788     (const InsTable*) &InsTabSunPlus,
789 #else
790     NULL,
791 #endif
792     (const InsTable*) &InsTabSweet16,
793     (const InsTable*) &InsTabHuC6280,
794 };
795 const InsTable* InsTab = (const InsTable*) &InsTab6502;
796
797 /* Table to build the effective 65xx opcode from a base opcode and an
798  * addressing mode.
799  */
800 static unsigned char EATab[10][AM65I_COUNT] = {
801     {   /* Table 0 */
802         0x00, 0x00, 0x05, 0x0D, 0x0F, 0x15, 0x1D, 0x1F,
803         0x00, 0x19, 0x12, 0x00, 0x07, 0x11, 0x17, 0x01,
804         0x00, 0x00, 0x00, 0x03, 0x13, 0x09, 0x00, 0x09,
805         0x00, 0x00
806     },
807     {   /* Table 1 */
808         0x08, 0x08, 0x04, 0x0C, 0x00, 0x14, 0x1C, 0x00,
809         0x14, 0x1C, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00,
810         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
811         0x00, 0x00
812     },
813     {   /* Table 2 */
814         0x00, 0x00, 0x24, 0x2C, 0x0F, 0x34, 0x3C, 0x00,
815         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
816         0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00,
817         0x00, 0x00
818     },
819     {   /* Table 3 */
820         0x3A, 0x3A, 0xC6, 0xCE, 0x00, 0xD6, 0xDE, 0x00,
821         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
822         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
823         0x00, 0x00
824     },
825     {   /* Table 4 */
826         0x1A, 0x1A, 0xE6, 0xEE, 0x00, 0xF6, 0xFE, 0x00,
827         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
828         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
829         0x00, 0x00
830     },
831     {   /* Table 5 */
832         0x00, 0x00, 0x60, 0x98, 0x00, 0x70, 0x9E, 0x00,
833         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
834         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
835         0x00, 0x00
836     },
837     {   /* Table 6 */
838         0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
839         0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
840         0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
841         0x00, 0x00
842     },
843     {   /* Table 7 */
844         0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
845         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
846         0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
847         0x00, 0x00
848     },
849     {   /* Table 8 */
850         0x00, 0x40, 0x01, 0x41, 0x00, 0x09, 0x49, 0x00,
851         0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00,
852         0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
853         0x00, 0x00
854     },
855     {   /* Table 9 */
856         0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x30, 0x00,
857         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
858         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
859         0x00, 0x00
860     },
861 };
862
863 /* Table to build the effective SWEET16 opcode from a base opcode and an
864  * addressing mode.
865  */
866 static unsigned char Sweet16EATab[2][AMSW16I_COUNT] = {
867     {   /* Table 0 */
868         0x00, 0x00, 0x00, 0x00, 0x00,
869     },
870     {   /* Table 1 */
871         0x00, 0x00, 0x00, 0x40, 0x20,
872     },
873 };
874
875 /* Table that encodes the additional bytes for each 65xx instruction */
876 unsigned char ExtBytes[AM65I_COUNT] = {
877     0,          /* Implicit */
878     0,          /* Accu */
879     1,          /* Direct */
880     2,          /* Absolute */
881     3,          /* Absolute long */
882     1,          /* Direct,X */
883     2,          /* Absolute,X */
884     3,          /* Absolute long,X */
885     1,          /* Direct,Y */
886     2,          /* Absolute,Y */
887     1,          /* (Direct) */
888     2,          /* (Absolute) */
889     1,          /* [Direct] */
890     1,          /* (Direct),Y */
891     1,          /* [Direct],Y */
892     1,          /* (Direct,X) */
893     2,          /* (Absolute,X) */
894     1,          /* Relative short */
895     2,          /* Relative long */
896     1,          /* r,s */
897     1,          /* (r,s),y */
898     1,          /* Immidiate accu */
899     1,          /* Immidiate index */
900     1,          /* Immidiate byte */
901     2,          /* Blockmove (65816) */
902     7,          /* Block transfer (HuC6280) */
903 };
904
905 /* Table that encodes the additional bytes for each SWEET16 instruction */
906 static unsigned char Sweet16ExtBytes[AMSW16I_COUNT] = {
907     0,          /* AMSW16_IMP */
908     1,          /* AMSW16_BRA */
909     2,          /* AMSW16_IMM */
910     0,          /* AMSW16_IND */
911     0,          /* AMSW16_REG */
912 };
913
914
915
916 /*****************************************************************************/
917 /*                   Handler functions for 6502 derivates                    */
918 /*****************************************************************************/
919
920
921
922 static int EvalEA (const InsDesc* Ins, EffAddr* A)
923 /* Evaluate the effective address. All fields in A will be valid after calling
924  * this function. The function returns true on success and false on errors.
925  */
926 {
927     /* Get the set of possible addressing modes */
928     GetEA (A);
929
930     /* From the possible addressing modes, remove the ones that are invalid
931      * for this instruction or CPU.
932      */
933     A->AddrModeSet &= Ins->AddrMode;
934
935     /* If we have an expression, check it and remove any addressing modes that
936      * are too small for the expression size. Since we have to study the
937      * expression anyway, do also replace it by a simpler one if possible.
938      */
939     if (A->Expr) {
940         ExprDesc ED;
941         ED_Init (&ED);
942
943         /* Study the expression */
944         StudyExpr (A->Expr, &ED);
945
946         /* Simplify it if possible */
947         A->Expr = SimplifyExpr (A->Expr, &ED);
948
949         /* If we don't know how big the expression is, assume the default
950          * address size for data.
951          */
952         if (ED.AddrSize == ADDR_SIZE_DEFAULT) {
953             ED.AddrSize = DataAddrSize;
954         }
955
956         /* Check the size */
957         switch (ED.AddrSize) {
958
959             case ADDR_SIZE_ABS:
960                 A->AddrModeSet &= ~AM65_SET_ZP;
961                 break;
962
963             case ADDR_SIZE_FAR:
964                 A->AddrModeSet &= ~(AM65_SET_ZP | AM65_SET_ABS);
965                 break;
966         }
967
968         /* Free any resource associated with the expression desc */
969         ED_Done (&ED);
970     }
971
972     /* Check if we have any adressing modes left */
973     if (A->AddrModeSet == 0) {
974         Error ("Illegal addressing mode");
975         return 0;
976     }
977     A->AddrMode    = BitFind (A->AddrModeSet);
978     A->AddrModeBit = (0x01UL << A->AddrMode);
979
980     /* If the instruction has a one byte operand and immediate addressing is
981      * allowed but not used, check for an operand expression in the form
982      * <label or >label, where label is a far or absolute label. If found,
983      * emit a warning. This warning protects against a typo, where the '#'
984      * for the immediate operand is omitted.
985      */
986     if (A->Expr && (Ins->AddrMode & AM65_IMM)                    &&
987         (A->AddrModeSet & (AM65_DIR | AM65_ABS | AM65_ABS_LONG)) &&
988         ExtBytes[A->AddrMode] == 1) {
989
990         /* Found, check the expression */
991         ExprNode* Left = A->Expr->Left;
992         if ((A->Expr->Op == EXPR_BYTE0 || A->Expr->Op == EXPR_BYTE1) &&
993             Left->Op == EXPR_SYMBOL                                  &&
994             GetSymAddrSize (Left->V.Sym) != ADDR_SIZE_ZP) {
995
996             /* Output a warning */
997             Warning (1, "Suspicious address expression");
998         }
999     }
1000
1001     /* Build the opcode */
1002     A->Opcode = Ins->BaseCode | EATab[Ins->ExtCode][A->AddrMode];
1003
1004     /* Success */
1005     return 1;
1006 }
1007
1008
1009
1010 static void EmitCode (EffAddr* A)
1011 /* Output code for the data in A */
1012 {
1013     /* Check how many extension bytes are needed and output the instruction */
1014     switch (ExtBytes[A->AddrMode]) {
1015
1016         case 0:
1017             Emit0 (A->Opcode);
1018             break;
1019
1020         case 1:
1021             Emit1 (A->Opcode, A->Expr);
1022             break;
1023
1024         case 2:
1025             if (CPU == CPU_65816 && (A->AddrModeBit & (AM65_ABS | AM65_ABS_X | AM65_ABS_Y))) {
1026                 /* This is a 16 bit mode that uses an address. If in 65816,
1027                  * mode, force this address into 16 bit range to allow
1028                  * addressing inside a 64K segment.
1029                  */
1030                 Emit2 (A->Opcode, GenWordExpr (A->Expr));
1031             } else {
1032                 Emit2 (A->Opcode, A->Expr);
1033             }
1034             break;
1035
1036         case 3:
1037             /* Far argument */
1038             Emit3 (A->Opcode, A->Expr);
1039             break;
1040
1041         default:
1042             Internal ("Invalid operand byte count: %u", ExtBytes[A->AddrMode]);
1043
1044     }
1045 }
1046
1047
1048
1049 static long PutImmed8 (const InsDesc* Ins)
1050 /* Parse and emit an immediate 8 bit instruction. Return the value of the
1051  * operand if it's available and const.
1052  */
1053 {
1054     EffAddr A;
1055     long Val = -1;
1056
1057     /* Evaluate the addressing mode */
1058     if (EvalEA (Ins, &A) == 0) {
1059         /* An error occurred */
1060         return -1L;
1061     }
1062
1063     /* If we have an expression and it's const, get it's value */
1064     if (A.Expr) {
1065         (void) IsConstExpr (A.Expr, &Val);
1066     }
1067
1068     /* Check how many extension bytes are needed and output the instruction */
1069     switch (ExtBytes[A.AddrMode]) {
1070
1071         case 1:
1072             Emit1 (A.Opcode, A.Expr);
1073             break;
1074
1075         default:
1076             Internal ("Invalid operand byte count: %u", ExtBytes[A.AddrMode]);
1077     }
1078
1079     /* Return the expression value */
1080     return Val;
1081 }
1082
1083
1084
1085 static void PutPCRel8 (const InsDesc* Ins)
1086 /* Handle branches with a 8 bit distance */
1087 {
1088     EmitPCRel (Ins->BaseCode, GenBranchExpr (2), 1);
1089 }
1090
1091
1092
1093 static void PutPCRel16 (const InsDesc* Ins)
1094 /* Handle branches with an 16 bit distance and PER */
1095 {
1096     EmitPCRel (Ins->BaseCode, GenBranchExpr (3), 2);
1097 }
1098
1099
1100
1101 static void PutBlockMove (const InsDesc* Ins)
1102 /* Handle the blockmove instructions (65816) */
1103 {
1104     Emit0 (Ins->BaseCode);
1105     EmitByte (Expression ());
1106     ConsumeComma ();
1107     EmitByte (Expression ());
1108 }
1109
1110
1111
1112 static void PutBlockTransfer (const InsDesc* Ins)
1113 /* Handle the block transfer instructions (HuC6280) */
1114 {
1115     Emit0 (Ins->BaseCode);
1116     EmitWord (Expression ());
1117     ConsumeComma ();
1118     EmitWord (Expression ());
1119     ConsumeComma ();
1120     EmitWord (Expression ());
1121 }
1122
1123
1124
1125 static void PutBitBranch (const InsDesc* Ins)
1126 /* Handle 65C02 branch on bit condition */
1127 {
1128     Emit0 (Ins->BaseCode);
1129     EmitByte (Expression ());
1130     ConsumeComma ();
1131     EmitSigned (GenBranchExpr (1), 1);
1132 }
1133
1134
1135
1136 static void PutREP (const InsDesc* Ins)
1137 /* Emit a REP instruction, track register sizes */
1138 {
1139     /* Use the generic handler */
1140     long Val = PutImmed8 (Ins);
1141
1142     /* We track the status only for the 816 CPU and in smart mode */
1143     if (CPU == CPU_65816 && SmartMode) {
1144
1145         /* Check the range for Val. */
1146         if (Val < 0) {
1147             /* We had an error */
1148             Warning (1, "Cannot track processor status byte");
1149         } else {
1150             if (Val & 0x10) {
1151                 /* Index registers to 16 bit */
1152                 ExtBytes[AM65I_IMM_INDEX] = 2;
1153             }
1154             if (Val & 0x20) {
1155                 /* Accu to 16 bit */
1156                 ExtBytes[AM65I_IMM_ACCU] = 2;
1157             }
1158         }
1159     }
1160 }
1161
1162
1163
1164 static void PutSEP (const InsDesc* Ins)
1165 /* Emit a SEP instruction (65816), track register sizes */
1166 {
1167     /* Use the generic handler */
1168     long Val = PutImmed8 (Ins);
1169
1170     /* We track the status only for the 816 CPU and in smart mode */
1171     if (CPU == CPU_65816 && SmartMode) {
1172
1173         /* Check the range for Val. */
1174         if (Val < 0) {
1175             /* We had an error */
1176             Warning (1, "Cannot track processor status byte");
1177         } else {
1178             if (Val & 0x10) {
1179                 /* Index registers to 8 bit */
1180                 ExtBytes[AM65I_IMM_INDEX] = 1;
1181             }
1182             if (Val & 0x20) {
1183                 /* Accu to 8 bit */
1184                 ExtBytes[AM65I_IMM_ACCU] = 1;
1185             }
1186         }
1187     }
1188 }
1189
1190
1191
1192 static void PutTAMn (const InsDesc* Ins)
1193 /* Emit a TAMn instruction (HuC6280). Since this is a two byte instruction with
1194  * implicit addressing mode, the opcode byte in the table is actually the
1195  * second operand byte. The TAM instruction is the more generic form, it takes
1196  * an immediate argument.
1197  */
1198 {
1199     /* Emit the TAM opcode itself */
1200     Emit0 (0x53);
1201
1202     /* Emit the argument, which is the opcode from the table */
1203     Emit0 (Ins->BaseCode);
1204 }
1205
1206
1207
1208 static void PutTMA (const InsDesc* Ins)
1209 /* Emit a TMA instruction (HuC6280) with an immediate argument. Only one bit
1210  * in the argument byte may be set.
1211  */
1212 {
1213     /* Use the generic handler */
1214     long Val = PutImmed8 (Ins);
1215
1216     /* Check the range for Val. */
1217     if (Val < 0) {
1218         /* We had an error */
1219         Warning (1, "Cannot check argument of TMA instruction");
1220     } else {
1221         /* Make sure just one bit is set */
1222         if ((Val & (Val - 1)) != 0) {
1223             Error ("Argument to TAM must be a power of two");
1224         }
1225     }
1226 }
1227
1228
1229
1230 static void PutTMAn (const InsDesc* Ins)
1231 /* Emit a TMAn instruction (HuC6280). Since this is a two byte instruction with
1232  * implicit addressing mode, the opcode byte in the table is actually the
1233  * second operand byte. The TAM instruction is the more generic form, it takes
1234  * an immediate argument.
1235  */
1236 {
1237     /* Emit the TMA opcode itself */
1238     Emit0 (0x43);
1239
1240     /* Emit the argument, which is the opcode from the table */
1241     Emit0 (Ins->BaseCode);
1242 }
1243
1244
1245
1246 static void PutTST (const InsDesc* Ins)
1247 /* Emit a TST instruction (HuC6280). */
1248 {
1249     ExprNode* Arg1;
1250     EffAddr   A;
1251
1252     /* The first argument is always an immediate byte */
1253     if (Tok != TOK_HASH) {
1254         ErrorSkip ("Invalid addressing mode");
1255         return;
1256     }
1257     NextTok ();
1258     Arg1 = Expression ();
1259
1260     /* Second argument follows */
1261     ConsumeComma ();
1262
1263     /* For the second argument, we use the standard function */
1264     if (EvalEA (Ins, &A)) {
1265
1266         /* No error, output code */
1267         Emit1 (A.Opcode, Arg1);
1268
1269         /* Check how many extension bytes are needed and output the instruction */
1270         switch (ExtBytes[A.AddrMode]) {
1271
1272             case 1:
1273                 EmitByte (A.Expr);
1274                 break;
1275
1276             case 2:
1277                 EmitWord (A.Expr);
1278                 break;
1279         }
1280     }
1281 }
1282
1283
1284
1285 static void PutJMP (const InsDesc* Ins)
1286 /* Handle the jump instruction for the 6502. Problem is that these chips have
1287  * a bug: If the address crosses a page, the upper byte gets not corrected and
1288  * the instruction will fail. The PutJmp function will add a linker assertion
1289  * to check for this case and is otherwise identical to PutAll.
1290  */
1291 {
1292     EffAddr A;
1293
1294     /* Evaluate the addressing mode used */
1295     if (EvalEA (Ins, &A)) {
1296
1297         /* Check for indirect addressing */
1298         if (A.AddrModeBit & AM65_ABS_IND) {
1299
1300             /* Compare the low byte of the expression to 0xFF to check for
1301              * a page cross. Be sure to use a copy of the expression otherwise
1302              * things will go weird later.
1303              */
1304             ExprNode* E = GenNE (GenByteExpr (CloneExpr (A.Expr)), 0xFF);
1305
1306             /* Generate the message */
1307             unsigned Msg = GetStringId ("\"jmp (abs)\" across page border");
1308
1309             /* Generate the assertion */
1310             AddAssertion (E, ASSERT_ACT_WARN, Msg);
1311         }
1312
1313         /* No error, output code */
1314         EmitCode (&A);
1315     }
1316 }
1317
1318
1319
1320 static void PutRTS (const InsDesc* Ins attribute ((unused)))
1321 /* Handle the RTS instruction for the 816. In smart mode emit a RTL opcode if
1322  * the enclosing scope is FAR.
1323  */
1324 {
1325     if (SmartMode && CurrentScope->AddrSize == ADDR_SIZE_FAR) {
1326         Emit0 (0x6B);       /* RTL */
1327     } else {
1328         Emit0 (0x60);       /* RTS */
1329     }
1330 }
1331
1332
1333
1334 static void PutAll (const InsDesc* Ins)
1335 /* Handle all other instructions */
1336 {
1337     EffAddr A;
1338
1339     /* Evaluate the addressing mode used */
1340     if (EvalEA (Ins, &A)) {
1341         /* No error, output code */
1342         EmitCode (&A);
1343     }
1344 }
1345
1346
1347
1348 /*****************************************************************************/
1349 /*                       Handler functions for SWEET16                       */
1350 /*****************************************************************************/
1351
1352
1353
1354 static void PutSweet16 (const InsDesc* Ins)
1355 /* Handle a generic sweet16 instruction */
1356 {
1357     EffAddr A;
1358
1359     /* Evaluate the addressing mode used */
1360     GetSweet16EA (&A);
1361
1362     /* From the possible addressing modes, remove the ones that are invalid
1363      * for this instruction or CPU.
1364      */
1365     A.AddrModeSet &= Ins->AddrMode;
1366
1367     /* Check if we have any adressing modes left */
1368     if (A.AddrModeSet == 0) {
1369         Error ("Illegal addressing mode");
1370         return;
1371     }
1372     A.AddrMode    = BitFind (A.AddrModeSet);
1373     A.AddrModeBit = (0x01UL << A.AddrMode);
1374
1375     /* Build the opcode */
1376     A.Opcode = Ins->BaseCode | Sweet16EATab[Ins->ExtCode][A.AddrMode] | A.Reg;
1377
1378     /* Check how many extension bytes are needed and output the instruction */
1379     switch (Sweet16ExtBytes[A.AddrMode]) {
1380
1381         case 0:
1382             Emit0 (A.Opcode);
1383             break;
1384
1385         case 1:
1386             Emit1 (A.Opcode, A.Expr);
1387             break;
1388
1389         case 2:
1390             Emit2 (A.Opcode, A.Expr);
1391             break;
1392
1393         default:
1394             Internal ("Invalid operand byte count: %u", Sweet16ExtBytes[A.AddrMode]);
1395
1396     }
1397 }
1398
1399
1400
1401 static void PutSweet16Branch (const InsDesc* Ins)
1402 /* Handle a sweet16 branch instruction */
1403 {
1404     EmitPCRel (Ins->BaseCode, GenBranchExpr (2), 1);
1405 }
1406
1407
1408
1409 /*****************************************************************************/
1410 /*                                   Code                                    */
1411 /*****************************************************************************/
1412
1413
1414
1415 static int CmpName (const void* Key, const void* Instr)
1416 /* Compare function for bsearch */
1417 {
1418     return strcmp ((const char*)Key, ((const InsDesc*) Instr)->Mnemonic);
1419 }
1420
1421
1422
1423 void SetCPU (cpu_t NewCPU)
1424 /* Set a new CPU */
1425 {
1426     /* Make sure the parameter is correct */
1427     CHECK (NewCPU < CPU_COUNT);
1428
1429     /* Check if we have support for the new CPU, if so, use it */
1430     if (InsTabs[NewCPU]) {
1431         CPU = NewCPU;
1432         InsTab = InsTabs[CPU];
1433     } else {
1434         Error ("CPU not supported");
1435     }
1436 }
1437
1438
1439
1440 cpu_t GetCPU (void)
1441 /* Return the current CPU */
1442 {
1443     return CPU;
1444 }
1445
1446
1447
1448 int FindInstruction (const char* Ident)
1449 /* Check if Ident is a valid mnemonic. If so, return the index in the
1450  * instruction table. If not, return -1.
1451  */
1452 {
1453     unsigned I;
1454     const InsDesc* ID;
1455     char Key[sizeof (ID->Mnemonic)];
1456
1457     /* Shortcut for the "none" CPU: If there are no instructions to search
1458      * for, bail out early.
1459      */
1460     if (InsTab->Count == 0) {
1461         /* Not found */
1462         return -1;
1463     }
1464
1465     /* Make a copy, and uppercase that copy */
1466     I = 0;
1467     while (Ident[I] != '\0') {
1468         /* If the identifier is longer than the longest mnemonic, it cannot
1469          * be one.
1470          */
1471         if (I >= sizeof (Key) - 1) {
1472             /* Not found, no need for further action */
1473             return -1;
1474         }
1475         Key[I] = toupper ((unsigned char)Ident[I]);
1476         ++I;
1477     }
1478     Key[I] = '\0';
1479
1480     /* Search for the key */
1481     ID = bsearch (Key, InsTab->Ins, InsTab->Count, sizeof (InsDesc), CmpName);
1482     if (ID == 0) {
1483         /* Not found */
1484         return -1;
1485     } else {
1486         /* Found, return the entry */
1487         return ID - InsTab->Ins;
1488     }
1489 }
1490
1491
1492
1493 void HandleInstruction (unsigned Index)
1494 /* Handle the mnemonic with the given index */
1495 {
1496     /* Safety check */
1497     PRECONDITION (Index < InsTab->Count);
1498
1499     /* Skip the mnemonic token */
1500     NextTok ();
1501
1502     /* Call the handler */
1503     InsTab->Ins[Index].Emit (&InsTab->Ins[Index]);
1504 }
1505
1506
1507