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