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