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