]> git.sur5r.net Git - cc65/blob - src/ca65/instr.c
Removed (pretty inconsistently used) tab chars from source code base.
[cc65] / src / ca65 / instr.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  instr.c                                  */
4 /*                                                                           */
5 /*             Instruction encoding for the ca65 macroassembler              */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2012, 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[26];
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     0,
788 #endif
789     (const InsTable*) &InsTabSweet16,
790     (const InsTable*) &InsTabHuC6280,
791     0,                                  /* Mitsubishi 740 */
792 };
793 const InsTable* InsTab = (const InsTable*) &InsTab6502;
794
795 /* Table to build the effective 65xx opcode from a base opcode and an
796  * addressing mode.
797  */
798 static unsigned char EATab[10][AM65I_COUNT] = {
799     {   /* Table 0 */
800         0x00, 0x00, 0x05, 0x0D, 0x0F, 0x15, 0x1D, 0x1F,
801         0x00, 0x19, 0x12, 0x00, 0x07, 0x11, 0x17, 0x01,
802         0x00, 0x00, 0x00, 0x03, 0x13, 0x09, 0x00, 0x09,
803         0x00, 0x00
804     },
805     {   /* Table 1 */
806         0x08, 0x08, 0x04, 0x0C, 0x00, 0x14, 0x1C, 0x00,
807         0x14, 0x1C, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00,
808         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
809         0x00, 0x00
810     },
811     {   /* Table 2 */
812         0x00, 0x00, 0x24, 0x2C, 0x0F, 0x34, 0x3C, 0x00,
813         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
814         0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00,
815         0x00, 0x00
816     },
817     {   /* Table 3 */
818         0x3A, 0x3A, 0xC6, 0xCE, 0x00, 0xD6, 0xDE, 0x00,
819         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
820         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
821         0x00, 0x00
822     },
823     {   /* Table 4 */
824         0x1A, 0x1A, 0xE6, 0xEE, 0x00, 0xF6, 0xFE, 0x00,
825         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
826         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
827         0x00, 0x00
828     },
829     {   /* Table 5 */
830         0x00, 0x00, 0x60, 0x98, 0x00, 0x70, 0x9E, 0x00,
831         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
832         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
833         0x00, 0x00
834     },
835     {   /* Table 6 */
836         0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
837         0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
838         0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
839         0x00, 0x00
840     },
841     {   /* Table 7 */
842         0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
843         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
844         0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
845         0x00, 0x00
846     },
847     {   /* Table 8 */
848         0x00, 0x40, 0x01, 0x41, 0x00, 0x09, 0x49, 0x00,
849         0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00,
850         0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
851         0x00, 0x00
852     },
853     {   /* Table 9 */
854         0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x30, 0x00,
855         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
856         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
857         0x00, 0x00
858     },
859 };
860
861 /* Table to build the effective SWEET16 opcode from a base opcode and an
862  * addressing mode.
863  */
864 static unsigned char Sweet16EATab[2][AMSW16I_COUNT] = {
865     {   /* Table 0 */
866         0x00, 0x00, 0x00, 0x00, 0x00,
867     },
868     {   /* Table 1 */
869         0x00, 0x00, 0x00, 0x40, 0x20,
870     },
871 };
872
873 /* Table that encodes the additional bytes for each 65xx instruction */
874 unsigned char ExtBytes[AM65I_COUNT] = {
875     0,          /* Implicit */
876     0,          /* Accu */
877     1,          /* Direct */
878     2,          /* Absolute */
879     3,          /* Absolute long */
880     1,          /* Direct,X */
881     2,          /* Absolute,X */
882     3,          /* Absolute long,X */
883     1,          /* Direct,Y */
884     2,          /* Absolute,Y */
885     1,          /* (Direct) */
886     2,          /* (Absolute) */
887     1,          /* [Direct] */
888     1,          /* (Direct),Y */
889     1,          /* [Direct],Y */
890     1,          /* (Direct,X) */
891     2,          /* (Absolute,X) */
892     1,          /* Relative short */
893     2,          /* Relative long */
894     1,          /* r,s */
895     1,          /* (r,s),y */
896     1,          /* Immidiate accu */
897     1,          /* Immidiate index */
898     1,          /* Immidiate byte */
899     2,          /* Blockmove (65816) */
900     7,          /* Block transfer (HuC6280) */
901 };
902
903 /* Table that encodes the additional bytes for each SWEET16 instruction */
904 static unsigned char Sweet16ExtBytes[AMSW16I_COUNT] = {
905     0,          /* AMSW16_IMP */
906     1,          /* AMSW16_BRA */
907     2,          /* AMSW16_IMM */
908     0,          /* AMSW16_IND */
909     0,          /* AMSW16_REG */
910 };
911
912
913
914 /*****************************************************************************/
915 /*                   Handler functions for 6502 derivates                    */
916 /*****************************************************************************/
917
918
919
920 static int EvalEA (const InsDesc* Ins, EffAddr* A)
921 /* Evaluate the effective address. All fields in A will be valid after calling
922  * this function. The function returns true on success and false on errors.
923  */
924 {
925     /* Get the set of possible addressing modes */
926     GetEA (A);
927
928     /* From the possible addressing modes, remove the ones that are invalid
929      * for this instruction or CPU.
930      */
931     A->AddrModeSet &= Ins->AddrMode;
932
933     /* If we have an expression, check it and remove any addressing modes that
934      * are too small for the expression size. Since we have to study the
935      * expression anyway, do also replace it by a simpler one if possible.
936      */
937     if (A->Expr) {
938         ExprDesc ED;
939         ED_Init (&ED);
940
941         /* Study the expression */
942         StudyExpr (A->Expr, &ED);
943
944         /* Simplify it if possible */
945         A->Expr = SimplifyExpr (A->Expr, &ED);
946
947         if (ED.AddrSize == ADDR_SIZE_DEFAULT) {
948             /* We don't know how big the expression is. If the instruction
949              * allows just one addressing mode, assume this as address size
950              * for the expression. Otherwise assume the default address size
951              * for data.
952              */
953             if ((A->AddrModeSet & ~AM65_ALL_ZP) == 0) {
954                 ED.AddrSize = ADDR_SIZE_ZP;
955             } else if ((A->AddrModeSet & ~AM65_ALL_ABS) == 0) {
956                 ED.AddrSize = ADDR_SIZE_ABS;
957             } else if ((A->AddrModeSet & ~AM65_ALL_FAR) == 0) {
958                 ED.AddrSize = ADDR_SIZE_FAR;
959             } else {
960                 ED.AddrSize = DataAddrSize;
961                 /* If the default address size of the data segment is unequal
962                  * to zero page addressing, but zero page addressing is 
963                  * allowed by the instruction, mark all symbols in the 
964                  * expression tree. This mark will be checked at end of 
965                  * assembly, and a warning is issued, if a zero page symbol
966                  * was guessed wrong here.
967                  */
968                 if (ED.AddrSize > ADDR_SIZE_ZP && (A->AddrModeSet & AM65_SET_ZP)) {
969                     ExprGuessedAddrSize (A->Expr, ADDR_SIZE_ZP);
970                 }
971             }
972         }
973
974         /* Check the size */
975         switch (ED.AddrSize) {
976
977             case ADDR_SIZE_ABS:
978                 A->AddrModeSet &= ~AM65_SET_ZP;
979                 break;
980
981             case ADDR_SIZE_FAR:
982                 A->AddrModeSet &= ~(AM65_SET_ZP | AM65_SET_ABS);
983                 break;
984         }
985
986         /* Free any resource associated with the expression desc */
987         ED_Done (&ED);
988     }
989
990     /* Check if we have any adressing modes left */
991     if (A->AddrModeSet == 0) {
992         Error ("Illegal addressing mode");
993         return 0;
994     }
995     A->AddrMode    = BitFind (A->AddrModeSet);
996     A->AddrModeBit = (0x01UL << A->AddrMode);
997
998     /* If the instruction has a one byte operand and immediate addressing is
999      * allowed but not used, check for an operand expression in the form
1000      * <label or >label, where label is a far or absolute label. If found,
1001      * emit a warning. This warning protects against a typo, where the '#'
1002      * for the immediate operand is omitted.
1003      */
1004     if (A->Expr && (Ins->AddrMode & AM65_ALL_IMM)                &&
1005         (A->AddrModeSet & (AM65_DIR | AM65_ABS | AM65_ABS_LONG)) &&
1006         ExtBytes[A->AddrMode] == 1) {
1007
1008         /* Found, check the expression */
1009         ExprNode* Left = A->Expr->Left;
1010         if ((A->Expr->Op == EXPR_BYTE0 || A->Expr->Op == EXPR_BYTE1) &&
1011             Left->Op == EXPR_SYMBOL                                  &&
1012             GetSymAddrSize (Left->V.Sym) != ADDR_SIZE_ZP) {
1013
1014             /* Output a warning */
1015             Warning (1, "Suspicious address expression");
1016         }
1017     }
1018
1019     /* Build the opcode */
1020     A->Opcode = Ins->BaseCode | EATab[Ins->ExtCode][A->AddrMode];
1021
1022     /* If feature force_range is active, and we have immediate addressing mode,
1023      * limit the expression to the maximum possible value.
1024      */
1025     if (A->AddrMode == AM65I_IMM_ACCU || A->AddrMode == AM65I_IMM_INDEX ||
1026         A->AddrMode == AM65I_IMM_IMPLICIT) {
1027         if (ForceRange && A->Expr) {
1028             A->Expr = MakeBoundedExpr (A->Expr, ExtBytes[A->AddrMode]);
1029         }
1030     }
1031
1032     /* Success */
1033     return 1;
1034 }
1035
1036
1037
1038 static void EmitCode (EffAddr* A)
1039 /* Output code for the data in A */
1040 {
1041     /* Check how many extension bytes are needed and output the instruction */
1042     switch (ExtBytes[A->AddrMode]) {
1043
1044         case 0:
1045             Emit0 (A->Opcode);
1046             break;
1047
1048         case 1:
1049             Emit1 (A->Opcode, A->Expr);
1050             break;
1051
1052         case 2:
1053             if (CPU == CPU_65816 && (A->AddrModeBit & (AM65_ABS | AM65_ABS_X | AM65_ABS_Y))) {
1054                 /* This is a 16 bit mode that uses an address. If in 65816,
1055                  * mode, force this address into 16 bit range to allow
1056                  * addressing inside a 64K segment.
1057                  */
1058                 Emit2 (A->Opcode, GenWordExpr (A->Expr));
1059             } else {
1060                 Emit2 (A->Opcode, A->Expr);
1061             }
1062             break;
1063
1064         case 3:
1065             /* Far argument */
1066             Emit3 (A->Opcode, A->Expr);
1067             break;
1068
1069         default:
1070             Internal ("Invalid operand byte count: %u", ExtBytes[A->AddrMode]);
1071
1072     }
1073 }
1074
1075
1076
1077 static long PutImmed8 (const InsDesc* Ins)
1078 /* Parse and emit an immediate 8 bit instruction. Return the value of the
1079  * operand if it's available and const.
1080  */
1081 {
1082     EffAddr A;
1083     long Val = -1;
1084
1085     /* Evaluate the addressing mode */
1086     if (EvalEA (Ins, &A) == 0) {
1087         /* An error occurred */
1088         return -1L;
1089     }
1090
1091     /* If we have an expression and it's const, get it's value */
1092     if (A.Expr) {
1093         (void) IsConstExpr (A.Expr, &Val);
1094     }
1095
1096     /* Check how many extension bytes are needed and output the instruction */
1097     switch (ExtBytes[A.AddrMode]) {
1098
1099         case 1:
1100             Emit1 (A.Opcode, A.Expr);
1101             break;
1102
1103         default:
1104             Internal ("Invalid operand byte count: %u", ExtBytes[A.AddrMode]);
1105     }
1106
1107     /* Return the expression value */
1108     return Val;
1109 }
1110
1111
1112
1113 static void PutPCRel8 (const InsDesc* Ins)
1114 /* Handle branches with a 8 bit distance */
1115 {
1116     EmitPCRel (Ins->BaseCode, GenBranchExpr (2), 1);
1117 }
1118
1119
1120
1121 static void PutPCRel16 (const InsDesc* Ins)
1122 /* Handle branches with an 16 bit distance and PER */
1123 {
1124     EmitPCRel (Ins->BaseCode, GenBranchExpr (3), 2);
1125 }
1126
1127
1128
1129 static void PutBlockMove (const InsDesc* Ins)
1130 /* Handle the blockmove instructions (65816) */
1131 {
1132     Emit0 (Ins->BaseCode);
1133     EmitByte (Expression ());
1134     ConsumeComma ();
1135     EmitByte (Expression ());
1136 }
1137
1138
1139
1140 static void PutBlockTransfer (const InsDesc* Ins)
1141 /* Handle the block transfer instructions (HuC6280) */
1142 {
1143     Emit0 (Ins->BaseCode);
1144     EmitWord (Expression ());
1145     ConsumeComma ();
1146     EmitWord (Expression ());
1147     ConsumeComma ();
1148     EmitWord (Expression ());
1149 }
1150
1151
1152
1153 static void PutBitBranch (const InsDesc* Ins)
1154 /* Handle 65C02 branch on bit condition */
1155 {
1156     Emit0 (Ins->BaseCode);
1157     EmitByte (Expression ());
1158     ConsumeComma ();
1159     EmitSigned (GenBranchExpr (1), 1);
1160 }
1161
1162
1163
1164 static void PutREP (const InsDesc* Ins)
1165 /* Emit a REP instruction, track register sizes */
1166 {
1167     /* Use the generic handler */
1168     long Val = PutImmed8 (Ins);
1169
1170     /* We track the status only for the 816 CPU and in smart mode */
1171     if (CPU == CPU_65816 && SmartMode) {
1172
1173         /* Check the range for Val. */
1174         if (Val < 0) {
1175             /* We had an error */
1176             Warning (1, "Cannot track processor status byte");
1177         } else {
1178             if (Val & 0x10) {
1179                 /* Index registers to 16 bit */
1180                 ExtBytes[AM65I_IMM_INDEX] = 2;
1181             }
1182             if (Val & 0x20) {
1183                 /* Accu to 16 bit */
1184                 ExtBytes[AM65I_IMM_ACCU] = 2;
1185             }
1186         }
1187     }
1188 }
1189
1190
1191
1192 static void PutSEP (const InsDesc* Ins)
1193 /* Emit a SEP instruction (65816), track register sizes */
1194 {
1195     /* Use the generic handler */
1196     long Val = PutImmed8 (Ins);
1197
1198     /* We track the status only for the 816 CPU and in smart mode */
1199     if (CPU == CPU_65816 && SmartMode) {
1200
1201         /* Check the range for Val. */
1202         if (Val < 0) {
1203             /* We had an error */
1204             Warning (1, "Cannot track processor status byte");
1205         } else {
1206             if (Val & 0x10) {
1207                 /* Index registers to 8 bit */
1208                 ExtBytes[AM65I_IMM_INDEX] = 1;
1209             }
1210             if (Val & 0x20) {
1211                 /* Accu to 8 bit */
1212                 ExtBytes[AM65I_IMM_ACCU] = 1;
1213             }
1214         }
1215     }
1216 }
1217
1218
1219
1220 static void PutTAMn (const InsDesc* Ins)
1221 /* Emit a TAMn instruction (HuC6280). Since this is a two byte instruction with
1222  * implicit addressing mode, the opcode byte in the table is actually the
1223  * second operand byte. The TAM instruction is the more generic form, it takes
1224  * an immediate argument.
1225  */
1226 {
1227     /* Emit the TAM opcode itself */
1228     Emit0 (0x53);
1229
1230     /* Emit the argument, which is the opcode from the table */
1231     Emit0 (Ins->BaseCode);
1232 }
1233
1234
1235
1236 static void PutTMA (const InsDesc* Ins)
1237 /* Emit a TMA instruction (HuC6280) with an immediate argument. Only one bit
1238  * in the argument byte may be set.
1239  */
1240 {
1241     /* Use the generic handler */
1242     long Val = PutImmed8 (Ins);
1243
1244     /* Check the range for Val. */
1245     if (Val < 0) {
1246         /* We had an error */
1247         Warning (1, "Cannot check argument of TMA instruction");
1248     } else {
1249         /* Make sure just one bit is set */
1250         if ((Val & (Val - 1)) != 0) {
1251             Error ("Argument to TAM must be a power of two");
1252         }
1253     }
1254 }
1255
1256
1257
1258 static void PutTMAn (const InsDesc* Ins)
1259 /* Emit a TMAn instruction (HuC6280). Since this is a two byte instruction with
1260  * implicit addressing mode, the opcode byte in the table is actually the
1261  * second operand byte. The TAM instruction is the more generic form, it takes
1262  * an immediate argument.
1263  */
1264 {
1265     /* Emit the TMA opcode itself */
1266     Emit0 (0x43);
1267
1268     /* Emit the argument, which is the opcode from the table */
1269     Emit0 (Ins->BaseCode);
1270 }
1271
1272
1273
1274 static void PutTST (const InsDesc* Ins)
1275 /* Emit a TST instruction (HuC6280). */
1276 {
1277     ExprNode* Arg1;
1278     EffAddr   A;
1279
1280     /* The first argument is always an immediate byte */
1281     if (CurTok.Tok != TOK_HASH) {
1282         ErrorSkip ("Invalid addressing mode");
1283         return;
1284     }
1285     NextTok ();
1286     Arg1 = Expression ();
1287
1288     /* Second argument follows */
1289     ConsumeComma ();
1290
1291     /* For the second argument, we use the standard function */
1292     if (EvalEA (Ins, &A)) {
1293
1294         /* No error, output code */
1295         Emit1 (A.Opcode, Arg1);
1296
1297         /* Check how many extension bytes are needed and output the instruction */
1298         switch (ExtBytes[A.AddrMode]) {
1299
1300             case 1:
1301                 EmitByte (A.Expr);
1302                 break;
1303
1304             case 2:
1305                 EmitWord (A.Expr);
1306                 break;
1307         }
1308     }
1309 }
1310
1311
1312
1313 static void PutJMP (const InsDesc* Ins)
1314 /* Handle the jump instruction for the 6502. Problem is that these chips have
1315  * a bug: If the address crosses a page, the upper byte gets not corrected and
1316  * the instruction will fail. The PutJmp function will add a linker assertion
1317  * to check for this case and is otherwise identical to PutAll.
1318  */
1319 {
1320     EffAddr A;
1321
1322     /* Evaluate the addressing mode used */
1323     if (EvalEA (Ins, &A)) {
1324
1325         /* Check for indirect addressing */
1326         if (A.AddrModeBit & AM65_ABS_IND) {
1327
1328             /* Compare the low byte of the expression to 0xFF to check for
1329              * a page cross. Be sure to use a copy of the expression otherwise
1330              * things will go weird later.
1331              */
1332             ExprNode* E = GenNE (GenByteExpr (CloneExpr (A.Expr)), 0xFF);
1333
1334             /* Generate the message */
1335             unsigned Msg = GetStringId ("\"jmp (abs)\" across page border");
1336
1337             /* Generate the assertion */
1338             AddAssertion (E, ASSERT_ACT_WARN, Msg);
1339         }
1340
1341         /* No error, output code */
1342         EmitCode (&A);
1343     }
1344 }
1345
1346
1347
1348 static void PutRTS (const InsDesc* Ins attribute ((unused)))
1349 /* Handle the RTS instruction for the 816. In smart mode emit a RTL opcode if
1350  * the enclosing scope is FAR.
1351  */
1352 {
1353     if (SmartMode && CurrentScope->AddrSize == ADDR_SIZE_FAR) {
1354         Emit0 (0x6B);       /* RTL */
1355     } else {
1356         Emit0 (0x60);       /* RTS */
1357     }
1358 }
1359
1360
1361
1362 static void PutAll (const InsDesc* Ins)
1363 /* Handle all other instructions */
1364 {
1365     EffAddr A;
1366
1367     /* Evaluate the addressing mode used */
1368     if (EvalEA (Ins, &A)) {
1369         /* No error, output code */
1370         EmitCode (&A);
1371     }
1372 }
1373
1374
1375
1376 /*****************************************************************************/
1377 /*                       Handler functions for SWEET16                       */
1378 /*****************************************************************************/
1379
1380
1381
1382 static void PutSweet16 (const InsDesc* Ins)
1383 /* Handle a generic sweet16 instruction */
1384 {
1385     EffAddr A;
1386
1387     /* Evaluate the addressing mode used */
1388     GetSweet16EA (&A);
1389
1390     /* From the possible addressing modes, remove the ones that are invalid
1391      * for this instruction or CPU.
1392      */
1393     A.AddrModeSet &= Ins->AddrMode;
1394
1395     /* Check if we have any adressing modes left */
1396     if (A.AddrModeSet == 0) {
1397         Error ("Illegal addressing mode");
1398         return;
1399     }
1400     A.AddrMode    = BitFind (A.AddrModeSet);
1401     A.AddrModeBit = (0x01UL << A.AddrMode);
1402
1403     /* Build the opcode */
1404     A.Opcode = Ins->BaseCode | Sweet16EATab[Ins->ExtCode][A.AddrMode] | A.Reg;
1405
1406     /* Check how many extension bytes are needed and output the instruction */
1407     switch (Sweet16ExtBytes[A.AddrMode]) {
1408
1409         case 0:
1410             Emit0 (A.Opcode);
1411             break;
1412
1413         case 1:
1414             Emit1 (A.Opcode, A.Expr);
1415             break;
1416
1417         case 2:
1418             Emit2 (A.Opcode, A.Expr);
1419             break;
1420
1421         default:
1422             Internal ("Invalid operand byte count: %u", Sweet16ExtBytes[A.AddrMode]);
1423
1424     }
1425 }
1426
1427
1428
1429 static void PutSweet16Branch (const InsDesc* Ins)
1430 /* Handle a sweet16 branch instruction */
1431 {
1432     EmitPCRel (Ins->BaseCode, GenBranchExpr (2), 1);
1433 }
1434
1435
1436
1437 /*****************************************************************************/
1438 /*                                   Code                                    */
1439 /*****************************************************************************/
1440
1441
1442
1443 static int CmpName (const void* Key, const void* Instr)
1444 /* Compare function for bsearch */
1445 {
1446     return strcmp ((const char*)Key, ((const InsDesc*) Instr)->Mnemonic);
1447 }
1448
1449
1450
1451 void SetCPU (cpu_t NewCPU)
1452 /* Set a new CPU */
1453 {
1454     /* Make sure the parameter is correct */
1455     CHECK (NewCPU < CPU_COUNT);
1456
1457     /* Check if we have support for the new CPU, if so, use it */
1458     if (NewCPU != CPU_UNKNOWN && InsTabs[NewCPU]) {
1459         CPU = NewCPU;
1460         InsTab = InsTabs[CPU];
1461     } else {
1462         Error ("CPU not supported");
1463     }
1464 }
1465
1466
1467
1468 cpu_t GetCPU (void)
1469 /* Return the current CPU */
1470 {
1471     return CPU;
1472 }
1473
1474
1475
1476 int FindInstruction (const StrBuf* Ident)
1477 /* Check if Ident is a valid mnemonic. If so, return the index in the
1478  * instruction table. If not, return -1.
1479  */
1480 {
1481     unsigned I;
1482     const InsDesc* ID;
1483     char Key[sizeof (ID->Mnemonic)];
1484
1485     /* Shortcut for the "none" CPU: If there are no instructions to search
1486      * for, bail out early.
1487      */
1488     if (InsTab->Count == 0) {
1489         /* Not found */
1490         return -1;
1491     }
1492
1493     /* Make a copy, and uppercase that copy */
1494     I = 0;
1495     while (I < SB_GetLen (Ident)) {
1496         /* If the identifier is longer than the longest mnemonic, it cannot
1497          * be one.
1498          */
1499         if (I >= sizeof (Key) - 1) {
1500             /* Not found, no need for further action */
1501             return -1;
1502         }
1503         Key[I] = toupper ((unsigned char)SB_AtUnchecked (Ident, I));
1504         ++I;
1505     }
1506     Key[I] = '\0';
1507
1508     /* Search for the key */
1509     ID = bsearch (Key, InsTab->Ins, InsTab->Count, sizeof (InsDesc), CmpName);
1510     if (ID == 0) {
1511         /* Not found */
1512         return -1;
1513     } else {
1514         /* Found, return the entry */
1515         return ID - InsTab->Ins;
1516     }
1517 }
1518
1519
1520
1521 void HandleInstruction (unsigned Index)
1522 /* Handle the mnemonic with the given index */
1523 {
1524     /* Safety check */
1525     PRECONDITION (Index < InsTab->Count);
1526
1527     /* Skip the mnemonic token */
1528     NextTok ();
1529
1530     /* Call the handler */
1531     InsTab->Ins[Index].Emit (&InsTab->Ins[Index]);
1532 }
1533
1534
1535