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