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