]> git.sur5r.net Git - cc65/blob - src/ca65/instr.c
5d8fc0043275064aa8513bef431b5c41bb39e87b
[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",  0x4000010, 0x5c, 1, PutAll },
520         { "JMP",  0x4010818, 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 /* Instruction table for the SWEET16 pseudo CPU */
589 static const struct {
590     unsigned Count;
591     InsDesc  Ins[26];
592 } InsTabSweet16 = {
593     sizeof (InsTabSweet16.Ins) / sizeof (InsTabSweet16.Ins[0]),
594     {
595         { "ADD",  AMSW16_REG,              0xA0, 0, PutSweet16 },
596         { "BC",   AMSW16_BRA,              0x03, 0, PutSweet16Branch },
597         { "BK",   AMSW16_IMP,              0x0A, 0, PutSweet16 },
598         { "BM",   AMSW16_BRA,              0x05, 0, PutSweet16Branch },
599         { "BM1",  AMSW16_BRA,              0x08, 0, PutSweet16Branch },
600         { "BNC",  AMSW16_BRA,              0x02, 0, PutSweet16Branch },
601         { "BNM1", AMSW16_BRA,              0x09, 0, PutSweet16Branch },
602         { "BNZ",  AMSW16_BRA,              0x07, 0, PutSweet16Branch },
603         { "BP",   AMSW16_BRA,              0x04, 0, PutSweet16Branch },
604         { "BR",   AMSW16_BRA,              0x01, 0, PutSweet16Branch },
605         { "BS",   AMSW16_BRA,              0x0B, 0, PutSweet16Branch },
606         { "BZ",   AMSW16_BRA,              0x06, 0, PutSweet16Branch },
607         { "CPR",  AMSW16_REG,              0xD0, 0, PutSweet16 },
608         { "DCR",  AMSW16_REG,              0xF0, 0, PutSweet16 },
609         { "INR",  AMSW16_REG,              0xE0, 0, PutSweet16 },
610         { "LD",   AMSW16_REG | AMSW16_IND, 0x00, 1, PutSweet16 },
611         { "LDD",  AMSW16_IND,              0x60, 0, PutSweet16 },
612         { "POP",  AMSW16_IND,              0x80, 0, PutSweet16 },
613         { "POPD", AMSW16_IND,              0xC0, 0, PutSweet16 },
614         { "RS",   AMSW16_IMP,              0x0B, 0, PutSweet16 },
615         { "RTN",  AMSW16_IMP,              0x00, 0, PutSweet16 },
616         { "SET",  AMSW16_IMM,              0x10, 0, PutSweet16 },
617         { "ST",   AMSW16_REG | AMSW16_IND, 0x10, 1, PutSweet16 },
618         { "STD",  AMSW16_IND,              0x70, 0, PutSweet16 },
619         { "STP",  AMSW16_IND,              0x90, 0, PutSweet16 },
620         { "SUB",  AMSW16_REG,              0xB0, 0, PutSweet16 },
621     }
622 };
623
624 /* Instruction table for the HuC6280 (the CPU used in the PC engine) */
625 static const struct {
626     unsigned Count;
627     InsDesc  Ins[135];
628 } InsTabHuC6280 = {
629     sizeof (InsTabHuC6280.Ins) / sizeof (InsTabHuC6280.Ins[0]),
630     {
631         { "ADC",  0x080A66C, 0x60, 0, PutAll },
632         { "AND",  0x080A66C, 0x20, 0, PutAll },
633         { "ASL",  0x000006e, 0x02, 1, PutAll },
634         { "BBR0", 0x0000000, 0x0F, 0, PutBitBranch },
635         { "BBR1", 0x0000000, 0x1F, 0, PutBitBranch },
636         { "BBR2", 0x0000000, 0x2F, 0, PutBitBranch },
637         { "BBR3", 0x0000000, 0x3F, 0, PutBitBranch },
638         { "BBR4", 0x0000000, 0x4F, 0, PutBitBranch },
639         { "BBR5", 0x0000000, 0x5F, 0, PutBitBranch },
640         { "BBR6", 0x0000000, 0x6F, 0, PutBitBranch },
641         { "BBR7", 0x0000000, 0x7F, 0, PutBitBranch },
642         { "BBS0", 0x0000000, 0x8F, 0, PutBitBranch },
643         { "BBS1", 0x0000000, 0x9F, 0, PutBitBranch },
644         { "BBS2", 0x0000000, 0xAF, 0, PutBitBranch },
645         { "BBS3", 0x0000000, 0xBF, 0, PutBitBranch },
646         { "BBS4", 0x0000000, 0xCF, 0, PutBitBranch },
647         { "BBS5", 0x0000000, 0xDF, 0, PutBitBranch },
648         { "BBS6", 0x0000000, 0xEF, 0, PutBitBranch },
649         { "BBS7", 0x0000000, 0xFF, 0, PutBitBranch },
650         { "BCC",  0x0020000, 0x90, 0, PutPCRel8 },
651         { "BCS",  0x0020000, 0xb0, 0, PutPCRel8 },
652         { "BEQ",  0x0020000, 0xf0, 0, PutPCRel8 },
653         { "BIT",  0x0A0006C, 0x00, 2, PutAll },
654         { "BMI",  0x0020000, 0x30, 0, PutPCRel8 },
655         { "BNE",  0x0020000, 0xd0, 0, PutPCRel8 },
656         { "BPL",  0x0020000, 0x10, 0, PutPCRel8 },
657         { "BRA",  0x0020000, 0x80, 0, PutPCRel8 },
658         { "BRK",  0x0000001, 0x00, 0, PutAll },
659         { "BSR",  0x0020000, 0x44, 0, PutPCRel8 },
660         { "BVC",  0x0020000, 0x50, 0, PutPCRel8 },
661         { "BVS",  0x0020000, 0x70, 0, PutPCRel8 },
662         { "CLA",  0x0000001, 0x62, 0, PutAll },
663         { "CLC",  0x0000001, 0x18, 0, PutAll },
664         { "CLD",  0x0000001, 0xd8, 0, PutAll },
665         { "CLI",  0x0000001, 0x58, 0, PutAll },
666         { "CLV",  0x0000001, 0xb8, 0, PutAll },
667         { "CLX",  0x0000001, 0x82, 0, PutAll },
668         { "CLY",  0x0000001, 0xc2, 0, PutAll },
669         { "CMP",  0x080A66C, 0xc0, 0, PutAll },
670         { "CPX",  0x080000C, 0xe0, 1, PutAll },
671         { "CPY",  0x080000C, 0xc0, 1, PutAll },
672         { "CSH",  0x0000001, 0xd4, 0, PutAll },
673         { "CSL",  0x0000001, 0x54, 0, PutAll },
674         { "DEA",  0x0000001, 0x00, 3, PutAll },   /* == DEC */
675         { "DEC",  0x000006F, 0x00, 3, PutAll },
676         { "DEX",  0x0000001, 0xca, 0, PutAll },
677         { "DEY",  0x0000001, 0x88, 0, PutAll },
678         { "EOR",  0x080A66C, 0x40, 0, PutAll },
679         { "INA",  0x0000001, 0x00, 4, PutAll },   /* == INC */
680         { "INC",  0x000006f, 0x00, 4, PutAll },
681         { "INX",  0x0000001, 0xe8, 0, PutAll },
682         { "INY",  0x0000001, 0xc8, 0, PutAll },
683         { "JMP",  0x0010808, 0x4c, 6, PutAll },
684         { "JSR",  0x0000008, 0x20, 7, PutAll },
685         { "LDA",  0x080A66C, 0xa0, 0, PutAll },
686         { "LDX",  0x080030C, 0xa2, 1, PutAll },
687         { "LDY",  0x080006C, 0xa0, 1, PutAll },
688         { "LSR",  0x000006F, 0x42, 1, PutAll },
689         { "NOP",  0x0000001, 0xea, 0, PutAll },
690         { "ORA",  0x080A66C, 0x00, 0, PutAll },
691         { "PHA",  0x0000001, 0x48, 0, PutAll },
692         { "PHP",  0x0000001, 0x08, 0, PutAll },
693         { "PHX",  0x0000001, 0xda, 0, PutAll },
694         { "PHY",  0x0000001, 0x5a, 0, PutAll },
695         { "PLA",  0x0000001, 0x68, 0, PutAll },
696         { "PLP",  0x0000001, 0x28, 0, PutAll },
697         { "PLX",  0x0000001, 0xfa, 0, PutAll },
698         { "PLY",  0x0000001, 0x7a, 0, PutAll },
699         { "RMB0", 0x0000004, 0x07, 1, PutAll },
700         { "RMB1", 0x0000004, 0x17, 1, PutAll },
701         { "RMB2", 0x0000004, 0x27, 1, PutAll },
702         { "RMB3", 0x0000004, 0x37, 1, PutAll },
703         { "RMB4", 0x0000004, 0x47, 1, PutAll },
704         { "RMB5", 0x0000004, 0x57, 1, PutAll },
705         { "RMB6", 0x0000004, 0x67, 1, PutAll },
706         { "RMB7", 0x0000004, 0x77, 1, PutAll },
707         { "ROL",  0x000006F, 0x22, 1, PutAll },
708         { "ROR",  0x000006F, 0x62, 1, PutAll },
709         { "RTI",  0x0000001, 0x40, 0, PutAll },
710         { "RTS",  0x0000001, 0x60, 0, PutAll },
711         { "SBC",  0x080A66C, 0xe0, 0, PutAll },
712         { "SAX",  0x0000001, 0x22, 0, PutAll },
713         { "SAY",  0x0000001, 0x42, 0, PutAll },
714         { "SEC",  0x0000001, 0x38, 0, PutAll },
715         { "SED",  0x0000001, 0xf8, 0, PutAll },
716         { "SEI",  0x0000001, 0x78, 0, PutAll },
717         { "SET",  0x0000001, 0xf4, 0, PutAll },
718         { "SMB0", 0x0000004, 0x87, 1, PutAll },
719         { "SMB1", 0x0000004, 0x97, 1, PutAll },
720         { "SMB2", 0x0000004, 0xA7, 1, PutAll },
721         { "SMB3", 0x0000004, 0xB7, 1, PutAll },
722         { "SMB4", 0x0000004, 0xC7, 1, PutAll },
723         { "SMB5", 0x0000004, 0xD7, 1, PutAll },
724         { "SMB6", 0x0000004, 0xE7, 1, PutAll },
725         { "SMB7", 0x0000004, 0xF7, 1, PutAll },
726         { "ST0",  0x0800000, 0x03, 1, PutAll },
727         { "ST1",  0x0800000, 0x13, 1, PutAll },
728         { "ST2",  0x0800000, 0x23, 1, PutAll },
729         { "STA",  0x000A66C, 0x80, 0, PutAll },
730         { "STX",  0x000010c, 0x82, 1, PutAll },
731         { "STY",  0x000002c, 0x80, 1, PutAll },
732         { "STZ",  0x000006c, 0x04, 5, PutAll },
733         { "SXY",  0x0000001, 0x02, 0, PutAll },
734         { "TAI",  0x2000000, 0xf3, 0, PutBlockTransfer },
735         { "TAM",  0x0800000, 0x53, 1, PutAll },
736         { "TAM0", 0x0000001, 0x01, 0, PutTAMn},
737         { "TAM1", 0x0000001, 0x02, 0, PutTAMn},
738         { "TAM2", 0x0000001, 0x04, 0, PutTAMn},
739         { "TAM3", 0x0000001, 0x08, 0, PutTAMn},
740         { "TAM4", 0x0000001, 0x10, 0, PutTAMn},
741         { "TAM5", 0x0000001, 0x20, 0, PutTAMn},
742         { "TAM6", 0x0000001, 0x40, 0, PutTAMn},
743         { "TAM7", 0x0000001, 0x80, 0, PutTAMn},
744         { "TAX",  0x0000001, 0xaa, 0, PutAll },
745         { "TAY",  0x0000001, 0xa8, 0, PutAll },
746         { "TDD",  0x2000000, 0xc3, 0, PutBlockTransfer },
747         { "TIA",  0x2000000, 0xe3, 0, PutBlockTransfer },
748         { "TII",  0x2000000, 0x73, 0, PutBlockTransfer },
749         { "TIN",  0x2000000, 0xD3, 0, PutBlockTransfer },
750         { "TMA",  0x0800000, 0x43, 1, PutTMA },
751         { "TMA0", 0x0000001, 0x01, 0, PutTMAn},
752         { "TMA1", 0x0000001, 0x02, 0, PutTMAn},
753         { "TMA2", 0x0000001, 0x04, 0, PutTMAn},
754         { "TMA3", 0x0000001, 0x08, 0, PutTMAn},
755         { "TMA4", 0x0000001, 0x10, 0, PutTMAn},
756         { "TMA5", 0x0000001, 0x20, 0, PutTMAn},
757         { "TMA6", 0x0000001, 0x40, 0, PutTMAn},
758         { "TMA7", 0x0000001, 0x80, 0, PutTMAn},
759         { "TRB",  0x000000c, 0x10, 1, PutAll },
760         { "TSB",  0x000000c, 0x00, 1, PutAll },
761         { "TST",  0x000006c, 0x83, 9, PutTST },
762         { "TSX",  0x0000001, 0xba, 0, PutAll },
763         { "TXA",  0x0000001, 0x8a, 0, PutAll },
764         { "TXS",  0x0000001, 0x9a, 0, PutAll },
765         { "TYA",  0x0000001, 0x98, 0, PutAll }
766     }
767 };
768
769
770
771 /* An array with instruction tables */
772 static const InsTable* InsTabs[CPU_COUNT] = {
773     (const InsTable*) &InsTabNone,
774     (const InsTable*) &InsTab6502,
775     (const InsTable*) &InsTab6502X,
776     (const InsTable*) &InsTab65SC02,
777     (const InsTable*) &InsTab65C02,
778     (const InsTable*) &InsTab65816,
779     (const InsTable*) &InsTabSweet16,
780     (const InsTable*) &InsTabHuC6280,
781     0,                                  /* Mitsubishi 740 */
782 };
783 const InsTable* InsTab = (const InsTable*) &InsTab6502;
784
785 /* Table to build the effective 65xx opcode from a base opcode and an
786  * addressing mode.
787  */
788 static unsigned char EATab[10][AM65I_COUNT] = {
789     {   /* Table 0 */
790         0x00, 0x00, 0x05, 0x0D, 0x0F, 0x15, 0x1D, 0x1F,
791         0x00, 0x19, 0x12, 0x00, 0x07, 0x11, 0x17, 0x01,
792         0x00, 0x00, 0x00, 0x03, 0x13, 0x09, 0x00, 0x09,
793         0x00, 0x00, 0x00
794     },
795     {   /* Table 1 */
796         0x08, 0x08, 0x04, 0x0C, 0x00, 0x14, 0x1C, 0x00,
797         0x14, 0x1C, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00,
798         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
799         0x00, 0x00, 0x80
800     },
801     {   /* Table 2 */
802         0x00, 0x00, 0x24, 0x2C, 0x0F, 0x34, 0x3C, 0x00,
803         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
804         0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00,
805         0x00, 0x00, 0x00
806     },
807     {   /* Table 3 */
808         0x3A, 0x3A, 0xC6, 0xCE, 0x00, 0xD6, 0xDE, 0x00,
809         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
810         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
811         0x00, 0x00, 0x00
812     },
813     {   /* Table 4 */
814         0x1A, 0x1A, 0xE6, 0xEE, 0x00, 0xF6, 0xFE, 0x00,
815         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
816         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
817         0x00, 0x00, 0x00
818     },
819     {   /* Table 5 */
820         0x00, 0x00, 0x60, 0x98, 0x00, 0x70, 0x9E, 0x00,
821         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
822         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
823         0x00, 0x00, 0x00
824     },
825     {   /* Table 6 */
826         0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
827         0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x30, 0x00,
828         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
829         0x00, 0x00, 0x90
830     },
831     {   /* Table 7 */
832         0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
833         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
834         0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
835         0x00, 0x00, 0x00
836     },
837     {   /* Table 8 */
838         0x00, 0x40, 0x01, 0x41, 0x00, 0x09, 0x49, 0x00,
839         0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00,
840         0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
841         0x00, 0x00, 0x00
842     },
843     {   /* Table 9 */
844         0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x30, 0x00,
845         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
846         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
847         0x00, 0x00, 0x00
848     },
849 };
850
851 /* Table to build the effective SWEET16 opcode from a base opcode and an
852  * addressing mode.
853  */
854 static unsigned char Sweet16EATab[2][AMSW16I_COUNT] = {
855     {   /* Table 0 */
856         0x00, 0x00, 0x00, 0x00, 0x00,
857     },
858     {   /* Table 1 */
859         0x00, 0x00, 0x00, 0x40, 0x20,
860     },
861 };
862
863 /* Table that encodes the additional bytes for each 65xx instruction */
864 unsigned char ExtBytes[AM65I_COUNT] = {
865     0,          /* Implicit */
866     0,          /* Accu */
867     1,          /* Direct */
868     2,          /* Absolute */
869     3,          /* Absolute long */
870     1,          /* Direct,X */
871     2,          /* Absolute,X */
872     3,          /* Absolute long,X */
873     1,          /* Direct,Y */
874     2,          /* Absolute,Y */
875     1,          /* (Direct) */
876     2,          /* (Absolute) */
877     1,          /* [Direct] */
878     1,          /* (Direct),Y */
879     1,          /* [Direct],Y */
880     1,          /* (Direct,X) */
881     2,          /* (Absolute,X) */
882     1,          /* Relative short */
883     2,          /* Relative long */
884     1,          /* r,s */
885     1,          /* (r,s),y */
886     1,          /* Immidiate accu */
887     1,          /* Immidiate index */
888     1,          /* Immidiate byte */
889     2,          /* Blockmove (65816) */
890     7,          /* Block transfer (HuC6280) */
891     2,          /* Absolute Indirect long */
892 };
893
894 /* Table that encodes the additional bytes for each SWEET16 instruction */
895 static unsigned char Sweet16ExtBytes[AMSW16I_COUNT] = {
896     0,          /* AMSW16_IMP */
897     1,          /* AMSW16_BRA */
898     2,          /* AMSW16_IMM */
899     0,          /* AMSW16_IND */
900     0,          /* AMSW16_REG */
901 };
902
903
904
905 /*****************************************************************************/
906 /*                   Handler functions for 6502 derivates                    */
907 /*****************************************************************************/
908
909
910
911 static int EvalEA (const InsDesc* Ins, EffAddr* A)
912 /* Evaluate the effective address. All fields in A will be valid after calling
913  * this function. The function returns true on success and false on errors.
914  */
915 {
916     /* Get the set of possible addressing modes */
917     GetEA (A);
918
919     /* From the possible addressing modes, remove the ones that are invalid
920      * for this instruction or CPU.
921      */
922     A->AddrModeSet &= Ins->AddrMode;
923
924     /* If we have an expression, check it and remove any addressing modes that
925      * are too small for the expression size. Since we have to study the
926      * expression anyway, do also replace it by a simpler one if possible.
927      */
928     if (A->Expr) {
929         ExprDesc ED;
930         ED_Init (&ED);
931
932         /* Study the expression */
933         StudyExpr (A->Expr, &ED);
934
935         /* Simplify it if possible */
936         A->Expr = SimplifyExpr (A->Expr, &ED);
937
938         if (ED.AddrSize == ADDR_SIZE_DEFAULT) {
939             /* We don't know how big the expression is. If the instruction
940              * allows just one addressing mode, assume this as address size
941              * for the expression. Otherwise assume the default address size
942              * for data.
943              */
944             if ((A->AddrModeSet & ~AM65_ALL_ZP) == 0) {
945                 ED.AddrSize = ADDR_SIZE_ZP;
946             } else if ((A->AddrModeSet & ~AM65_ALL_ABS) == 0) {
947                 ED.AddrSize = ADDR_SIZE_ABS;
948             } else if ((A->AddrModeSet & ~AM65_ALL_FAR) == 0) {
949                 ED.AddrSize = ADDR_SIZE_FAR;
950             } else {
951                 ED.AddrSize = DataAddrSize;
952                 /* If the default address size of the data segment is unequal
953                  * to zero page addressing, but zero page addressing is 
954                  * allowed by the instruction, mark all symbols in the 
955                  * expression tree. This mark will be checked at end of 
956                  * assembly, and a warning is issued, if a zero page symbol
957                  * was guessed wrong here.
958                  */
959                 if (ED.AddrSize > ADDR_SIZE_ZP && (A->AddrModeSet & AM65_SET_ZP)) {
960                     ExprGuessedAddrSize (A->Expr, ADDR_SIZE_ZP);
961                 }
962             }
963         }
964
965         /* Check the size */
966         switch (ED.AddrSize) {
967
968             case ADDR_SIZE_ABS:
969                 A->AddrModeSet &= ~AM65_SET_ZP;
970                 break;
971
972             case ADDR_SIZE_FAR:
973                 A->AddrModeSet &= ~(AM65_SET_ZP | AM65_SET_ABS);
974                 break;
975         }
976
977         /* Free any resource associated with the expression desc */
978         ED_Done (&ED);
979     }
980
981     /* Check if we have any adressing modes left */
982     if (A->AddrModeSet == 0) {
983         Error ("Illegal addressing mode");
984         return 0;
985     }
986     A->AddrMode    = BitFind (A->AddrModeSet);
987     A->AddrModeBit = (0x01UL << A->AddrMode);
988
989     /* If the instruction has a one byte operand and immediate addressing is
990      * allowed but not used, check for an operand expression in the form
991      * <label or >label, where label is a far or absolute label. If found,
992      * emit a warning. This warning protects against a typo, where the '#'
993      * for the immediate operand is omitted.
994      */
995     if (A->Expr && (Ins->AddrMode & AM65_ALL_IMM)                &&
996         (A->AddrModeSet & (AM65_DIR | AM65_ABS | AM65_ABS_LONG)) &&
997         ExtBytes[A->AddrMode] == 1) {
998
999         /* Found, check the expression */
1000         ExprNode* Left = A->Expr->Left;
1001         if ((A->Expr->Op == EXPR_BYTE0 || A->Expr->Op == EXPR_BYTE1) &&
1002             Left->Op == EXPR_SYMBOL                                  &&
1003             GetSymAddrSize (Left->V.Sym) != ADDR_SIZE_ZP) {
1004
1005             /* Output a warning */
1006             Warning (1, "Suspicious address expression");
1007         }
1008     }
1009
1010     /* Build the opcode */
1011     A->Opcode = Ins->BaseCode | EATab[Ins->ExtCode][A->AddrMode];
1012
1013     /* If feature force_range is active, and we have immediate addressing mode,
1014      * limit the expression to the maximum possible value.
1015      */
1016     if (A->AddrMode == AM65I_IMM_ACCU || A->AddrMode == AM65I_IMM_INDEX ||
1017         A->AddrMode == AM65I_IMM_IMPLICIT) {
1018         if (ForceRange && A->Expr) {
1019             A->Expr = MakeBoundedExpr (A->Expr, ExtBytes[A->AddrMode]);
1020         }
1021     }
1022
1023     /* Success */
1024     return 1;
1025 }
1026
1027
1028
1029 static void EmitCode (EffAddr* A)
1030 /* Output code for the data in A */
1031 {
1032     /* Check how many extension bytes are needed and output the instruction */
1033     switch (ExtBytes[A->AddrMode]) {
1034
1035         case 0:
1036             Emit0 (A->Opcode);
1037             break;
1038
1039         case 1:
1040             Emit1 (A->Opcode, A->Expr);
1041             break;
1042
1043         case 2:
1044             if (CPU == CPU_65816 && (A->AddrModeBit & (AM65_ABS | AM65_ABS_X | AM65_ABS_Y))) {
1045                 /* This is a 16 bit mode that uses an address. If in 65816,
1046                  * mode, force this address into 16 bit range to allow
1047                  * addressing inside a 64K segment.
1048                  */
1049                 Emit2 (A->Opcode, GenWordExpr (A->Expr));
1050             } else {
1051                 Emit2 (A->Opcode, A->Expr);
1052             }
1053             break;
1054
1055         case 3:
1056             /* Far argument */
1057             Emit3 (A->Opcode, A->Expr);
1058             break;
1059
1060         default:
1061             Internal ("Invalid operand byte count: %u", ExtBytes[A->AddrMode]);
1062
1063     }
1064 }
1065
1066
1067
1068 static long PutImmed8 (const InsDesc* Ins)
1069 /* Parse and emit an immediate 8 bit instruction. Return the value of the
1070  * operand if it's available and const.
1071  */
1072 {
1073     EffAddr A;
1074     long Val = -1;
1075
1076     /* Evaluate the addressing mode */
1077     if (EvalEA (Ins, &A) == 0) {
1078         /* An error occurred */
1079         return -1L;
1080     }
1081
1082     /* If we have an expression and it's const, get it's value */
1083     if (A.Expr) {
1084         (void) IsConstExpr (A.Expr, &Val);
1085     }
1086
1087     /* Check how many extension bytes are needed and output the instruction */
1088     switch (ExtBytes[A.AddrMode]) {
1089
1090         case 1:
1091             Emit1 (A.Opcode, A.Expr);
1092             break;
1093
1094         default:
1095             Internal ("Invalid operand byte count: %u", ExtBytes[A.AddrMode]);
1096     }
1097
1098     /* Return the expression value */
1099     return Val;
1100 }
1101
1102
1103
1104 static void PutPCRel8 (const InsDesc* Ins)
1105 /* Handle branches with a 8 bit distance */
1106 {
1107     EmitPCRel (Ins->BaseCode, GenBranchExpr (2), 1);
1108 }
1109
1110
1111
1112 static void PutPCRel16 (const InsDesc* Ins)
1113 /* Handle branches with an 16 bit distance and PER */
1114 {
1115     EmitPCRel (Ins->BaseCode, GenBranchExpr (3), 2);
1116 }
1117
1118
1119
1120 static void PutBlockMove (const InsDesc* Ins)
1121 /* Handle the blockmove instructions (65816) */
1122 {
1123     Emit0 (Ins->BaseCode);
1124     EmitByte (Expression ());
1125     ConsumeComma ();
1126     EmitByte (Expression ());
1127 }
1128
1129
1130
1131 static void PutBlockTransfer (const InsDesc* Ins)
1132 /* Handle the block transfer instructions (HuC6280) */
1133 {
1134     Emit0 (Ins->BaseCode);
1135     EmitWord (Expression ());
1136     ConsumeComma ();
1137     EmitWord (Expression ());
1138     ConsumeComma ();
1139     EmitWord (Expression ());
1140 }
1141
1142
1143
1144 static void PutBitBranch (const InsDesc* Ins)
1145 /* Handle 65C02 branch on bit condition */
1146 {
1147     Emit0 (Ins->BaseCode);
1148     EmitByte (Expression ());
1149     ConsumeComma ();
1150     EmitSigned (GenBranchExpr (1), 1);
1151 }
1152
1153
1154
1155 static void PutREP (const InsDesc* Ins)
1156 /* Emit a REP instruction, track register sizes */
1157 {
1158     /* Use the generic handler */
1159     long Val = PutImmed8 (Ins);
1160
1161     /* We track the status only for the 816 CPU and in smart mode */
1162     if (CPU == CPU_65816 && SmartMode) {
1163
1164         /* Check the range for Val. */
1165         if (Val < 0) {
1166             /* We had an error */
1167             Warning (1, "Cannot track processor status byte");
1168         } else {
1169             if (Val & 0x10) {
1170                 /* Index registers to 16 bit */
1171                 ExtBytes[AM65I_IMM_INDEX] = 2;
1172             }
1173             if (Val & 0x20) {
1174                 /* Accu to 16 bit */
1175                 ExtBytes[AM65I_IMM_ACCU] = 2;
1176             }
1177         }
1178     }
1179 }
1180
1181
1182
1183 static void PutSEP (const InsDesc* Ins)
1184 /* Emit a SEP instruction (65816), track register sizes */
1185 {
1186     /* Use the generic handler */
1187     long Val = PutImmed8 (Ins);
1188
1189     /* We track the status only for the 816 CPU and in smart mode */
1190     if (CPU == CPU_65816 && SmartMode) {
1191
1192         /* Check the range for Val. */
1193         if (Val < 0) {
1194             /* We had an error */
1195             Warning (1, "Cannot track processor status byte");
1196         } else {
1197             if (Val & 0x10) {
1198                 /* Index registers to 8 bit */
1199                 ExtBytes[AM65I_IMM_INDEX] = 1;
1200             }
1201             if (Val & 0x20) {
1202                 /* Accu to 8 bit */
1203                 ExtBytes[AM65I_IMM_ACCU] = 1;
1204             }
1205         }
1206     }
1207 }
1208
1209
1210
1211 static void PutTAMn (const InsDesc* Ins)
1212 /* Emit a TAMn instruction (HuC6280). Since this is a two byte instruction with
1213  * implicit addressing mode, the opcode byte in the table is actually the
1214  * second operand byte. The TAM instruction is the more generic form, it takes
1215  * an immediate argument.
1216  */
1217 {
1218     /* Emit the TAM opcode itself */
1219     Emit0 (0x53);
1220
1221     /* Emit the argument, which is the opcode from the table */
1222     Emit0 (Ins->BaseCode);
1223 }
1224
1225
1226
1227 static void PutTMA (const InsDesc* Ins)
1228 /* Emit a TMA instruction (HuC6280) with an immediate argument. Only one bit
1229  * in the argument byte may be set.
1230  */
1231 {
1232     /* Use the generic handler */
1233     long Val = PutImmed8 (Ins);
1234
1235     /* Check the range for Val. */
1236     if (Val < 0) {
1237         /* We had an error */
1238         Warning (1, "Cannot check argument of TMA instruction");
1239     } else {
1240         /* Make sure just one bit is set */
1241         if ((Val & (Val - 1)) != 0) {
1242             Error ("Argument to TAM must be a power of two");
1243         }
1244     }
1245 }
1246
1247
1248
1249 static void PutTMAn (const InsDesc* Ins)
1250 /* Emit a TMAn instruction (HuC6280). Since this is a two byte instruction with
1251  * implicit addressing mode, the opcode byte in the table is actually the
1252  * second operand byte. The TAM instruction is the more generic form, it takes
1253  * an immediate argument.
1254  */
1255 {
1256     /* Emit the TMA opcode itself */
1257     Emit0 (0x43);
1258
1259     /* Emit the argument, which is the opcode from the table */
1260     Emit0 (Ins->BaseCode);
1261 }
1262
1263
1264
1265 static void PutTST (const InsDesc* Ins)
1266 /* Emit a TST instruction (HuC6280). */
1267 {
1268     ExprNode* Arg1;
1269     EffAddr   A;
1270
1271     /* The first argument is always an immediate byte */
1272     if (CurTok.Tok != TOK_HASH) {
1273         ErrorSkip ("Invalid addressing mode");
1274         return;
1275     }
1276     NextTok ();
1277     Arg1 = Expression ();
1278
1279     /* Second argument follows */
1280     ConsumeComma ();
1281
1282     /* For the second argument, we use the standard function */
1283     if (EvalEA (Ins, &A)) {
1284
1285         /* No error, output code */
1286         Emit1 (A.Opcode, Arg1);
1287
1288         /* Check how many extension bytes are needed and output the instruction */
1289         switch (ExtBytes[A.AddrMode]) {
1290
1291             case 1:
1292                 EmitByte (A.Expr);
1293                 break;
1294
1295             case 2:
1296                 EmitWord (A.Expr);
1297                 break;
1298         }
1299     }
1300 }
1301
1302
1303
1304 static void PutJMP (const InsDesc* Ins)
1305 /* Handle the jump instruction for the 6502. Problem is that these chips have
1306  * a bug: If the address crosses a page, the upper byte gets not corrected and
1307  * the instruction will fail. The PutJmp function will add a linker assertion
1308  * to check for this case and is otherwise identical to PutAll.
1309  */
1310 {
1311     EffAddr A;
1312
1313     /* Evaluate the addressing mode used */
1314     if (EvalEA (Ins, &A)) {
1315
1316         /* Check for indirect addressing */
1317         if (A.AddrModeBit & AM65_ABS_IND) {
1318
1319             /* Compare the low byte of the expression to 0xFF to check for
1320              * a page cross. Be sure to use a copy of the expression otherwise
1321              * things will go weird later.
1322              */
1323             ExprNode* E = GenNE (GenByteExpr (CloneExpr (A.Expr)), 0xFF);
1324
1325             /* Generate the message */
1326             unsigned Msg = GetStringId ("\"jmp (abs)\" across page border");
1327
1328             /* Generate the assertion */
1329             AddAssertion (E, ASSERT_ACT_WARN, Msg);
1330         }
1331
1332         /* No error, output code */
1333         EmitCode (&A);
1334     }
1335 }
1336
1337
1338
1339 static void PutRTS (const InsDesc* Ins attribute ((unused)))
1340 /* Handle the RTS instruction for the 816. In smart mode emit a RTL opcode if
1341  * the enclosing scope is FAR.
1342  */
1343 {
1344     if (SmartMode && CurrentScope->AddrSize == ADDR_SIZE_FAR) {
1345         Emit0 (0x6B);       /* RTL */
1346     } else {
1347         Emit0 (0x60);       /* RTS */
1348     }
1349 }
1350
1351
1352
1353 static void PutAll (const InsDesc* Ins)
1354 /* Handle all other instructions */
1355 {
1356     EffAddr A;
1357
1358     /* Evaluate the addressing mode used */
1359     if (EvalEA (Ins, &A)) {
1360         /* No error, output code */
1361         EmitCode (&A);
1362     }
1363 }
1364
1365
1366
1367 /*****************************************************************************/
1368 /*                       Handler functions for SWEET16                       */
1369 /*****************************************************************************/
1370
1371
1372
1373 static void PutSweet16 (const InsDesc* Ins)
1374 /* Handle a generic sweet16 instruction */
1375 {
1376     EffAddr A;
1377
1378     /* Evaluate the addressing mode used */
1379     GetSweet16EA (&A);
1380
1381     /* From the possible addressing modes, remove the ones that are invalid
1382      * for this instruction or CPU.
1383      */
1384     A.AddrModeSet &= Ins->AddrMode;
1385
1386     /* Check if we have any adressing modes left */
1387     if (A.AddrModeSet == 0) {
1388         Error ("Illegal addressing mode");
1389         return;
1390     }
1391     A.AddrMode    = BitFind (A.AddrModeSet);
1392     A.AddrModeBit = (0x01UL << A.AddrMode);
1393
1394     /* Build the opcode */
1395     A.Opcode = Ins->BaseCode | Sweet16EATab[Ins->ExtCode][A.AddrMode] | A.Reg;
1396
1397     /* Check how many extension bytes are needed and output the instruction */
1398     switch (Sweet16ExtBytes[A.AddrMode]) {
1399
1400         case 0:
1401             Emit0 (A.Opcode);
1402             break;
1403
1404         case 1:
1405             Emit1 (A.Opcode, A.Expr);
1406             break;
1407
1408         case 2:
1409             Emit2 (A.Opcode, A.Expr);
1410             break;
1411
1412         default:
1413             Internal ("Invalid operand byte count: %u", Sweet16ExtBytes[A.AddrMode]);
1414
1415     }
1416 }
1417
1418
1419
1420 static void PutSweet16Branch (const InsDesc* Ins)
1421 /* Handle a sweet16 branch instruction */
1422 {
1423     EmitPCRel (Ins->BaseCode, GenBranchExpr (2), 1);
1424 }
1425
1426
1427
1428 /*****************************************************************************/
1429 /*                                   Code                                    */
1430 /*****************************************************************************/
1431
1432
1433
1434 static int CmpName (const void* Key, const void* Instr)
1435 /* Compare function for bsearch */
1436 {
1437     return strcmp ((const char*)Key, ((const InsDesc*) Instr)->Mnemonic);
1438 }
1439
1440
1441
1442 void SetCPU (cpu_t NewCPU)
1443 /* Set a new CPU */
1444 {
1445     /* Make sure the parameter is correct */
1446     CHECK (NewCPU < CPU_COUNT);
1447
1448     /* Check if we have support for the new CPU, if so, use it */
1449     if (NewCPU != CPU_UNKNOWN && InsTabs[NewCPU]) {
1450         CPU = NewCPU;
1451         InsTab = InsTabs[CPU];
1452     } else {
1453         Error ("CPU not supported");
1454     }
1455 }
1456
1457
1458
1459 cpu_t GetCPU (void)
1460 /* Return the current CPU */
1461 {
1462     return CPU;
1463 }
1464
1465
1466
1467 int FindInstruction (const StrBuf* Ident)
1468 /* Check if Ident is a valid mnemonic. If so, return the index in the
1469  * instruction table. If not, return -1.
1470  */
1471 {
1472     unsigned I;
1473     const InsDesc* ID;
1474     char Key[sizeof (ID->Mnemonic)];
1475
1476     /* Shortcut for the "none" CPU: If there are no instructions to search
1477      * for, bail out early.
1478      */
1479     if (InsTab->Count == 0) {
1480         /* Not found */
1481         return -1;
1482     }
1483
1484     /* Make a copy, and uppercase that copy */
1485     I = 0;
1486     while (I < SB_GetLen (Ident)) {
1487         /* If the identifier is longer than the longest mnemonic, it cannot
1488          * be one.
1489          */
1490         if (I >= sizeof (Key) - 1) {
1491             /* Not found, no need for further action */
1492             return -1;
1493         }
1494         Key[I] = toupper ((unsigned char)SB_AtUnchecked (Ident, I));
1495         ++I;
1496     }
1497     Key[I] = '\0';
1498
1499     /* Search for the key */
1500     ID = bsearch (Key, InsTab->Ins, InsTab->Count, sizeof (InsDesc), CmpName);
1501     if (ID == 0) {
1502         /* Not found */
1503         return -1;
1504     } else {
1505         /* Found, return the entry */
1506         return ID - InsTab->Ins;
1507     }
1508 }
1509
1510
1511
1512 void HandleInstruction (unsigned Index)
1513 /* Handle the mnemonic with the given index */
1514 {
1515     /* Safety check */
1516     PRECONDITION (Index < InsTab->Count);
1517
1518     /* Skip the mnemonic token */
1519     NextTok ();
1520
1521     /* Call the handler */
1522     InsTab->Ins[Index].Emit (&InsTab->Ins[Index]);
1523 }
1524
1525
1526