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