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