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