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