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 65C02 */
221 #define INS_COUNT_65C02 66
222 static const struct {
224 InsDesc Ins[INS_COUNT_65C02];
228 { "ADC", 0x080A66C, 0x60, 0, PutAll },
229 { "AND", 0x080A66C, 0x20, 0, PutAll },
230 { "ASL", 0x000006e, 0x02, 1, PutAll },
231 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
232 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
233 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
234 { "BIT", 0x0A0006C, 0x00, 2, PutAll },
235 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
236 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
237 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
238 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
239 { "BRK", 0x0000001, 0x00, 0, PutAll },
240 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
241 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
242 { "CLC", 0x0000001, 0x18, 0, PutAll },
243 { "CLD", 0x0000001, 0xd8, 0, PutAll },
244 { "CLI", 0x0000001, 0x58, 0, PutAll },
245 { "CLV", 0x0000001, 0xb8, 0, PutAll },
246 { "CMP", 0x080A66C, 0xc0, 0, PutAll },
247 { "CPX", 0x080000C, 0xe0, 1, PutAll },
248 { "CPY", 0x080000C, 0xc0, 1, PutAll },
249 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
250 { "DEC", 0x000006F, 0x00, 3, PutAll },
251 { "DEX", 0x0000001, 0xca, 0, PutAll },
252 { "DEY", 0x0000001, 0x88, 0, PutAll },
253 { "EOR", 0x080A66C, 0x40, 0, PutAll },
254 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
255 { "INC", 0x000006f, 0x00, 4, PutAll },
256 { "INX", 0x0000001, 0xe8, 0, PutAll },
257 { "INY", 0x0000001, 0xc8, 0, PutAll },
258 { "JMP", 0x0010808, 0x4c, 6, PutAll },
259 { "JSR", 0x0000008, 0x20, 7, PutAll },
260 { "LDA", 0x080A66C, 0xa0, 0, PutAll },
261 { "LDX", 0x080030C, 0xa2, 1, PutAll },
262 { "LDY", 0x080006C, 0xa0, 1, PutAll },
263 { "LSR", 0x000006F, 0x42, 1, PutAll },
264 { "NOP", 0x0000001, 0xea, 0, PutAll },
265 { "ORA", 0x080A66C, 0x00, 0, PutAll },
266 { "PHA", 0x0000001, 0x48, 0, PutAll },
267 { "PHP", 0x0000001, 0x08, 0, PutAll },
268 { "PHX", 0x0000001, 0xda, 0, PutAll },
269 { "PHY", 0x0000001, 0x5a, 0, PutAll },
270 { "PLA", 0x0000001, 0x68, 0, PutAll },
271 { "PLP", 0x0000001, 0x28, 0, PutAll },
272 { "PLX", 0x0000001, 0xfa, 0, PutAll },
273 { "PLY", 0x0000001, 0x7a, 0, PutAll },
274 { "ROL", 0x000006F, 0x22, 1, PutAll },
275 { "ROR", 0x000006F, 0x62, 1, PutAll },
276 { "RTI", 0x0000001, 0x40, 0, PutAll },
277 { "RTS", 0x0000001, 0x60, 0, PutAll },
278 { "SBC", 0x080A66C, 0xe0, 0, PutAll },
279 { "SEC", 0x0000001, 0x38, 0, PutAll },
280 { "SED", 0x0000001, 0xf8, 0, PutAll },
281 { "SEI", 0x0000001, 0x78, 0, PutAll },
282 { "STA", 0x000A66C, 0x80, 0, PutAll },
283 { "STX", 0x000010c, 0x82, 1, PutAll },
284 { "STY", 0x000002c, 0x80, 1, PutAll },
285 { "STZ", 0x000006c, 0x04, 5, PutAll },
286 { "TAX", 0x0000001, 0xaa, 0, PutAll },
287 { "TAY", 0x0000001, 0xa8, 0, PutAll },
288 { "TRB", 0x000000c, 0x10, 1, PutAll },
289 { "TSB", 0x000000c, 0x00, 1, PutAll },
290 { "TSX", 0x0000001, 0xba, 0, PutAll },
291 { "TXA", 0x0000001, 0x8a, 0, PutAll },
292 { "TXS", 0x0000001, 0x9a, 0, PutAll },
293 { "TYA", 0x0000001, 0x98, 0, PutAll }
297 /* Instruction table for the 65816 */
298 #define INS_COUNT_65816 101
299 static const struct {
301 InsDesc Ins[INS_COUNT_65816];
305 { "ADC", 0x0b8f6fc, 0x60, 0, PutAll },
306 { "AND", 0x0b8f6fc, 0x20, 0, PutAll },
307 { "ASL", 0x000006e, 0x02, 1, PutAll },
308 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
309 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
310 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
311 { "BGE", 0x0020000, 0xb0, 0, PutPCRel8 }, /* == BCS */
312 { "BIT", 0x0a0006c, 0x00, 2, PutAll },
313 { "BLT", 0x0020000, 0x90, 0, PutPCRel8 }, /* == BCC */
314 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
315 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
316 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
317 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
318 { "BRK", 0x0000001, 0x00, 0, PutAll },
319 { "BRL", 0x0040000, 0x82, 0, PutPCRel16 },
320 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
321 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
322 { "CLC", 0x0000001, 0x18, 0, PutAll },
323 { "CLD", 0x0000001, 0xd8, 0, PutAll },
324 { "CLI", 0x0000001, 0x58, 0, PutAll },
325 { "CLV", 0x0000001, 0xb8, 0, PutAll },
326 { "CMP", 0x0b8f6fc, 0xc0, 0, PutAll },
327 { "COP", 0x0000004, 0x02, 6, PutAll },
328 { "CPA", 0x0b8f6fc, 0xc0, 0, PutAll }, /* == CMP */
329 { "CPX", 0x0c0000c, 0xe0, 1, PutAll },
330 { "CPY", 0x0c0000c, 0xc0, 1, PutAll },
331 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
332 { "DEC", 0x000006F, 0x00, 3, PutAll },
333 { "DEX", 0x0000001, 0xca, 0, PutAll },
334 { "DEY", 0x0000001, 0x88, 0, PutAll },
335 { "EOR", 0x0b8f6fc, 0x40, 0, PutAll },
336 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
337 { "INC", 0x000006F, 0x00, 4, PutAll },
338 { "INX", 0x0000001, 0xe8, 0, PutAll },
339 { "INY", 0x0000001, 0xc8, 0, PutAll },
340 { "JML", 0x0000810, 0x5c, 1, PutAll },
341 { "JMP", 0x0010818, 0x4c, 6, PutAll },
342 { "JSL", 0x0000010, 0x20, 7, PutAll },
343 { "JSR", 0x0010018, 0x20, 7, PutAll },
344 { "LDA", 0x0b8f6fc, 0xa0, 0, PutAll },
345 { "LDX", 0x0c0030c, 0xa2, 1, PutAll },
346 { "LDY", 0x0c0006c, 0xa0, 1, PutAll },
347 { "LSR", 0x000006F, 0x42, 1, PutAll },
348 { "MVN", 0x1000000, 0x54, 0, PutBlockMove },
349 { "MVP", 0x1000000, 0x44, 0, PutBlockMove },
350 { "NOP", 0x0000001, 0xea, 0, PutAll },
351 { "ORA", 0x0b8f6fc, 0x00, 0, PutAll },
352 { "PEA", 0x0000008, 0xf4, 6, PutAll },
353 { "PEI", 0x0000400, 0xd4, 1, PutAll },
354 { "PER", 0x0040000, 0x62, 0, PutPCRel16 },
355 { "PHA", 0x0000001, 0x48, 0, PutAll },
356 { "PHB", 0x0000001, 0x8b, 0, PutAll },
357 { "PHD", 0x0000001, 0x0b, 0, PutAll },
358 { "PHK", 0x0000001, 0x4b, 0, PutAll },
359 { "PHP", 0x0000001, 0x08, 0, PutAll },
360 { "PHX", 0x0000001, 0xda, 0, PutAll },
361 { "PHY", 0x0000001, 0x5a, 0, PutAll },
362 { "PLA", 0x0000001, 0x68, 0, PutAll },
363 { "PLB", 0x0000001, 0xab, 0, PutAll },
364 { "PLD", 0x0000001, 0x2b, 0, PutAll },
365 { "PLP", 0x0000001, 0x28, 0, PutAll },
366 { "PLX", 0x0000001, 0xfa, 0, PutAll },
367 { "PLY", 0x0000001, 0x7a, 0, PutAll },
368 { "REP", 0x0800000, 0xc2, 1, PutREP },
369 { "ROL", 0x000006F, 0x22, 1, PutAll },
370 { "ROR", 0x000006F, 0x62, 1, PutAll },
371 { "RTI", 0x0000001, 0x40, 0, PutAll },
372 { "RTL", 0x0000001, 0x6b, 0, PutAll },
373 { "RTS", 0x0000001, 0x60, 0, PutAll },
374 { "SBC", 0x0b8f6fc, 0xe0, 0, PutAll },
375 { "SEC", 0x0000001, 0x38, 0, PutAll },
376 { "SED", 0x0000001, 0xf8, 0, PutAll },
377 { "SEI", 0x0000001, 0x78, 0, PutAll },
378 { "SEP", 0x0800000, 0xe2, 1, PutSEP },
379 { "STA", 0x018f6fc, 0x80, 0, PutAll },
380 { "STP", 0x0000001, 0xdb, 0, PutAll },
381 { "STX", 0x000010c, 0x82, 1, PutAll },
382 { "STY", 0x000002c, 0x80, 1, PutAll },
383 { "STZ", 0x000006c, 0x04, 5, PutAll },
384 { "SWA", 0x0000001, 0xeb, 0, PutAll }, /* == XBA */
385 { "TAD", 0x0000001, 0x5b, 0, PutAll }, /* == TCD */
386 { "TAS", 0x0000001, 0x1b, 0, PutAll }, /* == TCS */
387 { "TAX", 0x0000001, 0xaa, 0, PutAll },
388 { "TAY", 0x0000001, 0xa8, 0, PutAll },
389 { "TCD", 0x0000001, 0x5b, 0, PutAll },
390 { "TCS", 0x0000001, 0x1b, 0, PutAll },
391 { "TDA", 0x0000001, 0x7b, 0, PutAll }, /* == TDC */
392 { "TDC", 0x0000001, 0x7b, 0, PutAll },
393 { "TRB", 0x000000c, 0x10, 1, PutAll },
394 { "TSA", 0x0000001, 0x3b, 0, PutAll }, /* == TSC */
395 { "TSB", 0x000000c, 0x00, 1, PutAll },
396 { "TSC", 0x0000001, 0x3b, 0, PutAll },
397 { "TSX", 0x0000001, 0xba, 0, PutAll },
398 { "TXA", 0x0000001, 0x8a, 0, PutAll },
399 { "TXS", 0x0000001, 0x9a, 0, PutAll },
400 { "TXY", 0x0000001, 0x9b, 0, PutAll },
401 { "TYA", 0x0000001, 0x98, 0, PutAll },
402 { "TYX", 0x0000001, 0xbb, 0, PutAll },
403 { "WAI", 0x0000001, 0xcb, 0, PutAll },
404 { "XBA", 0x0000001, 0xeb, 0, PutAll },
405 { "XCE", 0x0000001, 0xfb, 0, PutAll }
410 /* Table for the SUNPLUS CPU */
411 #include "sunplus.inc"
416 /* An array with instruction tables */
417 static const InsTable* InsTabs[CPU_COUNT] = {
418 (const InsTable*) &InsTab6502,
419 (const InsTable*) &InsTab65SC02,
420 (const InsTable*) &InsTab65C02,
421 (const InsTable*) &InsTab65816,
423 (const InsTable*) &InsTabSunPlus,
426 const InsTable* InsTab = (const InsTable*) &InsTab6502;
428 /* Table to build the effective opcode from a base opcode and an addressing
431 unsigned char EATab [9][AMI_COUNT] = {
433 0x00, 0x00, 0x05, 0x0D, 0x0F, 0x15, 0x1D, 0x1F,
434 0x00, 0x19, 0x12, 0x00, 0x07, 0x11, 0x17, 0x01,
435 0x00, 0x00, 0x00, 0x03, 0x13, 0x09, 0x00, 0x09,
439 0x08, 0x08, 0x04, 0x0C, 0x00, 0x14, 0x1C, 0x00,
440 0x14, 0x1C, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
441 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
445 0x00, 0x00, 0x24, 0x2C, 0x0F, 0x34, 0x3C, 0x00,
446 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
447 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00,
451 0x3A, 0x3A, 0xC6, 0xCE, 0x00, 0xD6, 0xDE, 0x00,
452 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
453 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
457 0x1A, 0x1A, 0xE6, 0xEE, 0x00, 0xF6, 0xFE, 0x00,
458 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
459 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
463 0x00, 0x00, 0x60, 0x98, 0x00, 0x70, 0x9E, 0x00,
464 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
465 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
469 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
470 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
471 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
475 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
476 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
477 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
481 0x00, 0x40, 0x01, 0x41, 0x00, 0x09, 0x49, 0x00,
482 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00,
483 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
488 /* Table that encodes the additional bytes for each instruction */
489 unsigned char ExtBytes [AMI_COUNT] = {
494 3, /* Absolute long */
497 3, /* Absolute long,X */
506 2, /* (Absolute,X) */
507 1, /* Relative short */
508 2, /* Relative long */
511 1, /* Immidiate accu */
512 1, /* Immidiate index */
513 1, /* Immidiate byte */
519 /*****************************************************************************/
520 /* Handler functions */
521 /*****************************************************************************/
525 static int EvalEA (const InsDesc* Ins, EffAddr* A)
526 /* Evaluate the effective address. All fields in A will be valid after calling
527 * this function. The function returns true on success and false on errors.
530 /* Get the set of possible addressing modes */
533 /* From the possible addressing modes, remove the ones that are invalid
534 * for this instruction or CPU.
536 A->AddrModeSet &= Ins->AddrMode;
538 /* If we have possible zero page addressing modes, and the expression
539 * involved (if any) is not in byte range, remove the zero page addressing
542 if (A->Expr && (A->AddrModeSet & AM_ZP) && !IsByteExpr (A->Expr)) {
543 A->AddrModeSet &= ~AM_ZP;
546 /* Check if we have any adressing modes left */
547 if (A->AddrModeSet == 0) {
548 Error (ERR_ILLEGAL_ADDR_MODE);
551 A->AddrMode = BitFind (A->AddrModeSet);
552 A->AddrModeBit = (0x01UL << A->AddrMode);
554 /* If the instruction has a one byte operand and immediate addressing is
555 * allowed but not used, check for an operand expression in the form
556 * <label or >label, where label is a far or absolute label. If found,
557 * emit a warning. This warning protects against a typo, where the '#'
558 * for the immediate operand is omitted.
560 if (A->Expr && (Ins->AddrMode & AM_IMM) &&
561 (A->AddrModeSet & (AM_DIR | AM_ABS | AM_ABS_LONG)) &&
562 ExtBytes[A->AddrMode] == 1) {
564 /* Found, check the expression */
565 ExprNode* Left = A->Expr->Left;
566 if ((A->Expr->Op == EXPR_BYTE0 || A->Expr->Op == EXPR_BYTE1) &&
567 Left->Op == EXPR_SYMBOL &&
568 !SymIsZP (Left->V.Sym)) {
570 /* Output a warning */
571 Warning (WARN_SUSPICIOUS_ADDREXPR);
575 /* Build the opcode */
576 A->Opcode = Ins->BaseCode | EATab[Ins->ExtCode][A->AddrMode];
584 static void EmitCode (EffAddr* A)
585 /* Output code for the data in A */
587 /* Check how many extension bytes are needed and output the instruction */
588 switch (ExtBytes[A->AddrMode]) {
595 Emit1 (A->Opcode, A->Expr);
599 if (CPU == CPU_65816 && (A->AddrModeBit & (AM_ABS | AM_ABS_X | AM_ABS_Y))) {
600 /* This is a 16 bit mode that uses an address. If in 65816,
601 * mode, force this address into 16 bit range to allow
602 * addressing inside a 64K segment.
604 Emit2 (A->Opcode, GenWordExpr (A->Expr));
606 Emit2 (A->Opcode, A->Expr);
612 /* Separate bank given */
613 Emit3b (A->Opcode, A->Expr, A->Bank);
615 /* One far argument */
616 Emit3 (A->Opcode, A->Expr);
621 Internal ("Invalid operand byte count: %u", ExtBytes[A->AddrMode]);
628 static long PutImmed8 (const InsDesc* Ins)
629 /* Parse and emit an immediate 8 bit instruction. Return the value of the
630 * operand if it's available and const.
636 /* Evaluate the addressing mode */
637 if (EvalEA (Ins, &A) == 0) {
638 /* An error occurred */
642 /* If we have an expression and it's const, get it's value */
643 if (A.Expr && IsConstExpr (A.Expr)) {
644 Val = GetExprVal (A.Expr);
647 /* Check how many extension bytes are needed and output the instruction */
648 switch (ExtBytes[A.AddrMode]) {
651 Emit1 (A.Opcode, A.Expr);
655 Internal ("Invalid operand byte count: %u", ExtBytes[A.AddrMode]);
658 /* Return the expression value */
664 static void PutPCRel8 (const InsDesc* Ins)
665 /* Handle branches with a 8 bit distance */
667 EmitPCRel (Ins->BaseCode, GenBranchExpr (2), 1);
672 static void PutPCRel16 (const InsDesc* Ins)
673 /* Handle branches with an 16 bit distance and PER */
675 EmitPCRel (Ins->BaseCode, GenBranchExpr (3), 2);
680 static void PutBlockMove (const InsDesc* Ins)
681 /* Handle the blockmove instructions */
683 Emit0 (Ins->BaseCode);
684 EmitByte (Expression ());
686 EmitByte (Expression ());
691 static void PutREP (const InsDesc* Ins)
692 /* Emit a REP instruction, track register sizes */
694 /* Use the generic handler */
695 long Val = PutImmed8 (Ins);
697 /* We track the status only for the 816 CPU and in smart mode */
698 if (CPU == CPU_65816 && SmartMode) {
700 /* Check the range for Val. */
702 /* We had an error */
703 Warning (WARN_CANNOT_TRACK_STATUS);
706 /* Index registers to 16 bit */
707 ExtBytes[AMI_IMM_INDEX] = 2;
711 ExtBytes[AMI_IMM_ACCU] = 2;
719 static void PutSEP (const InsDesc* Ins)
720 /* Emit a SEP instruction, track register sizes */
722 /* Use the generic handler */
723 long Val = PutImmed8 (Ins);
725 /* We track the status only for the 816 CPU and in smart mode */
726 if (CPU == CPU_65816 && SmartMode) {
728 /* Check the range for Val. */
730 /* We had an error */
731 Warning (WARN_CANNOT_TRACK_STATUS);
734 /* Index registers to 8 bit */
735 ExtBytes [AMI_IMM_INDEX] = 1;
739 ExtBytes [AMI_IMM_ACCU] = 1;
747 static void PutJmp (const InsDesc* Ins)
748 /* Handle the jump instruction for the 6502. Problem is that these chips have
749 * a bug: If the address crosses a page, the upper byte gets not corrected and
750 * the instruction will fail. The PutJmp function will add a linker assertion
751 * to check for this case and is otherwise identical to PutAll.
756 /* Evaluate the addressing mode used */
757 if (EvalEA (Ins, &A)) {
759 /* Check for indirect addressing */
760 if (A.AddrModeBit & AM_ABS_IND) {
762 /* Compare the low byte of the expression to 0xFF to check for
763 * a page cross. Be sure to use a copy of the expression otherwise
764 * things will go weird later.
766 ExprNode* E = GenNE (GenByteExpr (CloneExpr (A.Expr)), 0xFF);
768 /* Generate the message */
769 unsigned Msg = GetStringId ("\"jmp (abs)\" across page border");
771 /* Generate the assertion */
772 AddAssertion (E, ASSERT_ACT_WARN, Msg);
775 /* No error, output code */
782 static void PutAll (const InsDesc* Ins)
783 /* Handle all other instructions */
787 /* Evaluate the addressing mode used */
788 if (EvalEA (Ins, &A)) {
789 /* No error, output code */
796 /*****************************************************************************/
798 /*****************************************************************************/
802 static int CmpName (const void* Key, const void* Instr)
803 /* Compare function for bsearch */
805 return strcmp ((const char*)Key, ((const InsDesc*) Instr)->Mnemonic);
810 void SetCPU (cpu_t NewCPU)
813 /* Make sure the parameter is correct */
814 CHECK (NewCPU < CPU_COUNT);
816 /* Check if we have support for the new CPU, if so, use it */
817 if (InsTabs[NewCPU]) {
819 InsTab = InsTabs[CPU];
821 Error (ERR_CPU_NOT_SUPPORTED);
828 /* Return the current CPU */
835 int FindInstruction (const char* Ident)
836 /* Check if Ident is a valid mnemonic. If so, return the index in the
837 * instruction table. If not, return -1.
841 char Key [sizeof (I->Mnemonic)];
843 /* Accept only strings with the right length */
844 if (strlen (Ident) != sizeof (I->Mnemonic)-1) {
849 /* Make a copy, and uppercase that copy */
850 Key [0] = toupper (Ident [0]);
851 Key [1] = toupper (Ident [1]);
852 Key [2] = toupper (Ident [2]);
855 /* Search for the key */
856 I = bsearch (Key, InsTab->Ins, InsTab->Count, sizeof (InsDesc), CmpName);
861 /* Found, return the entry */
862 return I - InsTab->Ins;
868 void HandleInstruction (unsigned Index)
869 /* Handle the mnemonic with the given index */
872 PRECONDITION (Index < InsTab->Count);
874 /* Skip the mnemonic token */
877 /* Call the handler */
878 InsTab->Ins[Index].Emit (&InsTab->Ins[Index]);