]> git.sur5r.net Git - cc65/blob - src/ca65/instr.c
33f364c1a8d5f9df7becf1414b390863a083092c
[cc65] / src / ca65 / instr.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  instr.c                                  */
4 /*                                                                           */
5 /*             Instruction encoding for the ca65 macroassembler              */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2003 Ullrich von Bassewitz                                       */
10 /*               Römerstraße 52                                              */
11 /*               D-70794 Filderstadt                                         */
12 /* EMail:        uz@cc65.org                                                 */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdlib.h>
37 #include <string.h>
38 #include <ctype.h>
39
40 /* common */
41 #include "addrsize.h"
42 #include "assertdefs.h"
43 #include "attrib.h"
44 #include "bitops.h"
45 #include "check.h"
46 #include "mmodel.h"
47
48 /* ca65 */
49 #include "asserts.h"
50 #include "ea.h"
51 #include "error.h"
52 #include "expr.h"
53 #include "global.h"
54 #include "instr.h"
55 #include "nexttok.h"
56 #include "objcode.h"
57 #include "spool.h"
58 #include "studyexpr.h"
59 #include "symtab.h"
60
61
62
63 /*****************************************************************************/
64 /*                                   Data                                    */
65 /*****************************************************************************/
66
67
68
69 /* Forwards for handler functions */
70 static void PutPCRel8 (const InsDesc* Ins);
71 static void PutPCRel16 (const InsDesc* Ins);
72 static void PutBlockMove (const InsDesc* Ins);
73 static void PutBitBranch (const InsDesc* Ins);
74 static void PutREP (const InsDesc* Ins);
75 static void PutSEP (const InsDesc* Ins);
76 static void PutJMP (const InsDesc* Ins);
77 static void PutRTS (const InsDesc* Ins);
78 static void PutAll (const InsDesc* Ins);
79
80
81
82 /* Instruction table for the 6502 */
83 #define INS_COUNT_6502          56
84 static const struct {
85     unsigned Count;
86     InsDesc  Ins[INS_COUNT_6502];
87 } InsTab6502 = {
88     INS_COUNT_6502,
89     {
90         { "ADC",  0x080A26C, 0x60, 0, PutAll },
91         { "AND",  0x080A26C, 0x20, 0, PutAll },
92         { "ASL",  0x000006e, 0x02, 1, PutAll },
93         { "BCC",  0x0020000, 0x90, 0, PutPCRel8 },
94         { "BCS",  0x0020000, 0xb0, 0, PutPCRel8 },
95         { "BEQ",  0x0020000, 0xf0, 0, PutPCRel8 },
96         { "BIT",  0x000000C, 0x00, 2, PutAll },
97         { "BMI",  0x0020000, 0x30, 0, PutPCRel8 },
98         { "BNE",  0x0020000, 0xd0, 0, PutPCRel8 },
99         { "BPL",  0x0020000, 0x10, 0, PutPCRel8 },
100         { "BRK",  0x0000001, 0x00, 0, PutAll },
101         { "BVC",  0x0020000, 0x50, 0, PutPCRel8 },
102         { "BVS",  0x0020000, 0x70, 0, PutPCRel8 },
103         { "CLC",  0x0000001, 0x18, 0, PutAll },
104         { "CLD",  0x0000001, 0xd8, 0, PutAll },
105         { "CLI",  0x0000001, 0x58, 0, PutAll },
106         { "CLV",  0x0000001, 0xb8, 0, PutAll },
107         { "CMP",  0x080A26C, 0xc0, 0, PutAll },
108         { "CPX",  0x080000C, 0xe0, 1, PutAll },
109         { "CPY",  0x080000C, 0xc0, 1, PutAll },
110         { "DEC",  0x000006C, 0x00, 3, PutAll },
111         { "DEX",  0x0000001, 0xca, 0, PutAll },
112         { "DEY",  0x0000001, 0x88, 0, PutAll },
113         { "EOR",  0x080A26C, 0x40, 0, PutAll },
114         { "INC",  0x000006c, 0x00, 4, PutAll },
115         { "INX",  0x0000001, 0xe8, 0, PutAll },
116         { "INY",  0x0000001, 0xc8, 0, PutAll },
117         { "JMP",  0x0000808, 0x4c, 6, PutJMP },
118         { "JSR",  0x0000008, 0x20, 7, PutAll },
119         { "LDA",  0x080A26C, 0xa0, 0, PutAll },
120         { "LDX",  0x080030C, 0xa2, 1, PutAll },
121         { "LDY",  0x080006C, 0xa0, 1, PutAll },
122         { "LSR",  0x000006F, 0x42, 1, PutAll },
123         { "NOP",  0x0000001, 0xea, 0, PutAll },
124         { "ORA",  0x080A26C, 0x00, 0, PutAll },
125         { "PHA",  0x0000001, 0x48, 0, PutAll },
126         { "PHP",  0x0000001, 0x08, 0, PutAll },
127         { "PLA",  0x0000001, 0x68, 0, PutAll },
128         { "PLP",  0x0000001, 0x28, 0, PutAll },
129         { "ROL",  0x000006F, 0x22, 1, PutAll },
130         { "ROR",  0x000006F, 0x62, 1, PutAll },
131         { "RTI",  0x0000001, 0x40, 0, PutAll },
132         { "RTS",  0x0000001, 0x60, 0, PutAll },
133         { "SBC",  0x080A26C, 0xe0, 0, PutAll },
134         { "SEC",  0x0000001, 0x38, 0, PutAll },
135         { "SED",  0x0000001, 0xf8, 0, PutAll },
136         { "SEI",  0x0000001, 0x78, 0, PutAll },
137         { "STA",  0x000A26C, 0x80, 0, PutAll },
138         { "STX",  0x000010c, 0x82, 1, PutAll },
139         { "STY",  0x000002c, 0x80, 1, PutAll },
140         { "TAX",  0x0000001, 0xaa, 0, PutAll },
141         { "TAY",  0x0000001, 0xa8, 0, PutAll },
142         { "TSX",  0x0000001, 0xba, 0, PutAll },
143         { "TXA",  0x0000001, 0x8a, 0, PutAll },
144         { "TXS",  0x0000001, 0x9a, 0, PutAll },
145         { "TYA",  0x0000001, 0x98, 0, PutAll }
146     }
147 };
148
149 /* Instruction table for the 6502 with illegal instructions */
150 #define INS_COUNT_6502X         70
151 static const struct {
152     unsigned Count;
153     InsDesc  Ins[INS_COUNT_6502X];
154 } InsTab6502X = {
155     INS_COUNT_6502X,
156     {
157         { "ADC",  0x080A26C, 0x60, 0, PutAll },
158         { "ALR",  0x0800000, 0x4B, 0, PutAll },         /* X */
159         { "ANC",  0x0800000, 0x0B, 0, PutAll },         /* X */
160         { "AND",  0x080A26C, 0x20, 0, PutAll },
161         { "ARR",  0x0800000, 0x6B, 0, PutAll },         /* X */
162         { "ASL",  0x000006e, 0x02, 1, PutAll },
163         { "AXS",  0x0800000, 0xCB, 0, PutAll },         /* X */
164         { "BCC",  0x0020000, 0x90, 0, PutPCRel8 },
165         { "BCS",  0x0020000, 0xb0, 0, PutPCRel8 },
166         { "BEQ",  0x0020000, 0xf0, 0, PutPCRel8 },
167         { "BIT",  0x000000C, 0x00, 2, PutAll },
168         { "BMI",  0x0020000, 0x30, 0, PutPCRel8 },
169         { "BNE",  0x0020000, 0xd0, 0, PutPCRel8 },
170         { "BPL",  0x0020000, 0x10, 0, PutPCRel8 },
171         { "BRK",  0x0000001, 0x00, 0, PutAll },
172         { "BVC",  0x0020000, 0x50, 0, PutPCRel8 },
173         { "BVS",  0x0020000, 0x70, 0, PutPCRel8 },
174         { "CLC",  0x0000001, 0x18, 0, PutAll },
175         { "CLD",  0x0000001, 0xd8, 0, PutAll },
176         { "CLI",  0x0000001, 0x58, 0, PutAll },
177         { "CLV",  0x0000001, 0xb8, 0, PutAll },
178         { "CMP",  0x080A26C, 0xc0, 0, PutAll },
179         { "CPX",  0x080000C, 0xe0, 1, PutAll },
180         { "CPY",  0x080000C, 0xc0, 1, PutAll },
181         { "DCP",  0x000A26C, 0xC3, 0, PutAll },         /* X */
182         { "DEC",  0x000006C, 0x00, 3, PutAll },
183         { "DEX",  0x0000001, 0xca, 0, PutAll },
184         { "DEY",  0x0000001, 0x88, 0, PutAll },
185         { "EOR",  0x080A26C, 0x40, 0, PutAll },
186         { "INC",  0x000006c, 0x00, 4, PutAll },
187         { "INX",  0x0000001, 0xe8, 0, PutAll },
188         { "INY",  0x0000001, 0xc8, 0, PutAll },
189         { "ISC",  0x000A26C, 0xE3, 0, PutAll },         /* X */
190         { "JAM",  0x0000001, 0x02, 0, PutAll },         /* X */
191         { "JMP",  0x0000808, 0x4c, 6, PutJMP },
192         { "JSR",  0x0000008, 0x20, 7, PutAll },
193         { "LAS",  0x0000200, 0xBB, 0, PutAll },         /* X */
194         { "LAX",  0x000A30C, 0xA3, 1, PutAll },         /* X */
195         { "LDA",  0x080A26C, 0xa0, 0, PutAll },
196         { "LDX",  0x080030C, 0xa2, 1, PutAll },
197         { "LDY",  0x080006C, 0xa0, 1, PutAll },
198         { "LSR",  0x000006F, 0x42, 1, PutAll },
199         { "NOP",  0x0000001, 0xea, 0, PutAll },
200         { "ORA",  0x080A26C, 0x00, 0, PutAll },
201         { "PHA",  0x0000001, 0x48, 0, PutAll },
202         { "PHP",  0x0000001, 0x08, 0, PutAll },
203         { "PLA",  0x0000001, 0x68, 0, PutAll },
204         { "PLP",  0x0000001, 0x28, 0, PutAll },
205         { "RLA",  0x000A26C, 0x23, 0, PutAll },         /* X */
206         { "ROL",  0x000006F, 0x22, 1, PutAll },
207         { "ROR",  0x000006F, 0x62, 1, PutAll },
208         { "RRA",  0x000A26C, 0x63, 0, PutAll },         /* X */
209         { "RTI",  0x0000001, 0x40, 0, PutAll },
210         { "RTS",  0x0000001, 0x60, 0, PutAll },
211         { "SAX",  0x000810C, 0x83, 1, PutAll },         /* X */
212         { "SBC",  0x080A26C, 0xe0, 0, PutAll },
213         { "SEC",  0x0000001, 0x38, 0, PutAll },
214         { "SED",  0x0000001, 0xf8, 0, PutAll },
215         { "SEI",  0x0000001, 0x78, 0, PutAll },
216         { "SLO",  0x000A26C, 0x03, 0, PutAll },         /* X */
217         { "SRE",  0x000A26C, 0x43, 0, PutAll },         /* X */
218         { "STA",  0x000A26C, 0x80, 0, PutAll },
219         { "STX",  0x000010c, 0x82, 1, PutAll },
220         { "STY",  0x000002c, 0x80, 1, PutAll },
221         { "TAX",  0x0000001, 0xaa, 0, PutAll },
222         { "TAY",  0x0000001, 0xa8, 0, PutAll },
223         { "TSX",  0x0000001, 0xba, 0, PutAll },
224         { "TXA",  0x0000001, 0x8a, 0, PutAll },
225         { "TXS",  0x0000001, 0x9a, 0, PutAll },
226         { "TYA",  0x0000001, 0x98, 0, PutAll }
227     }
228 };
229
230 /* Instruction table for the 65SC02 */
231 #define INS_COUNT_65SC02        66
232 static const struct {
233     unsigned Count;
234     InsDesc  Ins[INS_COUNT_65SC02];
235 } InsTab65SC02 = {
236     INS_COUNT_65SC02,
237     {
238         { "ADC",  0x080A66C, 0x60, 0, PutAll },
239         { "AND",  0x080A66C, 0x20, 0, PutAll },
240         { "ASL",  0x000006e, 0x02, 1, PutAll },
241         { "BCC",  0x0020000, 0x90, 0, PutPCRel8 },
242         { "BCS",  0x0020000, 0xb0, 0, PutPCRel8 },
243         { "BEQ",  0x0020000, 0xf0, 0, PutPCRel8 },
244         { "BIT",  0x0A0006C, 0x00, 2, PutAll },
245         { "BMI",  0x0020000, 0x30, 0, PutPCRel8 },
246         { "BNE",  0x0020000, 0xd0, 0, PutPCRel8 },
247         { "BPL",  0x0020000, 0x10, 0, PutPCRel8 },
248         { "BRA",  0x0020000, 0x80, 0, PutPCRel8 },
249         { "BRK",  0x0000001, 0x00, 0, PutAll },
250         { "BVC",  0x0020000, 0x50, 0, PutPCRel8 },
251         { "BVS",  0x0020000, 0x70, 0, PutPCRel8 },
252         { "CLC",  0x0000001, 0x18, 0, PutAll },
253         { "CLD",  0x0000001, 0xd8, 0, PutAll },
254         { "CLI",  0x0000001, 0x58, 0, PutAll },
255         { "CLV",  0x0000001, 0xb8, 0, PutAll },
256         { "CMP",  0x080A66C, 0xc0, 0, PutAll },
257         { "CPX",  0x080000C, 0xe0, 1, PutAll },
258         { "CPY",  0x080000C, 0xc0, 1, PutAll },
259         { "DEA",  0x0000001, 0x00, 3, PutAll },   /* == DEC */
260         { "DEC",  0x000006F, 0x00, 3, PutAll },
261         { "DEX",  0x0000001, 0xca, 0, PutAll },
262         { "DEY",  0x0000001, 0x88, 0, PutAll },
263         { "EOR",  0x080A66C, 0x40, 0, PutAll },
264         { "INA",  0x0000001, 0x00, 4, PutAll },   /* == INC */
265         { "INC",  0x000006f, 0x00, 4, PutAll },
266         { "INX",  0x0000001, 0xe8, 0, PutAll },
267         { "INY",  0x0000001, 0xc8, 0, PutAll },
268         { "JMP",  0x0010808, 0x4c, 6, PutAll },
269         { "JSR",  0x0000008, 0x20, 7, PutAll },
270         { "LDA",  0x080A66C, 0xa0, 0, PutAll },
271         { "LDX",  0x080030C, 0xa2, 1, PutAll },
272         { "LDY",  0x080006C, 0xa0, 1, PutAll },
273         { "LSR",  0x000006F, 0x42, 1, PutAll },
274         { "NOP",  0x0000001, 0xea, 0, PutAll },
275         { "ORA",  0x080A66C, 0x00, 0, PutAll },
276         { "PHA",  0x0000001, 0x48, 0, PutAll },
277         { "PHP",  0x0000001, 0x08, 0, PutAll },
278         { "PHX",  0x0000001, 0xda, 0, PutAll },
279         { "PHY",  0x0000001, 0x5a, 0, PutAll },
280         { "PLA",  0x0000001, 0x68, 0, PutAll },
281         { "PLP",  0x0000001, 0x28, 0, PutAll },
282         { "PLX",  0x0000001, 0xfa, 0, PutAll },
283         { "PLY",  0x0000001, 0x7a, 0, PutAll },
284         { "ROL",  0x000006F, 0x22, 1, PutAll },
285         { "ROR",  0x000006F, 0x62, 1, PutAll },
286         { "RTI",  0x0000001, 0x40, 0, PutAll },
287         { "RTS",  0x0000001, 0x60, 0, PutAll },
288         { "SBC",  0x080A66C, 0xe0, 0, PutAll },
289         { "SEC",  0x0000001, 0x38, 0, PutAll },
290         { "SED",  0x0000001, 0xf8, 0, PutAll },
291         { "SEI",  0x0000001, 0x78, 0, PutAll },
292         { "STA",  0x000A66C, 0x80, 0, PutAll },
293         { "STX",  0x000010c, 0x82, 1, PutAll },
294         { "STY",  0x000002c, 0x80, 1, PutAll },
295         { "STZ",  0x000006c, 0x04, 5, PutAll },
296         { "TAX",  0x0000001, 0xaa, 0, PutAll },
297         { "TAY",  0x0000001, 0xa8, 0, PutAll },
298         { "TRB",  0x000000c, 0x10, 1, PutAll },
299         { "TSB",  0x000000c, 0x00, 1, PutAll },
300         { "TSX",  0x0000001, 0xba, 0, PutAll },
301         { "TXA",  0x0000001, 0x8a, 0, PutAll },
302         { "TXS",  0x0000001, 0x9a, 0, PutAll },
303         { "TYA",  0x0000001, 0x98, 0, PutAll }
304     }
305 };
306
307 /* Instruction table for the 65C02 */
308 #define INS_COUNT_65C02         98
309 static const struct {
310     unsigned Count;
311     InsDesc  Ins[INS_COUNT_65C02];
312 } InsTab65C02 = {
313     INS_COUNT_65C02,
314     {
315         { "ADC",  0x080A66C, 0x60, 0, PutAll },
316         { "AND",  0x080A66C, 0x20, 0, PutAll },
317         { "ASL",  0x000006e, 0x02, 1, PutAll },
318         { "BBR0", 0x0000000, 0x0F, 0, PutBitBranch },
319         { "BBR1", 0x0000000, 0x1F, 0, PutBitBranch },
320         { "BBR2", 0x0000000, 0x2F, 0, PutBitBranch },
321         { "BBR3", 0x0000000, 0x3F, 0, PutBitBranch },
322         { "BBR4", 0x0000000, 0x4F, 0, PutBitBranch },
323         { "BBR5", 0x0000000, 0x5F, 0, PutBitBranch },
324         { "BBR6", 0x0000000, 0x6F, 0, PutBitBranch },
325         { "BBR7", 0x0000000, 0x7F, 0, PutBitBranch },
326         { "BBS0", 0x0000000, 0x8F, 0, PutBitBranch },
327         { "BBS1", 0x0000000, 0x9F, 0, PutBitBranch },
328         { "BBS2", 0x0000000, 0xAF, 0, PutBitBranch },
329         { "BBS3", 0x0000000, 0xBF, 0, PutBitBranch },
330         { "BBS4", 0x0000000, 0xCF, 0, PutBitBranch },
331         { "BBS5", 0x0000000, 0xDF, 0, PutBitBranch },
332         { "BBS6", 0x0000000, 0xEF, 0, PutBitBranch },
333         { "BBS7", 0x0000000, 0xFF, 0, PutBitBranch },
334         { "BCC",  0x0020000, 0x90, 0, PutPCRel8 },
335         { "BCS",  0x0020000, 0xb0, 0, PutPCRel8 },
336         { "BEQ",  0x0020000, 0xf0, 0, PutPCRel8 },
337         { "BIT",  0x0A0006C, 0x00, 2, PutAll },
338         { "BMI",  0x0020000, 0x30, 0, PutPCRel8 },
339         { "BNE",  0x0020000, 0xd0, 0, PutPCRel8 },
340         { "BPL",  0x0020000, 0x10, 0, PutPCRel8 },
341         { "BRA",  0x0020000, 0x80, 0, PutPCRel8 },
342         { "BRK",  0x0000001, 0x00, 0, PutAll },
343         { "BVC",  0x0020000, 0x50, 0, PutPCRel8 },
344         { "BVS",  0x0020000, 0x70, 0, PutPCRel8 },
345         { "CLC",  0x0000001, 0x18, 0, PutAll },
346         { "CLD",  0x0000001, 0xd8, 0, PutAll },
347         { "CLI",  0x0000001, 0x58, 0, PutAll },
348         { "CLV",  0x0000001, 0xb8, 0, PutAll },
349         { "CMP",  0x080A66C, 0xc0, 0, PutAll },
350         { "CPX",  0x080000C, 0xe0, 1, PutAll },
351         { "CPY",  0x080000C, 0xc0, 1, PutAll },
352         { "DEA",  0x0000001, 0x00, 3, PutAll },   /* == DEC */
353         { "DEC",  0x000006F, 0x00, 3, PutAll },
354         { "DEX",  0x0000001, 0xca, 0, PutAll },
355         { "DEY",  0x0000001, 0x88, 0, PutAll },
356         { "EOR",  0x080A66C, 0x40, 0, PutAll },
357         { "INA",  0x0000001, 0x00, 4, PutAll },   /* == INC */
358         { "INC",  0x000006f, 0x00, 4, PutAll },
359         { "INX",  0x0000001, 0xe8, 0, PutAll },
360         { "INY",  0x0000001, 0xc8, 0, PutAll },
361         { "JMP",  0x0010808, 0x4c, 6, PutAll },
362         { "JSR",  0x0000008, 0x20, 7, PutAll },
363         { "LDA",  0x080A66C, 0xa0, 0, PutAll },
364         { "LDX",  0x080030C, 0xa2, 1, PutAll },
365         { "LDY",  0x080006C, 0xa0, 1, PutAll },
366         { "LSR",  0x000006F, 0x42, 1, PutAll },
367         { "NOP",  0x0000001, 0xea, 0, PutAll },
368         { "ORA",  0x080A66C, 0x00, 0, PutAll },
369         { "PHA",  0x0000001, 0x48, 0, PutAll },
370         { "PHP",  0x0000001, 0x08, 0, PutAll },
371         { "PHX",  0x0000001, 0xda, 0, PutAll },
372         { "PHY",  0x0000001, 0x5a, 0, PutAll },
373         { "PLA",  0x0000001, 0x68, 0, PutAll },
374         { "PLP",  0x0000001, 0x28, 0, PutAll },
375         { "PLX",  0x0000001, 0xfa, 0, PutAll },
376         { "PLY",  0x0000001, 0x7a, 0, PutAll },
377         { "RMB0", 0x0000004, 0x07, 1, PutAll },
378         { "RMB1", 0x0000004, 0x17, 1, PutAll },
379         { "RMB2", 0x0000004, 0x27, 1, PutAll },
380         { "RMB3", 0x0000004, 0x37, 1, PutAll },
381         { "RMB4", 0x0000004, 0x47, 1, PutAll },
382         { "RMB5", 0x0000004, 0x57, 1, PutAll },
383         { "RMB6", 0x0000004, 0x67, 1, PutAll },
384         { "RMB7", 0x0000004, 0x77, 1, PutAll },
385         { "ROL",  0x000006F, 0x22, 1, PutAll },
386         { "ROR",  0x000006F, 0x62, 1, PutAll },
387         { "RTI",  0x0000001, 0x40, 0, PutAll },
388         { "RTS",  0x0000001, 0x60, 0, PutAll },
389         { "SBC",  0x080A66C, 0xe0, 0, PutAll },
390         { "SEC",  0x0000001, 0x38, 0, PutAll },
391         { "SED",  0x0000001, 0xf8, 0, PutAll },
392         { "SEI",  0x0000001, 0x78, 0, PutAll },
393         { "SMB0", 0x0000004, 0x87, 1, PutAll },
394         { "SMB1", 0x0000004, 0x97, 1, PutAll },
395         { "SMB2", 0x0000004, 0xA7, 1, PutAll },
396         { "SMB3", 0x0000004, 0xB7, 1, PutAll },
397         { "SMB4", 0x0000004, 0xC7, 1, PutAll },
398         { "SMB5", 0x0000004, 0xD7, 1, PutAll },
399         { "SMB6", 0x0000004, 0xE7, 1, PutAll },
400         { "SMB7", 0x0000004, 0xF7, 1, PutAll },
401         { "STA",  0x000A66C, 0x80, 0, PutAll },
402         { "STX",  0x000010c, 0x82, 1, PutAll },
403         { "STY",  0x000002c, 0x80, 1, PutAll },
404         { "STZ",  0x000006c, 0x04, 5, PutAll },
405         { "TAX",  0x0000001, 0xaa, 0, PutAll },
406         { "TAY",  0x0000001, 0xa8, 0, PutAll },
407         { "TRB",  0x000000c, 0x10, 1, PutAll },
408         { "TSB",  0x000000c, 0x00, 1, PutAll },
409         { "TSX",  0x0000001, 0xba, 0, PutAll },
410         { "TXA",  0x0000001, 0x8a, 0, PutAll },
411         { "TXS",  0x0000001, 0x9a, 0, PutAll },
412         { "TYA",  0x0000001, 0x98, 0, PutAll }
413     }
414 };
415
416 /* Instruction table for the 65816 */
417 #define INS_COUNT_65816 101
418 static const struct {
419     unsigned Count;
420     InsDesc  Ins[INS_COUNT_65816];
421 } InsTab65816 = {
422     INS_COUNT_65816,             
423     {
424         { "ADC",  0x0b8f6fc, 0x60, 0, PutAll },
425         { "AND",  0x0b8f6fc, 0x20, 0, PutAll },
426         { "ASL",  0x000006e, 0x02, 1, PutAll },
427         { "BCC",  0x0020000, 0x90, 0, PutPCRel8 },
428         { "BCS",  0x0020000, 0xb0, 0, PutPCRel8 },
429         { "BEQ",  0x0020000, 0xf0, 0, PutPCRel8 },
430         { "BGE",  0x0020000, 0xb0, 0, PutPCRel8 },   /* == BCS */
431         { "BIT",  0x0a0006c, 0x00, 2, PutAll },
432         { "BLT",  0x0020000, 0x90, 0, PutPCRel8 },   /* == BCC */
433         { "BMI",  0x0020000, 0x30, 0, PutPCRel8 },
434         { "BNE",  0x0020000, 0xd0, 0, PutPCRel8 },
435         { "BPL",  0x0020000, 0x10, 0, PutPCRel8 },
436         { "BRA",  0x0020000, 0x80, 0, PutPCRel8 },
437         { "BRK",  0x0000001, 0x00, 0, PutAll },
438         { "BRL",  0x0040000, 0x82, 0, PutPCRel16 },
439         { "BVC",  0x0020000, 0x50, 0, PutPCRel8 },
440         { "BVS",  0x0020000, 0x70, 0, PutPCRel8 },
441         { "CLC",  0x0000001, 0x18, 0, PutAll },
442         { "CLD",  0x0000001, 0xd8, 0, PutAll },
443         { "CLI",  0x0000001, 0x58, 0, PutAll },
444         { "CLV",  0x0000001, 0xb8, 0, PutAll },
445         { "CMP",  0x0b8f6fc, 0xc0, 0, PutAll },
446         { "COP",  0x0000004, 0x02, 6, PutAll },
447         { "CPA",  0x0b8f6fc, 0xc0, 0, PutAll },   /* == CMP */
448         { "CPX",  0x0c0000c, 0xe0, 1, PutAll },
449         { "CPY",  0x0c0000c, 0xc0, 1, PutAll },
450         { "DEA",  0x0000001, 0x00, 3, PutAll },   /* == DEC */
451         { "DEC",  0x000006F, 0x00, 3, PutAll },
452         { "DEX",  0x0000001, 0xca, 0, PutAll },
453         { "DEY",  0x0000001, 0x88, 0, PutAll },
454         { "EOR",  0x0b8f6fc, 0x40, 0, PutAll },
455         { "INA",  0x0000001, 0x00, 4, PutAll },   /* == INC */
456         { "INC",  0x000006F, 0x00, 4, PutAll },
457         { "INX",  0x0000001, 0xe8, 0, PutAll },
458         { "INY",  0x0000001, 0xc8, 0, PutAll },
459         { "JML",  0x0000810, 0x5c, 1, PutAll },
460         { "JMP",  0x0010818, 0x4c, 6, PutAll },
461         { "JSL",  0x0000010, 0x20, 7, PutAll },
462         { "JSR",  0x0010018, 0x20, 7, PutAll },
463         { "LDA",  0x0b8f6fc, 0xa0, 0, PutAll },
464         { "LDX",  0x0c0030c, 0xa2, 1, PutAll },
465         { "LDY",  0x0c0006c, 0xa0, 1, PutAll },
466         { "LSR",  0x000006F, 0x42, 1, PutAll },
467         { "MVN",  0x1000000, 0x54, 0, PutBlockMove },
468         { "MVP",  0x1000000, 0x44, 0, PutBlockMove },
469         { "NOP",  0x0000001, 0xea, 0, PutAll },
470         { "ORA",  0x0b8f6fc, 0x00, 0, PutAll },
471         { "PEA",  0x0000008, 0xf4, 6, PutAll },
472         { "PEI",  0x0000400, 0xd4, 1, PutAll },
473         { "PER",  0x0040000, 0x62, 0, PutPCRel16 },
474         { "PHA",  0x0000001, 0x48, 0, PutAll },
475         { "PHB",  0x0000001, 0x8b, 0, PutAll },
476         { "PHD",  0x0000001, 0x0b, 0, PutAll },
477         { "PHK",  0x0000001, 0x4b, 0, PutAll },
478         { "PHP",  0x0000001, 0x08, 0, PutAll },
479         { "PHX",  0x0000001, 0xda, 0, PutAll },
480         { "PHY",  0x0000001, 0x5a, 0, PutAll },
481         { "PLA",  0x0000001, 0x68, 0, PutAll },
482         { "PLB",  0x0000001, 0xab, 0, PutAll },
483         { "PLD",  0x0000001, 0x2b, 0, PutAll },
484         { "PLP",  0x0000001, 0x28, 0, PutAll },
485         { "PLX",  0x0000001, 0xfa, 0, PutAll },
486         { "PLY",  0x0000001, 0x7a, 0, PutAll },
487         { "REP",  0x0800000, 0xc2, 1, PutREP },
488         { "ROL",  0x000006F, 0x22, 1, PutAll },
489         { "ROR",  0x000006F, 0x62, 1, PutAll },
490         { "RTI",  0x0000001, 0x40, 0, PutAll },
491         { "RTL",  0x0000001, 0x6b, 0, PutAll },
492         { "RTS",  0x0000001, 0x60, 0, PutRTS },
493         { "SBC",  0x0b8f6fc, 0xe0, 0, PutAll },
494         { "SEC",  0x0000001, 0x38, 0, PutAll },
495         { "SED",  0x0000001, 0xf8, 0, PutAll },
496         { "SEI",  0x0000001, 0x78, 0, PutAll },
497         { "SEP",  0x0800000, 0xe2, 1, PutSEP },
498         { "STA",  0x018f6fc, 0x80, 0, PutAll },
499         { "STP",  0x0000001, 0xdb, 0, PutAll },
500         { "STX",  0x000010c, 0x82, 1, PutAll },
501         { "STY",  0x000002c, 0x80, 1, PutAll },
502         { "STZ",  0x000006c, 0x04, 5, PutAll },
503         { "SWA",  0x0000001, 0xeb, 0, PutAll },   /* == XBA */
504         { "TAD",  0x0000001, 0x5b, 0, PutAll },   /* == TCD */
505         { "TAS",  0x0000001, 0x1b, 0, PutAll },   /* == TCS */
506         { "TAX",  0x0000001, 0xaa, 0, PutAll },
507         { "TAY",  0x0000001, 0xa8, 0, PutAll },
508         { "TCD",  0x0000001, 0x5b, 0, PutAll },
509         { "TCS",  0x0000001, 0x1b, 0, PutAll },
510         { "TDA",  0x0000001, 0x7b, 0, PutAll },   /* == TDC */
511         { "TDC",  0x0000001, 0x7b, 0, PutAll },
512         { "TRB",  0x000000c, 0x10, 1, PutAll },
513         { "TSA",  0x0000001, 0x3b, 0, PutAll },   /* == TSC */
514         { "TSB",  0x000000c, 0x00, 1, PutAll },
515         { "TSC",  0x0000001, 0x3b, 0, PutAll },
516         { "TSX",  0x0000001, 0xba, 0, PutAll },
517         { "TXA",  0x0000001, 0x8a, 0, PutAll },
518         { "TXS",  0x0000001, 0x9a, 0, PutAll },
519         { "TXY",  0x0000001, 0x9b, 0, PutAll },
520         { "TYA",  0x0000001, 0x98, 0, PutAll },
521         { "TYX",  0x0000001, 0xbb, 0, PutAll },
522         { "WAI",  0x0000001, 0xcb, 0, PutAll },
523         { "XBA",  0x0000001, 0xeb, 0, PutAll },
524         { "XCE",  0x0000001, 0xfb, 0, PutAll }
525     }
526 };
527
528 #ifdef SUNPLUS
529 /* Table for the SUNPLUS CPU */
530 #include "sunplus.inc"
531 #endif
532
533
534
535 /* An array with instruction tables */
536 static const InsTable* InsTabs[CPU_COUNT] = {
537     (const InsTable*) &InsTab6502,
538     (const InsTable*) &InsTab6502X,
539     (const InsTable*) &InsTab65SC02,
540     (const InsTable*) &InsTab65C02,
541     (const InsTable*) &InsTab65816,
542 #ifdef SUNPLUS
543     (const InsTable*) &InsTabSunPlus,
544 #endif
545 };
546 const InsTable* InsTab = (const InsTable*) &InsTab6502;
547
548 /* Table to build the effective opcode from a base opcode and an addressing
549  * mode.
550  */
551 unsigned char EATab [9][AMI_COUNT] = {
552     {   /* Table 0 */
553         0x00, 0x00, 0x05, 0x0D, 0x0F, 0x15, 0x1D, 0x1F,
554         0x00, 0x19, 0x12, 0x00, 0x07, 0x11, 0x17, 0x01,
555         0x00, 0x00, 0x00, 0x03, 0x13, 0x09, 0x00, 0x09,
556         0x00
557     },
558     {   /* Table 1 */
559         0x08, 0x08, 0x04, 0x0C, 0x00, 0x14, 0x1C, 0x00,
560         0x14, 0x1C, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00,
561         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
562         0x00
563     },
564     {   /* Table 2 */
565         0x00, 0x00, 0x24, 0x2C, 0x0F, 0x34, 0x3C, 0x00,
566         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
567         0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00,
568         0x00
569     },
570     {   /* Table 3 */
571         0x3A, 0x3A, 0xC6, 0xCE, 0x00, 0xD6, 0xDE, 0x00,
572         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
573         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
574         0x00
575     },
576     {   /* Table 4 */
577         0x1A, 0x1A, 0xE6, 0xEE, 0x00, 0xF6, 0xFE, 0x00,
578         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
579         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
580         0x00
581     },
582     {   /* Table 5 */
583         0x00, 0x00, 0x60, 0x98, 0x00, 0x70, 0x9E, 0x00,
584         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
585         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
586         0x00
587     },
588     {   /* Table 6 */
589         0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
590         0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
591         0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
592         0x00
593     },
594     {   /* Table 7 */
595         0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
596         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
597         0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
598         0x00
599     },
600     {   /* Table 8 */
601         0x00, 0x40, 0x01, 0x41, 0x00, 0x09, 0x49, 0x00,
602         0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00,
603         0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
604         0x00
605     },
606 };
607
608 /* Table that encodes the additional bytes for each instruction */
609 unsigned char ExtBytes [AMI_COUNT] = {
610     0,          /* Implicit */
611     0,          /* Accu */
612     1,          /* Direct */
613     2,          /* Absolute */
614     3,          /* Absolute long */
615     1,          /* Direct,X */
616     2,          /* Absolute,X */
617     3,          /* Absolute long,X */
618     1,          /* Direct,Y */
619     2,          /* Absolute,Y */
620     1,          /* (Direct) */
621     2,          /* (Absolute) */
622     1,          /* [Direct] */
623     1,          /* (Direct),Y */
624     1,          /* [Direct],Y */
625     1,          /* (Direct,X) */
626     2,          /* (Absolute,X) */
627     1,          /* Relative short */
628     2,          /* Relative long */
629     1,          /* r,s */
630     1,          /* (r,s),y */
631     1,          /* Immidiate accu */
632     1,          /* Immidiate index */
633     1,          /* Immidiate byte */
634     2           /* Blockmove */
635 };
636
637
638
639 /*****************************************************************************/
640 /*                             Handler functions                             */
641 /*****************************************************************************/
642
643
644
645 static int EvalEA (const InsDesc* Ins, EffAddr* A)
646 /* Evaluate the effective address. All fields in A will be valid after calling
647  * this function. The function returns true on success and false on errors.
648  */
649 {
650     /* Get the set of possible addressing modes */
651     GetEA (A);
652
653     /* From the possible addressing modes, remove the ones that are invalid
654      * for this instruction or CPU.
655      */
656     A->AddrModeSet &= Ins->AddrMode;
657
658     /* If we have an expression, check it and remove any addressing modes that
659      * are too small for the expression size. Since we have to study the
660      * expression anyway, do also replace it by a simpler one if possible.
661      */
662     if (A->Expr) {
663         ExprDesc ED;
664         ED_Init (&ED);
665
666         /* Study the expression */
667         StudyExpr (A->Expr, &ED);
668
669         /* Simplify it if possible */
670         A->Expr = SimplifyExpr (A->Expr, &ED);
671
672         /* If we don't know how big the expression is, assume the default
673          * address size for data.
674          */
675         if (ED.AddrSize == ADDR_SIZE_DEFAULT) {
676             ED.AddrSize = DataAddrSize;
677         }
678
679         /* Check the size */
680         switch (ED.AddrSize) {
681
682             case ADDR_SIZE_ABS:
683                 A->AddrModeSet &= ~AM_SET_ZP;
684                 break;
685
686             case ADDR_SIZE_FAR:
687                 A->AddrModeSet &= ~(AM_SET_ZP | AM_SET_ABS);
688                 break;
689         }
690
691         /* Free any resource associated with the expression desc */
692         ED_Done (&ED);
693     }
694
695     /* Check if we have any adressing modes left */
696     if (A->AddrModeSet == 0) {
697         Error ("Illegal addressing mode");
698         return 0;
699     }
700     A->AddrMode    = BitFind (A->AddrModeSet);
701     A->AddrModeBit = (0x01UL << A->AddrMode);
702
703     /* If the instruction has a one byte operand and immediate addressing is
704      * allowed but not used, check for an operand expression in the form
705      * <label or >label, where label is a far or absolute label. If found,
706      * emit a warning. This warning protects against a typo, where the '#'
707      * for the immediate operand is omitted.
708      */
709     if (A->Expr && (Ins->AddrMode & AM_IMM)                &&
710         (A->AddrModeSet & (AM_DIR | AM_ABS | AM_ABS_LONG)) &&
711         ExtBytes[A->AddrMode] == 1) {
712
713         /* Found, check the expression */
714         ExprNode* Left = A->Expr->Left;
715         if ((A->Expr->Op == EXPR_BYTE0 || A->Expr->Op == EXPR_BYTE1) &&
716             Left->Op == EXPR_SYMBOL                                  &&
717             GetSymAddrSize (Left->V.Sym) != ADDR_SIZE_ZP) {
718
719             /* Output a warning */
720             Warning (1, "Suspicious address expression");
721         }
722     }
723
724     /* Build the opcode */
725     A->Opcode = Ins->BaseCode | EATab[Ins->ExtCode][A->AddrMode];
726
727     /* Success */
728     return 1;
729 }
730
731
732
733 static void EmitCode (EffAddr* A)
734 /* Output code for the data in A */
735 {
736     /* Check how many extension bytes are needed and output the instruction */
737     switch (ExtBytes[A->AddrMode]) {
738
739         case 0:
740             Emit0 (A->Opcode);
741             break;
742
743         case 1:
744             Emit1 (A->Opcode, A->Expr);
745             break;
746
747         case 2:
748             if (CPU == CPU_65816 && (A->AddrModeBit & (AM_ABS | AM_ABS_X | AM_ABS_Y))) {
749                 /* This is a 16 bit mode that uses an address. If in 65816,
750                  * mode, force this address into 16 bit range to allow
751                  * addressing inside a 64K segment.
752                  */
753                 Emit2 (A->Opcode, GenWordExpr (A->Expr));
754             } else {
755                 Emit2 (A->Opcode, A->Expr);
756             }
757             break;
758
759         case 3:
760             /* Far argument */
761             Emit3 (A->Opcode, A->Expr);
762             break;
763
764         default:
765             Internal ("Invalid operand byte count: %u", ExtBytes[A->AddrMode]);
766
767     }
768 }
769
770
771
772 static long PutImmed8 (const InsDesc* Ins)
773 /* Parse and emit an immediate 8 bit instruction. Return the value of the
774  * operand if it's available and const.
775  */
776 {
777     EffAddr A;
778     long Val = -1;
779
780     /* Evaluate the addressing mode */
781     if (EvalEA (Ins, &A) == 0) {
782         /* An error occurred */
783         return -1L;
784     }
785
786     /* If we have an expression and it's const, get it's value */
787     if (A.Expr) {
788         (void) IsConstExpr (A.Expr, &Val);
789     }
790
791     /* Check how many extension bytes are needed and output the instruction */
792     switch (ExtBytes[A.AddrMode]) {
793
794         case 1:
795             Emit1 (A.Opcode, A.Expr);
796             break;
797
798         default:
799             Internal ("Invalid operand byte count: %u", ExtBytes[A.AddrMode]);
800     }
801
802     /* Return the expression value */
803     return Val;
804 }
805
806
807
808 static void PutPCRel8 (const InsDesc* Ins)
809 /* Handle branches with a 8 bit distance */
810 {
811     EmitPCRel (Ins->BaseCode, GenBranchExpr (2), 1);
812 }
813
814
815
816 static void PutPCRel16 (const InsDesc* Ins)
817 /* Handle branches with an 16 bit distance and PER */
818 {
819     EmitPCRel (Ins->BaseCode, GenBranchExpr (3), 2);
820 }
821
822
823
824 static void PutBlockMove (const InsDesc* Ins)
825 /* Handle the blockmove instructions */
826 {
827     Emit0 (Ins->BaseCode);
828     EmitByte (Expression ());
829     ConsumeComma ();
830     EmitByte (Expression ());
831 }
832
833
834
835 static void PutBitBranch (const InsDesc* Ins)
836 /* Handle 65C02 branch on bit condition */
837 {
838     Emit0 (Ins->BaseCode);
839     EmitByte (Expression ());
840     ConsumeComma ();
841     EmitSigned (GenBranchExpr (1), 1);
842 }
843
844
845
846 static void PutREP (const InsDesc* Ins)
847 /* Emit a REP instruction, track register sizes */
848 {
849     /* Use the generic handler */
850     long Val = PutImmed8 (Ins);
851
852     /* We track the status only for the 816 CPU and in smart mode */
853     if (CPU == CPU_65816 && SmartMode) {
854
855         /* Check the range for Val. */
856         if (Val < 0) {
857             /* We had an error */
858             Warning (1, "Cannot track processor status byte");
859         } else {
860             if (Val & 0x10) {
861                 /* Index registers to 16 bit */
862                 ExtBytes[AMI_IMM_INDEX] = 2;
863             }
864             if (Val & 0x20) {
865                 /* Accu to 16 bit */
866                 ExtBytes[AMI_IMM_ACCU] = 2;
867             }
868         }
869     }
870 }
871
872
873
874 static void PutSEP (const InsDesc* Ins)
875 /* Emit a SEP instruction, track register sizes */
876 {
877     /* Use the generic handler */
878     long Val = PutImmed8 (Ins);
879
880     /* We track the status only for the 816 CPU and in smart mode */
881     if (CPU == CPU_65816 && SmartMode) {
882
883         /* Check the range for Val. */
884         if (Val < 0) {
885             /* We had an error */
886             Warning (1, "Cannot track processor status byte");
887         } else {
888             if (Val & 0x10) {
889                 /* Index registers to 8 bit */
890                 ExtBytes [AMI_IMM_INDEX] = 1;
891             }
892             if (Val & 0x20) {
893                 /* Accu to 8 bit */
894                 ExtBytes [AMI_IMM_ACCU] = 1;
895             }
896         }
897     }
898 }
899
900
901
902 static void PutJMP (const InsDesc* Ins)
903 /* Handle the jump instruction for the 6502. Problem is that these chips have
904  * a bug: If the address crosses a page, the upper byte gets not corrected and
905  * the instruction will fail. The PutJmp function will add a linker assertion
906  * to check for this case and is otherwise identical to PutAll.
907  */
908 {
909     EffAddr A;
910
911     /* Evaluate the addressing mode used */
912     if (EvalEA (Ins, &A)) {
913
914         /* Check for indirect addressing */
915         if (A.AddrModeBit & AM_ABS_IND) {
916
917             /* Compare the low byte of the expression to 0xFF to check for
918              * a page cross. Be sure to use a copy of the expression otherwise
919              * things will go weird later.
920              */
921             ExprNode* E = GenNE (GenByteExpr (CloneExpr (A.Expr)), 0xFF);
922
923             /* Generate the message */
924             unsigned Msg = GetStringId ("\"jmp (abs)\" across page border");
925
926             /* Generate the assertion */
927             AddAssertion (E, ASSERT_ACT_WARN, Msg);
928         }
929
930         /* No error, output code */
931         EmitCode (&A);
932     }
933 }
934
935
936
937 static void PutRTS (const InsDesc* Ins attribute ((unused)))
938 /* Handle the RTS instruction for the 816. In smart mode emit a RTL opcode if
939  * the enclosing scope is FAR.
940  */
941 {
942     if (SmartMode && CurrentScope->AddrSize == ADDR_SIZE_FAR) {
943         Emit0 (0x6B);       /* RTL */
944     } else {
945         Emit0 (0x60);       /* RTS */
946     }
947 }
948
949
950
951 static void PutAll (const InsDesc* Ins)
952 /* Handle all other instructions */
953 {
954     EffAddr A;
955
956     /* Evaluate the addressing mode used */
957     if (EvalEA (Ins, &A)) {
958         /* No error, output code */
959         EmitCode (&A);
960     }
961 }
962
963
964
965 /*****************************************************************************/
966 /*                                   Code                                    */
967 /*****************************************************************************/
968
969
970
971 static int CmpName (const void* Key, const void* Instr)
972 /* Compare function for bsearch */
973 {
974     return strcmp ((const char*)Key, ((const InsDesc*) Instr)->Mnemonic);
975 }
976
977
978
979 void SetCPU (cpu_t NewCPU)
980 /* Set a new CPU */
981 {
982     /* Make sure the parameter is correct */
983     CHECK (NewCPU < CPU_COUNT);
984
985     /* Check if we have support for the new CPU, if so, use it */
986     if (InsTabs[NewCPU]) {
987         CPU = NewCPU;
988         InsTab = InsTabs[CPU];
989     } else {
990         Error ("CPU not supported");
991     }
992 }
993
994
995
996 cpu_t GetCPU (void)
997 /* Return the current CPU */
998 {
999     return CPU;
1000 }
1001
1002
1003
1004 int FindInstruction (const char* Ident)
1005 /* Check if Ident is a valid mnemonic. If so, return the index in the
1006  * instruction table. If not, return -1.
1007  */
1008 {
1009     unsigned I;
1010     const InsDesc* ID;
1011     char Key[sizeof (ID->Mnemonic)];
1012
1013     /* Make a copy, and uppercase that copy */
1014     I = 0;
1015     while (Ident[I] != '\0') {
1016         /* If the identifier is longer than the longest mnemonic, it cannot
1017          * be one.
1018          */
1019         if (I >= sizeof (Key) - 1) {
1020             /* Not found, no need for further action */
1021             return -1;
1022         }
1023         Key[I] = toupper ((unsigned char)Ident[I]);
1024         ++I;
1025     }
1026     Key[I] = '\0';
1027
1028     /* Search for the key */
1029     ID = bsearch (Key, InsTab->Ins, InsTab->Count, sizeof (InsDesc), CmpName);
1030     if (ID == 0) {
1031         /* Not found */
1032         return -1;
1033     } else {
1034         /* Found, return the entry */
1035         return ID - InsTab->Ins;
1036     }
1037 }
1038
1039
1040
1041 void HandleInstruction (unsigned Index)
1042 /* Handle the mnemonic with the given index */
1043 {
1044     /* Safety check */
1045     PRECONDITION (Index < InsTab->Count);
1046
1047     /* Skip the mnemonic token */
1048     NextTok ();
1049
1050     /* Call the handler */
1051     InsTab->Ins[Index].Emit (&InsTab->Ins[Index]);
1052 }
1053
1054
1055