]> git.sur5r.net Git - cc65/blob - src/ca65/instr.c
Added LOWCODE and STARTUP segments
[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 /* 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 /* The current CPU and an array with instruction tables */
335 static enum CPUType CPU = CPU_6502;
336 static const InsTable* InsTabs[CPU_COUNT] = {
337     (const InsTable*) &InsTab6502,
338     (const InsTable*) &InsTab65SC02,
339     (const InsTable*) &InsTab65816,
340 #ifdef SUNPLUS
341     (const InsTable*) &InsTabSunPlus,
342 #else
343     NULL,
344 #endif
345 };
346 const InsTable* InsTab = (const InsTable*) &InsTab6502;
347
348 /* Table to build the effective opcode from a base opcode and an addressing
349  * mode.
350  */
351 unsigned char EATab [9][AMI_COUNT] = {
352     {   /* Table 0 */
353         0x00, 0x00, 0x05, 0x0D, 0x0F, 0x15, 0x1D, 0x1F,
354         0x00, 0x19, 0x12, 0x00, 0x07, 0x11, 0x17, 0x01,
355         0x00, 0x00, 0x00, 0x03, 0x13, 0x09, 0x00, 0x09,
356         0x00
357     },
358     {   /* Table 1 */
359         0x08, 0x08, 0x04, 0x0C, 0x00, 0x14, 0x1C, 0x00,
360         0x14, 0x1C, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
361         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
362         0x00
363     },
364     {   /* Table 2 */
365         0x00, 0x00, 0x24, 0x2C, 0x0F, 0x34, 0x3C, 0x00,
366         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
367         0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00,
368         0x00
369     },
370     {   /* Table 3 */
371         0x3A, 0x3A, 0xC6, 0xCE, 0x00, 0xD6, 0xDE, 0x00,
372         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
373         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
374         0x00
375     },
376     {   /* Table 4 */
377         0x1A, 0x1A, 0xE6, 0xEE, 0x00, 0xF6, 0xFE, 0x00,
378         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
379         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
380         0x00
381     },
382     {   /* Table 5 */
383         0x00, 0x00, 0x60, 0x98, 0x00, 0x70, 0x9E, 0x00,
384         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
385         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
386         0x00
387     },
388     {   /* Table 6 */
389         0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
390         0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
391         0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
392         0x00
393     },
394     {   /* Table 7 */
395         0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
396         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
397         0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
398         0x00
399     },
400     {   /* Table 8 */
401         0x00, 0x40, 0x01, 0x41, 0x00, 0x09, 0x49, 0x00,
402         0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00,
403         0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
404         0x00
405     },
406 };
407
408 /* Table that encodes the additional bytes for each instruction */
409 unsigned char ExtBytes [AMI_COUNT] = {
410     0,          /* Implicit */
411     0,          /* Accu */
412     1,          /* Direct */
413     2,          /* Absolute */
414     3,          /* Absolute long */
415     1,          /* Direct,X */
416     2,          /* Absolute,X */
417     3,          /* Absolute long,X */
418     1,          /* Direct,Y */
419     2,          /* Absolute,Y */
420     1,          /* (Direct) */
421     2,          /* (Absolute) */
422     1,          /* [Direct] */
423     1,          /* (Direct),Y */
424     1,          /* [Direct],Y */
425     1,          /* (Direct,X) */
426     2,          /* (Absolute,X) */
427     1,          /* Relative short */
428     2,          /* Relative long */
429     1,          /* r,s */
430     1,          /* (r,s),y */
431     1,          /* Immidiate accu */
432     1,          /* Immidiate index */
433     1,          /* Immidiate byte */
434     2           /* Blockmove */
435 };
436
437
438
439 /*****************************************************************************/
440 /*                             Handler functions                             */
441 /*****************************************************************************/
442
443
444
445 static long PutImmed8 (const InsDesc* Ins)
446 /* Parse and emit an immediate 8 bit instruction. Return the value of the
447  * operand if it's available and const.
448  */
449 {
450     ExprNode* Expr;
451     ExprNode* Bank;
452     unsigned long AddrMode;
453     unsigned char OpCode;
454     long Val = -1;
455
456     /* Get the addressing mode used */
457     GetEA (&AddrMode, &Expr, &Bank);
458
459     /* From the possible addressing modes, remove the ones that are invalid
460      * for this instruction or CPU.
461      */
462     AddrMode &= Ins->AddrMode;
463
464     /* If we have possible zero page addressing modes, and the expression
465      * involved (if any) is not in byte range, remove the zero page addressing
466      * modes.
467      */
468     if (Expr && (AddrMode & AM_ZP) && !IsByteExpr (Expr)) {
469         AddrMode &= ~AM_ZP;
470     }
471
472     /* Check if we have any adressing modes left */
473     if (AddrMode == 0) {
474         Error (ERR_ILLEGAL_ADDR_MODE);
475         return -1;
476     }
477     AddrMode = BitFind (AddrMode);
478
479     /* Build the opcode */
480     OpCode = Ins->BaseCode | EATab [Ins->ExtCode][AddrMode];
481
482     /* If we have an expression and it's const, get it's value */
483     if (Expr && IsConstExpr (Expr)) {
484         Val = GetExprVal (Expr);
485     }
486
487     /* Check how many extension bytes are needed and output the instruction */
488     switch (ExtBytes [AddrMode]) {
489
490         case 1:
491             Emit1 (OpCode, Expr);
492             break;
493
494         default:
495             Internal ("Invalid operand byte count: %u", ExtBytes [AddrMode]);
496     }
497
498     /* Return the expression value */
499     return Val;
500 }
501
502
503
504 static void PutPCRel8 (const InsDesc* Ins)
505 /* Handle branches with a 8 bit distance */
506 {
507     EmitPCRel (Ins->BaseCode, BranchExpr (2), 1);
508 }
509
510
511
512 static void PutPCRel16 (const InsDesc* Ins)
513 /* Handle branches with an 16 bit distance and PER */
514 {
515     EmitPCRel (Ins->BaseCode, BranchExpr (3), 2);
516 }
517
518
519
520 static void PutBlockMove (const InsDesc* Ins)
521 /* Handle the blockmove instructions */
522 {
523     Emit0 (Ins->BaseCode);
524     EmitByte (Expression ());
525     ConsumeComma ();
526     EmitByte (Expression ());
527 }
528
529
530
531 static void PutREP (const InsDesc* Ins)
532 /* Emit a REP instruction, track register sizes */
533 {
534     /* Use the generic handler */
535     long Val = PutImmed8 (Ins);
536
537     /* We track the status only for the 816 CPU and in smart mode */
538     if (CPU == CPU_65816 && SmartMode) {
539
540         /* Check the range for Val. */
541         if (Val < 0) {
542             /* We had an error */
543             Warning (WARN_CANNOT_TRACK_STATUS);
544         } else {
545             if (Val & 0x10) {
546                 /* Index registers to 16 bit */
547                 ExtBytes [AMI_IMM_INDEX] = 2;
548             }
549             if (Val & 0x20) {
550                 /* Accu to 16 bit */
551                 ExtBytes [AMI_IMM_ACCU] = 2;
552             }
553         }
554     }
555 }
556
557
558
559 static void PutSEP (const InsDesc* Ins)
560 /* Emit a SEP instruction, track register sizes */
561 {
562     /* Use the generic handler */
563     long Val = PutImmed8 (Ins);
564
565     /* We track the status only for the 816 CPU and in smart mode */
566     if (CPU == CPU_65816 && SmartMode) {
567
568         /* Check the range for Val. */
569         if (Val < 0) {
570             /* We had an error */
571             Warning (WARN_CANNOT_TRACK_STATUS);
572         } else {
573             if (Val & 0x10) {
574                 /* Index registers to 8 bit */
575                 ExtBytes [AMI_IMM_INDEX] = 1;
576             }
577             if (Val & 0x20) {
578                 /* Accu to 8 bit */
579                 ExtBytes [AMI_IMM_ACCU] = 1;
580             }
581         }
582     }
583 }
584
585
586
587 static void PutAll (const InsDesc* Ins)
588 /* Handle all other instructions */
589 {
590     ExprNode* Expr;
591     ExprNode* Bank;
592     unsigned long AddrModeSet;
593     unsigned char OpCode;
594     unsigned AddrMode;
595     unsigned long AddrModeBit;
596
597     /* Get the addressing mode used */
598     GetEA (&AddrModeSet, &Expr, &Bank);
599
600     /* From the possible addressing modes, remove the ones that are invalid
601      * for this instruction or CPU.
602      */
603     AddrModeSet &= Ins->AddrMode;
604
605     /* If we have possible zero page addressing modes, and the expression
606      * involved (if any) is not in byte range, remove the zero page addressing
607      * modes.
608      */
609     if (Expr && (AddrModeSet & AM_ZP) && !IsByteExpr (Expr)) {
610         AddrModeSet &= ~AM_ZP;
611     }
612
613     /* Check if we have any adressing modes left */
614     if (AddrModeSet == 0) {
615         Error (ERR_ILLEGAL_ADDR_MODE);
616         return;
617     }
618     AddrMode = BitFind (AddrModeSet);
619
620     /* Build the opcode */
621     OpCode = Ins->BaseCode | EATab [Ins->ExtCode][AddrMode];
622
623     /* Check how many extension bytes are needed and output the instruction */
624     switch (ExtBytes [AddrMode]) {
625
626         case 0:
627             Emit0 (OpCode);
628             break;
629
630         case 1:
631             Emit1 (OpCode, Expr);
632             break;
633
634         case 2:
635             AddrModeBit = (1L << AddrMode);
636             if (CPU == CPU_65816 && (AddrModeBit & (AM_ABS | AM_ABS_X | AM_ABS_Y))) {
637                 /* This is a 16 bit mode that uses an address. If in 65816,
638                  * mode, force this address into 16 bit range to allow
639                  * addressing inside a 64K segment.
640                  */
641                 Emit2 (OpCode, ForceWordExpr (Expr));
642             } else {
643                 Emit2 (OpCode, Expr);
644             }
645             break;
646
647         case 3:
648             if (Bank) {
649                 /* Separate bank given */
650                 Emit3b (OpCode, Expr, Bank);
651             } else {
652                 /* One far argument */
653                 Emit3 (OpCode, Expr);
654             }
655             break;
656
657         default:
658             Internal ("Invalid operand byte count: %u", ExtBytes [AddrMode]);
659
660     }
661 }
662
663
664
665 /*****************************************************************************/
666 /*                                   Code                                    */
667 /*****************************************************************************/
668
669
670
671 static int CmpName (const void* Key, const void* Instr)
672 /* Compare function for bsearch */
673 {
674     return strcmp ((const char*)Key, ((const InsDesc*) Instr)->Mnemonic);
675 }
676
677
678
679 void SetCPU (enum CPUType NewCPU)
680 /* Set a new CPU */
681 {
682     /* Make sure the parameter is correct */
683     CHECK (NewCPU < CPU_COUNT);
684
685     /* Check if we have support for the new CPU, if so, use it */
686     if (InsTabs[NewCPU]) {
687         CPU = NewCPU;
688         InsTab = InsTabs[CPU];
689     } else {
690         Error (ERR_CPU_NOT_SUPPORTED);
691     }
692 }
693
694
695
696 enum CPUType GetCPU (void)
697 /* Return the current CPU */
698 {
699     return CPU;
700 }
701
702
703
704 int FindInstruction (const char* Ident)
705 /* Check if Ident is a valid mnemonic. If so, return the index in the
706  * instruction table. If not, return -1.
707  */
708 {
709     const InsDesc* I;
710     char Key [sizeof (I->Mnemonic)];
711
712     /* Accept only strings with the right length */
713     if (strlen (Ident) != sizeof (I->Mnemonic)-1) {
714         /* Wrong length */
715         return -1;
716     }
717
718     /* Make a copy, and uppercase that copy */
719     Key [0] = toupper (Ident [0]);
720     Key [1] = toupper (Ident [1]);
721     Key [2] = toupper (Ident [2]);
722     Key [3] = '\0';
723
724     /* Search for the key */
725     I = bsearch (Key, InsTab->Ins, InsTab->Count, sizeof (InsDesc), CmpName);
726     if (I == 0) {
727         /* Not found */
728         return -1;
729     } else {
730         /* Found, return the entry */
731         return I - InsTab->Ins;
732     }
733 }
734
735
736
737 void HandleInstruction (unsigned Index)
738 /* Handle the mnemonic with the given index */
739 {
740     /* Safety check */
741     PRECONDITION (Index < InsTab->Count);
742
743     /* Skip the mnemonic token */
744     NextTok ();
745
746     /* Call the handler */
747     InsTab->Ins[Index].Emit (&InsTab->Ins[Index]);
748 }
749
750
751