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