1 /*****************************************************************************/
5 /* Instruction encoding for the ca65 macroassembler */
9 /* (C) 1998-2003 Ullrich von Bassewitz */
10 /* Römerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
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. */
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: */
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 */
32 /*****************************************************************************/
41 #include "assertdefs.h"
59 /*****************************************************************************/
61 /*****************************************************************************/
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);
76 /* Instruction table for the 6502 */
77 #define INS_COUNT_6502 56
80 InsDesc Ins[INS_COUNT_6502];
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 }
143 /* Instruction table for the 65SC02 */
144 #define INS_COUNT_65SC02 66
145 static const struct {
147 InsDesc Ins[INS_COUNT_65SC02];
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 }
220 /* Instruction table for the 65816 */
221 #define INS_COUNT_65816 101
222 static const struct {
224 InsDesc Ins[INS_COUNT_65816];
228 { "ADC", 0x0b8f6fc, 0x60, 0, PutAll },
229 { "AND", 0x0b8f6fc, 0x20, 0, PutAll },
230 { "ASL", 0x000006e, 0x02, 1, PutAll },
231 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
232 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
233 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
234 { "BGE", 0x0020000, 0xb0, 0, PutPCRel8 }, /* == BCS */
235 { "BIT", 0x0a0006c, 0x00, 2, PutAll },
236 { "BLT", 0x0020000, 0x90, 0, PutPCRel8 }, /* == BCC */
237 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
238 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
239 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
240 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
241 { "BRK", 0x0000001, 0x00, 0, PutAll },
242 { "BRL", 0x0040000, 0x82, 0, PutPCRel16 },
243 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
244 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
245 { "CLC", 0x0000001, 0x18, 0, PutAll },
246 { "CLD", 0x0000001, 0xd8, 0, PutAll },
247 { "CLI", 0x0000001, 0x58, 0, PutAll },
248 { "CLV", 0x0000001, 0xb8, 0, PutAll },
249 { "CMP", 0x0b8f6fc, 0xc0, 0, PutAll },
250 { "COP", 0x0000004, 0x02, 6, PutAll },
251 { "CPA", 0x0b8f6fc, 0xc0, 0, PutAll }, /* == CMP */
252 { "CPX", 0x0c0000c, 0xe0, 1, PutAll },
253 { "CPY", 0x0c0000c, 0xc0, 1, PutAll },
254 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
255 { "DEC", 0x000006F, 0x00, 3, PutAll },
256 { "DEX", 0x0000001, 0xca, 0, PutAll },
257 { "DEY", 0x0000001, 0x88, 0, PutAll },
258 { "EOR", 0x0b8f6fc, 0x40, 0, PutAll },
259 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
260 { "INC", 0x000006F, 0x00, 4, PutAll },
261 { "INX", 0x0000001, 0xe8, 0, PutAll },
262 { "INY", 0x0000001, 0xc8, 0, PutAll },
263 { "JML", 0x0000810, 0x5c, 1, PutAll },
264 { "JMP", 0x0010818, 0x4c, 6, PutAll },
265 { "JSL", 0x0000010, 0x20, 7, PutAll },
266 { "JSR", 0x0010018, 0x20, 7, PutAll },
267 { "LDA", 0x0b8f6fc, 0xa0, 0, PutAll },
268 { "LDX", 0x0c0030c, 0xa2, 1, PutAll },
269 { "LDY", 0x0c0006c, 0xa0, 1, PutAll },
270 { "LSR", 0x000006F, 0x42, 1, PutAll },
271 { "MVN", 0x1000000, 0x54, 0, PutBlockMove },
272 { "MVP", 0x1000000, 0x44, 0, PutBlockMove },
273 { "NOP", 0x0000001, 0xea, 0, PutAll },
274 { "ORA", 0x0b8f6fc, 0x00, 0, PutAll },
275 { "PEA", 0x0000008, 0xf4, 6, PutAll },
276 { "PEI", 0x0000400, 0xd4, 1, PutAll },
277 { "PER", 0x0040000, 0x62, 0, PutPCRel16 },
278 { "PHA", 0x0000001, 0x48, 0, PutAll },
279 { "PHB", 0x0000001, 0x8b, 0, PutAll },
280 { "PHD", 0x0000001, 0x0b, 0, PutAll },
281 { "PHK", 0x0000001, 0x4b, 0, PutAll },
282 { "PHP", 0x0000001, 0x08, 0, PutAll },
283 { "PHX", 0x0000001, 0xda, 0, PutAll },
284 { "PHY", 0x0000001, 0x5a, 0, PutAll },
285 { "PLA", 0x0000001, 0x68, 0, PutAll },
286 { "PLB", 0x0000001, 0xab, 0, PutAll },
287 { "PLD", 0x0000001, 0x2b, 0, PutAll },
288 { "PLP", 0x0000001, 0x28, 0, PutAll },
289 { "PLX", 0x0000001, 0xfa, 0, PutAll },
290 { "PLY", 0x0000001, 0x7a, 0, PutAll },
291 { "REP", 0x0800000, 0xc2, 1, PutREP },
292 { "ROL", 0x000006F, 0x22, 1, PutAll },
293 { "ROR", 0x000006F, 0x62, 1, PutAll },
294 { "RTI", 0x0000001, 0x40, 0, PutAll },
295 { "RTL", 0x0000001, 0x6b, 0, PutAll },
296 { "RTS", 0x0000001, 0x60, 0, PutAll },
297 { "SBC", 0x0b8f6fc, 0xe0, 0, PutAll },
298 { "SEC", 0x0000001, 0x38, 0, PutAll },
299 { "SED", 0x0000001, 0xf8, 0, PutAll },
300 { "SEI", 0x0000001, 0x78, 0, PutAll },
301 { "SEP", 0x0800000, 0xe2, 1, PutSEP },
302 { "STA", 0x018f6fc, 0x80, 0, PutAll },
303 { "STP", 0x0000001, 0xdb, 0, PutAll },
304 { "STX", 0x000010c, 0x82, 1, PutAll },
305 { "STY", 0x000002c, 0x80, 1, PutAll },
306 { "STZ", 0x000006c, 0x04, 5, PutAll },
307 { "SWA", 0x0000001, 0xeb, 0, PutAll }, /* == XBA */
308 { "TAD", 0x0000001, 0x5b, 0, PutAll }, /* == TCD */
309 { "TAS", 0x0000001, 0x1b, 0, PutAll }, /* == TCS */
310 { "TAX", 0x0000001, 0xaa, 0, PutAll },
311 { "TAY", 0x0000001, 0xa8, 0, PutAll },
312 { "TCD", 0x0000001, 0x5b, 0, PutAll },
313 { "TCS", 0x0000001, 0x1b, 0, PutAll },
314 { "TDA", 0x0000001, 0x7b, 0, PutAll }, /* == TDC */
315 { "TDC", 0x0000001, 0x7b, 0, PutAll },
316 { "TRB", 0x000000c, 0x10, 1, PutAll },
317 { "TSA", 0x0000001, 0x3b, 0, PutAll }, /* == TSC */
318 { "TSB", 0x000000c, 0x00, 1, PutAll },
319 { "TSC", 0x0000001, 0x3b, 0, PutAll },
320 { "TSX", 0x0000001, 0xba, 0, PutAll },
321 { "TXA", 0x0000001, 0x8a, 0, PutAll },
322 { "TXS", 0x0000001, 0x9a, 0, PutAll },
323 { "TXY", 0x0000001, 0x9b, 0, PutAll },
324 { "TYA", 0x0000001, 0x98, 0, PutAll },
325 { "TYX", 0x0000001, 0xbb, 0, PutAll },
326 { "WAI", 0x0000001, 0xcb, 0, PutAll },
327 { "XBA", 0x0000001, 0xeb, 0, PutAll },
328 { "XCE", 0x0000001, 0xfb, 0, PutAll }
333 /* Table for the SUNPLUS CPU */
334 #include "sunplus.inc"
339 /* An array with instruction tables */
340 static const InsTable* InsTabs[CPU_COUNT] = {
341 (const InsTable*) &InsTab6502,
342 (const InsTable*) &InsTab65SC02,
343 (const InsTable*) &InsTab65816,
345 (const InsTable*) &InsTabSunPlus,
350 const InsTable* InsTab = (const InsTable*) &InsTab6502;
352 /* Table to build the effective opcode from a base opcode and an addressing
355 unsigned char EATab [9][AMI_COUNT] = {
357 0x00, 0x00, 0x05, 0x0D, 0x0F, 0x15, 0x1D, 0x1F,
358 0x00, 0x19, 0x12, 0x00, 0x07, 0x11, 0x17, 0x01,
359 0x00, 0x00, 0x00, 0x03, 0x13, 0x09, 0x00, 0x09,
363 0x08, 0x08, 0x04, 0x0C, 0x00, 0x14, 0x1C, 0x00,
364 0x14, 0x1C, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
365 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
369 0x00, 0x00, 0x24, 0x2C, 0x0F, 0x34, 0x3C, 0x00,
370 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
371 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00,
375 0x3A, 0x3A, 0xC6, 0xCE, 0x00, 0xD6, 0xDE, 0x00,
376 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
377 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
381 0x1A, 0x1A, 0xE6, 0xEE, 0x00, 0xF6, 0xFE, 0x00,
382 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
383 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
387 0x00, 0x00, 0x60, 0x98, 0x00, 0x70, 0x9E, 0x00,
388 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
389 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
393 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
394 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
395 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
399 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
400 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
401 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
405 0x00, 0x40, 0x01, 0x41, 0x00, 0x09, 0x49, 0x00,
406 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00,
407 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
412 /* Table that encodes the additional bytes for each instruction */
413 unsigned char ExtBytes [AMI_COUNT] = {
418 3, /* Absolute long */
421 3, /* Absolute long,X */
430 2, /* (Absolute,X) */
431 1, /* Relative short */
432 2, /* Relative long */
435 1, /* Immidiate accu */
436 1, /* Immidiate index */
437 1, /* Immidiate byte */
443 /*****************************************************************************/
444 /* Handler functions */
445 /*****************************************************************************/
449 static int EvalEA (const InsDesc* Ins, EffAddr* A)
450 /* Evaluate the effective address. All fields in A will be valid after calling
451 * this function. The function returns true on success and false on errors.
454 /* Get the set of possible addressing modes */
457 /* From the possible addressing modes, remove the ones that are invalid
458 * for this instruction or CPU.
460 A->AddrModeSet &= Ins->AddrMode;
462 /* If we have possible zero page addressing modes, and the expression
463 * involved (if any) is not in byte range, remove the zero page addressing
466 if (A->Expr && (A->AddrModeSet & AM_ZP) && !IsByteExpr (A->Expr)) {
467 A->AddrModeSet &= ~AM_ZP;
470 /* Check if we have any adressing modes left */
471 if (A->AddrModeSet == 0) {
472 Error (ERR_ILLEGAL_ADDR_MODE);
475 A->AddrMode = BitFind (A->AddrModeSet);
476 A->AddrModeBit = (0x01UL << A->AddrMode);
478 /* If the instruction has a one byte operand and immediate addressing is
479 * allowed but not used, check for an operand expression in the form
480 * <label or >label, where label is a far or absolute label. If found,
481 * emit a warning. This warning protects against a typo, where the '#'
482 * for the immediate operand is omitted.
484 if (A->Expr && (Ins->AddrMode & AM_IMM) &&
485 (A->AddrModeSet & (AM_DIR | AM_ABS | AM_ABS_LONG)) &&
486 ExtBytes[A->AddrMode] == 1) {
488 /* Found, check the expression */
489 ExprNode* Left = A->Expr->Left;
490 if ((A->Expr->Op == EXPR_BYTE0 || A->Expr->Op == EXPR_BYTE1) &&
491 Left->Op == EXPR_SYMBOL &&
492 !SymIsZP (Left->V.Sym)) {
494 /* Output a warning */
495 Warning (WARN_SUSPICIOUS_ADDREXPR);
499 /* Build the opcode */
500 A->Opcode = Ins->BaseCode | EATab[Ins->ExtCode][A->AddrMode];
508 static void EmitCode (EffAddr* A)
509 /* Output code for the data in A */
511 /* Check how many extension bytes are needed and output the instruction */
512 switch (ExtBytes[A->AddrMode]) {
519 Emit1 (A->Opcode, A->Expr);
523 if (CPU == CPU_65816 && (A->AddrModeBit & (AM_ABS | AM_ABS_X | AM_ABS_Y))) {
524 /* This is a 16 bit mode that uses an address. If in 65816,
525 * mode, force this address into 16 bit range to allow
526 * addressing inside a 64K segment.
528 Emit2 (A->Opcode, GenWordExpr (A->Expr));
530 Emit2 (A->Opcode, A->Expr);
536 /* Separate bank given */
537 Emit3b (A->Opcode, A->Expr, A->Bank);
539 /* One far argument */
540 Emit3 (A->Opcode, A->Expr);
545 Internal ("Invalid operand byte count: %u", ExtBytes[A->AddrMode]);
552 static long PutImmed8 (const InsDesc* Ins)
553 /* Parse and emit an immediate 8 bit instruction. Return the value of the
554 * operand if it's available and const.
560 /* Evaluate the addressing mode */
561 if (EvalEA (Ins, &A) == 0) {
562 /* An error occurred */
566 /* If we have an expression and it's const, get it's value */
567 if (A.Expr && IsConstExpr (A.Expr)) {
568 Val = GetExprVal (A.Expr);
571 /* Check how many extension bytes are needed and output the instruction */
572 switch (ExtBytes[A.AddrMode]) {
575 Emit1 (A.Opcode, A.Expr);
579 Internal ("Invalid operand byte count: %u", ExtBytes[A.AddrMode]);
582 /* Return the expression value */
588 static void PutPCRel8 (const InsDesc* Ins)
589 /* Handle branches with a 8 bit distance */
591 EmitPCRel (Ins->BaseCode, GenBranchExpr (2), 1);
596 static void PutPCRel16 (const InsDesc* Ins)
597 /* Handle branches with an 16 bit distance and PER */
599 EmitPCRel (Ins->BaseCode, GenBranchExpr (3), 2);
604 static void PutBlockMove (const InsDesc* Ins)
605 /* Handle the blockmove instructions */
607 Emit0 (Ins->BaseCode);
608 EmitByte (Expression ());
610 EmitByte (Expression ());
615 static void PutREP (const InsDesc* Ins)
616 /* Emit a REP instruction, track register sizes */
618 /* Use the generic handler */
619 long Val = PutImmed8 (Ins);
621 /* We track the status only for the 816 CPU and in smart mode */
622 if (CPU == CPU_65816 && SmartMode) {
624 /* Check the range for Val. */
626 /* We had an error */
627 Warning (WARN_CANNOT_TRACK_STATUS);
630 /* Index registers to 16 bit */
631 ExtBytes[AMI_IMM_INDEX] = 2;
635 ExtBytes[AMI_IMM_ACCU] = 2;
643 static void PutSEP (const InsDesc* Ins)
644 /* Emit a SEP instruction, track register sizes */
646 /* Use the generic handler */
647 long Val = PutImmed8 (Ins);
649 /* We track the status only for the 816 CPU and in smart mode */
650 if (CPU == CPU_65816 && SmartMode) {
652 /* Check the range for Val. */
654 /* We had an error */
655 Warning (WARN_CANNOT_TRACK_STATUS);
658 /* Index registers to 8 bit */
659 ExtBytes [AMI_IMM_INDEX] = 1;
663 ExtBytes [AMI_IMM_ACCU] = 1;
671 static void PutJmp (const InsDesc* Ins)
672 /* Handle the jump instruction for the 6502. Problem is that these chips have
673 * a bug: If the address crosses a page, the upper byte gets not corrected and
674 * the instruction will fail. The PutJmp function will add a linker assertion
675 * to check for this case and is otherwise identical to PutAll.
680 /* Evaluate the addressing mode used */
681 if (EvalEA (Ins, &A)) {
683 /* Check for indirect addressing */
684 if (A.AddrModeBit & AM_ABS_IND) {
686 /* Compare the low byte of the expression to 0xFF to check for
687 * a page cross. Be sure to use a copy of the expression otherwise
688 * things will go weird later.
690 ExprNode* E = GenNE (GenByteExpr (CloneExpr (A.Expr)), 0xFF);
692 /* Generate the message */
693 unsigned Msg = GetStringId ("\"jmp (abs)\" across page border");
695 /* Generate the assertion */
696 AddAssertion (E, ASSERT_ACT_WARN, Msg);
699 /* No error, output code */
706 static void PutAll (const InsDesc* Ins)
707 /* Handle all other instructions */
711 /* Evaluate the addressing mode used */
712 if (EvalEA (Ins, &A)) {
713 /* No error, output code */
720 /*****************************************************************************/
722 /*****************************************************************************/
726 static int CmpName (const void* Key, const void* Instr)
727 /* Compare function for bsearch */
729 return strcmp ((const char*)Key, ((const InsDesc*) Instr)->Mnemonic);
734 void SetCPU (cpu_t NewCPU)
737 /* Make sure the parameter is correct */
738 CHECK (NewCPU < CPU_COUNT);
740 /* Check if we have support for the new CPU, if so, use it */
741 if (InsTabs[NewCPU]) {
743 InsTab = InsTabs[CPU];
745 Error (ERR_CPU_NOT_SUPPORTED);
752 /* Return the current CPU */
759 int FindInstruction (const char* Ident)
760 /* Check if Ident is a valid mnemonic. If so, return the index in the
761 * instruction table. If not, return -1.
765 char Key [sizeof (I->Mnemonic)];
767 /* Accept only strings with the right length */
768 if (strlen (Ident) != sizeof (I->Mnemonic)-1) {
773 /* Make a copy, and uppercase that copy */
774 Key [0] = toupper (Ident [0]);
775 Key [1] = toupper (Ident [1]);
776 Key [2] = toupper (Ident [2]);
779 /* Search for the key */
780 I = bsearch (Key, InsTab->Ins, InsTab->Count, sizeof (InsDesc), CmpName);
785 /* Found, return the entry */
786 return I - InsTab->Ins;
792 void HandleInstruction (unsigned Index)
793 /* Handle the mnemonic with the given index */
796 PRECONDITION (Index < InsTab->Count);
798 /* Skip the mnemonic token */
801 /* Call the handler */
802 InsTab->Ins[Index].Emit (&InsTab->Ins[Index]);