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