1 /*****************************************************************************/
5 /* Instruction encoding for the ca65 macroassembler */
9 /* (C) 1998-2004 Ullrich von Bassewitz */
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 /*****************************************************************************/
42 #include "assertdefs.h"
60 #include "studyexpr.h"
65 /*****************************************************************************/
67 /*****************************************************************************/
71 /* Forwards for handler functions */
72 static void PutPCRel8 (const InsDesc* Ins);
73 static void PutPCRel16 (const InsDesc* Ins);
74 static void PutBlockMove (const InsDesc* Ins);
75 static void PutBitBranch (const InsDesc* Ins);
76 static void PutREP (const InsDesc* Ins);
77 static void PutSEP (const InsDesc* Ins);
78 static void PutJMP (const InsDesc* Ins);
79 static void PutRTS (const InsDesc* Ins);
80 static void PutAll (const InsDesc* Ins);
81 static void PutSweet16 (const InsDesc* Ins);
82 static void PutSweet16Branch (const InsDesc* Ins);
86 /* Empty instruction table */
93 /* Instruction table for the 6502 */
94 #define INS_COUNT_6502 56
97 InsDesc Ins[INS_COUNT_6502];
101 { "ADC", 0x080A26C, 0x60, 0, PutAll },
102 { "AND", 0x080A26C, 0x20, 0, PutAll },
103 { "ASL", 0x000006e, 0x02, 1, PutAll },
104 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
105 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
106 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
107 { "BIT", 0x000000C, 0x00, 2, PutAll },
108 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
109 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
110 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
111 { "BRK", 0x0000001, 0x00, 0, PutAll },
112 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
113 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
114 { "CLC", 0x0000001, 0x18, 0, PutAll },
115 { "CLD", 0x0000001, 0xd8, 0, PutAll },
116 { "CLI", 0x0000001, 0x58, 0, PutAll },
117 { "CLV", 0x0000001, 0xb8, 0, PutAll },
118 { "CMP", 0x080A26C, 0xc0, 0, PutAll },
119 { "CPX", 0x080000C, 0xe0, 1, PutAll },
120 { "CPY", 0x080000C, 0xc0, 1, PutAll },
121 { "DEC", 0x000006C, 0x00, 3, PutAll },
122 { "DEX", 0x0000001, 0xca, 0, PutAll },
123 { "DEY", 0x0000001, 0x88, 0, PutAll },
124 { "EOR", 0x080A26C, 0x40, 0, PutAll },
125 { "INC", 0x000006c, 0x00, 4, PutAll },
126 { "INX", 0x0000001, 0xe8, 0, PutAll },
127 { "INY", 0x0000001, 0xc8, 0, PutAll },
128 { "JMP", 0x0000808, 0x4c, 6, PutJMP },
129 { "JSR", 0x0000008, 0x20, 7, PutAll },
130 { "LDA", 0x080A26C, 0xa0, 0, PutAll },
131 { "LDX", 0x080030C, 0xa2, 1, PutAll },
132 { "LDY", 0x080006C, 0xa0, 1, PutAll },
133 { "LSR", 0x000006F, 0x42, 1, PutAll },
134 { "NOP", 0x0000001, 0xea, 0, PutAll },
135 { "ORA", 0x080A26C, 0x00, 0, PutAll },
136 { "PHA", 0x0000001, 0x48, 0, PutAll },
137 { "PHP", 0x0000001, 0x08, 0, PutAll },
138 { "PLA", 0x0000001, 0x68, 0, PutAll },
139 { "PLP", 0x0000001, 0x28, 0, PutAll },
140 { "ROL", 0x000006F, 0x22, 1, PutAll },
141 { "ROR", 0x000006F, 0x62, 1, PutAll },
142 { "RTI", 0x0000001, 0x40, 0, PutAll },
143 { "RTS", 0x0000001, 0x60, 0, PutAll },
144 { "SBC", 0x080A26C, 0xe0, 0, PutAll },
145 { "SEC", 0x0000001, 0x38, 0, PutAll },
146 { "SED", 0x0000001, 0xf8, 0, PutAll },
147 { "SEI", 0x0000001, 0x78, 0, PutAll },
148 { "STA", 0x000A26C, 0x80, 0, PutAll },
149 { "STX", 0x000010c, 0x82, 1, PutAll },
150 { "STY", 0x000002c, 0x80, 1, PutAll },
151 { "TAX", 0x0000001, 0xaa, 0, PutAll },
152 { "TAY", 0x0000001, 0xa8, 0, PutAll },
153 { "TSX", 0x0000001, 0xba, 0, PutAll },
154 { "TXA", 0x0000001, 0x8a, 0, PutAll },
155 { "TXS", 0x0000001, 0x9a, 0, PutAll },
156 { "TYA", 0x0000001, 0x98, 0, PutAll }
160 /* Instruction table for the 6502 with illegal instructions */
161 #define INS_COUNT_6502X 70
162 static const struct {
164 InsDesc Ins[INS_COUNT_6502X];
168 { "ADC", 0x080A26C, 0x60, 0, PutAll },
169 { "ALR", 0x0800000, 0x4B, 0, PutAll }, /* X */
170 { "ANC", 0x0800000, 0x0B, 0, PutAll }, /* X */
171 { "AND", 0x080A26C, 0x20, 0, PutAll },
172 { "ARR", 0x0800000, 0x6B, 0, PutAll }, /* X */
173 { "ASL", 0x000006e, 0x02, 1, PutAll },
174 { "AXS", 0x0800000, 0xCB, 0, PutAll }, /* X */
175 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
176 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
177 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
178 { "BIT", 0x000000C, 0x00, 2, PutAll },
179 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
180 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
181 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
182 { "BRK", 0x0000001, 0x00, 0, PutAll },
183 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
184 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
185 { "CLC", 0x0000001, 0x18, 0, PutAll },
186 { "CLD", 0x0000001, 0xd8, 0, PutAll },
187 { "CLI", 0x0000001, 0x58, 0, PutAll },
188 { "CLV", 0x0000001, 0xb8, 0, PutAll },
189 { "CMP", 0x080A26C, 0xc0, 0, PutAll },
190 { "CPX", 0x080000C, 0xe0, 1, PutAll },
191 { "CPY", 0x080000C, 0xc0, 1, PutAll },
192 { "DCP", 0x000A26C, 0xC3, 0, PutAll }, /* X */
193 { "DEC", 0x000006C, 0x00, 3, PutAll },
194 { "DEX", 0x0000001, 0xca, 0, PutAll },
195 { "DEY", 0x0000001, 0x88, 0, PutAll },
196 { "EOR", 0x080A26C, 0x40, 0, PutAll },
197 { "INC", 0x000006c, 0x00, 4, PutAll },
198 { "INX", 0x0000001, 0xe8, 0, PutAll },
199 { "INY", 0x0000001, 0xc8, 0, PutAll },
200 { "ISC", 0x000A26C, 0xE3, 0, PutAll }, /* X */
201 { "JAM", 0x0000001, 0x02, 0, PutAll }, /* X */
202 { "JMP", 0x0000808, 0x4c, 6, PutJMP },
203 { "JSR", 0x0000008, 0x20, 7, PutAll },
204 { "LAS", 0x0000200, 0xBB, 0, PutAll }, /* X */
205 { "LAX", 0x000A30C, 0xA3, 1, PutAll }, /* X */
206 { "LDA", 0x080A26C, 0xa0, 0, PutAll },
207 { "LDX", 0x080030C, 0xa2, 1, PutAll },
208 { "LDY", 0x080006C, 0xa0, 1, PutAll },
209 { "LSR", 0x000006F, 0x42, 1, PutAll },
210 { "NOP", 0x0000001, 0xea, 0, PutAll },
211 { "ORA", 0x080A26C, 0x00, 0, PutAll },
212 { "PHA", 0x0000001, 0x48, 0, PutAll },
213 { "PHP", 0x0000001, 0x08, 0, PutAll },
214 { "PLA", 0x0000001, 0x68, 0, PutAll },
215 { "PLP", 0x0000001, 0x28, 0, PutAll },
216 { "RLA", 0x000A26C, 0x23, 0, PutAll }, /* X */
217 { "ROL", 0x000006F, 0x22, 1, PutAll },
218 { "ROR", 0x000006F, 0x62, 1, PutAll },
219 { "RRA", 0x000A26C, 0x63, 0, PutAll }, /* X */
220 { "RTI", 0x0000001, 0x40, 0, PutAll },
221 { "RTS", 0x0000001, 0x60, 0, PutAll },
222 { "SAX", 0x000810C, 0x83, 1, PutAll }, /* X */
223 { "SBC", 0x080A26C, 0xe0, 0, PutAll },
224 { "SEC", 0x0000001, 0x38, 0, PutAll },
225 { "SED", 0x0000001, 0xf8, 0, PutAll },
226 { "SEI", 0x0000001, 0x78, 0, PutAll },
227 { "SLO", 0x000A26C, 0x03, 0, PutAll }, /* X */
228 { "SRE", 0x000A26C, 0x43, 0, PutAll }, /* X */
229 { "STA", 0x000A26C, 0x80, 0, PutAll },
230 { "STX", 0x000010c, 0x82, 1, PutAll },
231 { "STY", 0x000002c, 0x80, 1, PutAll },
232 { "TAX", 0x0000001, 0xaa, 0, PutAll },
233 { "TAY", 0x0000001, 0xa8, 0, PutAll },
234 { "TSX", 0x0000001, 0xba, 0, PutAll },
235 { "TXA", 0x0000001, 0x8a, 0, PutAll },
236 { "TXS", 0x0000001, 0x9a, 0, PutAll },
237 { "TYA", 0x0000001, 0x98, 0, PutAll }
241 /* Instruction table for the 65SC02 */
242 #define INS_COUNT_65SC02 66
243 static const struct {
245 InsDesc Ins[INS_COUNT_65SC02];
249 { "ADC", 0x080A66C, 0x60, 0, PutAll },
250 { "AND", 0x080A66C, 0x20, 0, PutAll },
251 { "ASL", 0x000006e, 0x02, 1, PutAll },
252 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
253 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
254 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
255 { "BIT", 0x0A0006C, 0x00, 2, PutAll },
256 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
257 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
258 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
259 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
260 { "BRK", 0x0000001, 0x00, 0, PutAll },
261 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
262 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
263 { "CLC", 0x0000001, 0x18, 0, PutAll },
264 { "CLD", 0x0000001, 0xd8, 0, PutAll },
265 { "CLI", 0x0000001, 0x58, 0, PutAll },
266 { "CLV", 0x0000001, 0xb8, 0, PutAll },
267 { "CMP", 0x080A66C, 0xc0, 0, PutAll },
268 { "CPX", 0x080000C, 0xe0, 1, PutAll },
269 { "CPY", 0x080000C, 0xc0, 1, PutAll },
270 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
271 { "DEC", 0x000006F, 0x00, 3, PutAll },
272 { "DEX", 0x0000001, 0xca, 0, PutAll },
273 { "DEY", 0x0000001, 0x88, 0, PutAll },
274 { "EOR", 0x080A66C, 0x40, 0, PutAll },
275 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
276 { "INC", 0x000006f, 0x00, 4, PutAll },
277 { "INX", 0x0000001, 0xe8, 0, PutAll },
278 { "INY", 0x0000001, 0xc8, 0, PutAll },
279 { "JMP", 0x0010808, 0x4c, 6, PutAll },
280 { "JSR", 0x0000008, 0x20, 7, PutAll },
281 { "LDA", 0x080A66C, 0xa0, 0, PutAll },
282 { "LDX", 0x080030C, 0xa2, 1, PutAll },
283 { "LDY", 0x080006C, 0xa0, 1, PutAll },
284 { "LSR", 0x000006F, 0x42, 1, PutAll },
285 { "NOP", 0x0000001, 0xea, 0, PutAll },
286 { "ORA", 0x080A66C, 0x00, 0, PutAll },
287 { "PHA", 0x0000001, 0x48, 0, PutAll },
288 { "PHP", 0x0000001, 0x08, 0, PutAll },
289 { "PHX", 0x0000001, 0xda, 0, PutAll },
290 { "PHY", 0x0000001, 0x5a, 0, PutAll },
291 { "PLA", 0x0000001, 0x68, 0, PutAll },
292 { "PLP", 0x0000001, 0x28, 0, PutAll },
293 { "PLX", 0x0000001, 0xfa, 0, PutAll },
294 { "PLY", 0x0000001, 0x7a, 0, PutAll },
295 { "ROL", 0x000006F, 0x22, 1, PutAll },
296 { "ROR", 0x000006F, 0x62, 1, PutAll },
297 { "RTI", 0x0000001, 0x40, 0, PutAll },
298 { "RTS", 0x0000001, 0x60, 0, PutAll },
299 { "SBC", 0x080A66C, 0xe0, 0, PutAll },
300 { "SEC", 0x0000001, 0x38, 0, PutAll },
301 { "SED", 0x0000001, 0xf8, 0, PutAll },
302 { "SEI", 0x0000001, 0x78, 0, PutAll },
303 { "STA", 0x000A66C, 0x80, 0, PutAll },
304 { "STX", 0x000010c, 0x82, 1, PutAll },
305 { "STY", 0x000002c, 0x80, 1, PutAll },
306 { "STZ", 0x000006c, 0x04, 5, PutAll },
307 { "TAX", 0x0000001, 0xaa, 0, PutAll },
308 { "TAY", 0x0000001, 0xa8, 0, PutAll },
309 { "TRB", 0x000000c, 0x10, 1, PutAll },
310 { "TSB", 0x000000c, 0x00, 1, PutAll },
311 { "TSX", 0x0000001, 0xba, 0, PutAll },
312 { "TXA", 0x0000001, 0x8a, 0, PutAll },
313 { "TXS", 0x0000001, 0x9a, 0, PutAll },
314 { "TYA", 0x0000001, 0x98, 0, PutAll }
318 /* Instruction table for the 65C02 */
319 #define INS_COUNT_65C02 98
320 static const struct {
322 InsDesc Ins[INS_COUNT_65C02];
326 { "ADC", 0x080A66C, 0x60, 0, PutAll },
327 { "AND", 0x080A66C, 0x20, 0, PutAll },
328 { "ASL", 0x000006e, 0x02, 1, PutAll },
329 { "BBR0", 0x0000000, 0x0F, 0, PutBitBranch },
330 { "BBR1", 0x0000000, 0x1F, 0, PutBitBranch },
331 { "BBR2", 0x0000000, 0x2F, 0, PutBitBranch },
332 { "BBR3", 0x0000000, 0x3F, 0, PutBitBranch },
333 { "BBR4", 0x0000000, 0x4F, 0, PutBitBranch },
334 { "BBR5", 0x0000000, 0x5F, 0, PutBitBranch },
335 { "BBR6", 0x0000000, 0x6F, 0, PutBitBranch },
336 { "BBR7", 0x0000000, 0x7F, 0, PutBitBranch },
337 { "BBS0", 0x0000000, 0x8F, 0, PutBitBranch },
338 { "BBS1", 0x0000000, 0x9F, 0, PutBitBranch },
339 { "BBS2", 0x0000000, 0xAF, 0, PutBitBranch },
340 { "BBS3", 0x0000000, 0xBF, 0, PutBitBranch },
341 { "BBS4", 0x0000000, 0xCF, 0, PutBitBranch },
342 { "BBS5", 0x0000000, 0xDF, 0, PutBitBranch },
343 { "BBS6", 0x0000000, 0xEF, 0, PutBitBranch },
344 { "BBS7", 0x0000000, 0xFF, 0, PutBitBranch },
345 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
346 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
347 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
348 { "BIT", 0x0A0006C, 0x00, 2, PutAll },
349 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
350 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
351 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
352 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
353 { "BRK", 0x0000001, 0x00, 0, PutAll },
354 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
355 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
356 { "CLC", 0x0000001, 0x18, 0, PutAll },
357 { "CLD", 0x0000001, 0xd8, 0, PutAll },
358 { "CLI", 0x0000001, 0x58, 0, PutAll },
359 { "CLV", 0x0000001, 0xb8, 0, PutAll },
360 { "CMP", 0x080A66C, 0xc0, 0, PutAll },
361 { "CPX", 0x080000C, 0xe0, 1, PutAll },
362 { "CPY", 0x080000C, 0xc0, 1, PutAll },
363 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
364 { "DEC", 0x000006F, 0x00, 3, PutAll },
365 { "DEX", 0x0000001, 0xca, 0, PutAll },
366 { "DEY", 0x0000001, 0x88, 0, PutAll },
367 { "EOR", 0x080A66C, 0x40, 0, PutAll },
368 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
369 { "INC", 0x000006f, 0x00, 4, PutAll },
370 { "INX", 0x0000001, 0xe8, 0, PutAll },
371 { "INY", 0x0000001, 0xc8, 0, PutAll },
372 { "JMP", 0x0010808, 0x4c, 6, PutAll },
373 { "JSR", 0x0000008, 0x20, 7, PutAll },
374 { "LDA", 0x080A66C, 0xa0, 0, PutAll },
375 { "LDX", 0x080030C, 0xa2, 1, PutAll },
376 { "LDY", 0x080006C, 0xa0, 1, PutAll },
377 { "LSR", 0x000006F, 0x42, 1, PutAll },
378 { "NOP", 0x0000001, 0xea, 0, PutAll },
379 { "ORA", 0x080A66C, 0x00, 0, PutAll },
380 { "PHA", 0x0000001, 0x48, 0, PutAll },
381 { "PHP", 0x0000001, 0x08, 0, PutAll },
382 { "PHX", 0x0000001, 0xda, 0, PutAll },
383 { "PHY", 0x0000001, 0x5a, 0, PutAll },
384 { "PLA", 0x0000001, 0x68, 0, PutAll },
385 { "PLP", 0x0000001, 0x28, 0, PutAll },
386 { "PLX", 0x0000001, 0xfa, 0, PutAll },
387 { "PLY", 0x0000001, 0x7a, 0, PutAll },
388 { "RMB0", 0x0000004, 0x07, 1, PutAll },
389 { "RMB1", 0x0000004, 0x17, 1, PutAll },
390 { "RMB2", 0x0000004, 0x27, 1, PutAll },
391 { "RMB3", 0x0000004, 0x37, 1, PutAll },
392 { "RMB4", 0x0000004, 0x47, 1, PutAll },
393 { "RMB5", 0x0000004, 0x57, 1, PutAll },
394 { "RMB6", 0x0000004, 0x67, 1, PutAll },
395 { "RMB7", 0x0000004, 0x77, 1, PutAll },
396 { "ROL", 0x000006F, 0x22, 1, PutAll },
397 { "ROR", 0x000006F, 0x62, 1, PutAll },
398 { "RTI", 0x0000001, 0x40, 0, PutAll },
399 { "RTS", 0x0000001, 0x60, 0, PutAll },
400 { "SBC", 0x080A66C, 0xe0, 0, PutAll },
401 { "SEC", 0x0000001, 0x38, 0, PutAll },
402 { "SED", 0x0000001, 0xf8, 0, PutAll },
403 { "SEI", 0x0000001, 0x78, 0, PutAll },
404 { "SMB0", 0x0000004, 0x87, 1, PutAll },
405 { "SMB1", 0x0000004, 0x97, 1, PutAll },
406 { "SMB2", 0x0000004, 0xA7, 1, PutAll },
407 { "SMB3", 0x0000004, 0xB7, 1, PutAll },
408 { "SMB4", 0x0000004, 0xC7, 1, PutAll },
409 { "SMB5", 0x0000004, 0xD7, 1, PutAll },
410 { "SMB6", 0x0000004, 0xE7, 1, PutAll },
411 { "SMB7", 0x0000004, 0xF7, 1, PutAll },
412 { "STA", 0x000A66C, 0x80, 0, PutAll },
413 { "STX", 0x000010c, 0x82, 1, PutAll },
414 { "STY", 0x000002c, 0x80, 1, PutAll },
415 { "STZ", 0x000006c, 0x04, 5, PutAll },
416 { "TAX", 0x0000001, 0xaa, 0, PutAll },
417 { "TAY", 0x0000001, 0xa8, 0, PutAll },
418 { "TRB", 0x000000c, 0x10, 1, PutAll },
419 { "TSB", 0x000000c, 0x00, 1, PutAll },
420 { "TSX", 0x0000001, 0xba, 0, PutAll },
421 { "TXA", 0x0000001, 0x8a, 0, PutAll },
422 { "TXS", 0x0000001, 0x9a, 0, PutAll },
423 { "TYA", 0x0000001, 0x98, 0, PutAll }
427 /* Instruction table for the 65816 */
428 #define INS_COUNT_65816 101
429 static const struct {
431 InsDesc Ins[INS_COUNT_65816];
435 { "ADC", 0x0b8f6fc, 0x60, 0, PutAll },
436 { "AND", 0x0b8f6fc, 0x20, 0, PutAll },
437 { "ASL", 0x000006e, 0x02, 1, PutAll },
438 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
439 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
440 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
441 { "BGE", 0x0020000, 0xb0, 0, PutPCRel8 }, /* == BCS */
442 { "BIT", 0x0a0006c, 0x00, 2, PutAll },
443 { "BLT", 0x0020000, 0x90, 0, PutPCRel8 }, /* == BCC */
444 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
445 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
446 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
447 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
448 { "BRK", 0x0000001, 0x00, 0, PutAll },
449 { "BRL", 0x0040000, 0x82, 0, PutPCRel16 },
450 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
451 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
452 { "CLC", 0x0000001, 0x18, 0, PutAll },
453 { "CLD", 0x0000001, 0xd8, 0, PutAll },
454 { "CLI", 0x0000001, 0x58, 0, PutAll },
455 { "CLV", 0x0000001, 0xb8, 0, PutAll },
456 { "CMP", 0x0b8f6fc, 0xc0, 0, PutAll },
457 { "COP", 0x0000004, 0x02, 6, PutAll },
458 { "CPA", 0x0b8f6fc, 0xc0, 0, PutAll }, /* == CMP */
459 { "CPX", 0x0c0000c, 0xe0, 1, PutAll },
460 { "CPY", 0x0c0000c, 0xc0, 1, PutAll },
461 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
462 { "DEC", 0x000006F, 0x00, 3, PutAll },
463 { "DEX", 0x0000001, 0xca, 0, PutAll },
464 { "DEY", 0x0000001, 0x88, 0, PutAll },
465 { "EOR", 0x0b8f6fc, 0x40, 0, PutAll },
466 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
467 { "INC", 0x000006F, 0x00, 4, PutAll },
468 { "INX", 0x0000001, 0xe8, 0, PutAll },
469 { "INY", 0x0000001, 0xc8, 0, PutAll },
470 { "JML", 0x0000810, 0x5c, 1, PutAll },
471 { "JMP", 0x0010818, 0x4c, 6, PutAll },
472 { "JSL", 0x0000010, 0x20, 7, PutAll },
473 { "JSR", 0x0010018, 0x20, 7, PutAll },
474 { "LDA", 0x0b8f6fc, 0xa0, 0, PutAll },
475 { "LDX", 0x0c0030c, 0xa2, 1, PutAll },
476 { "LDY", 0x0c0006c, 0xa0, 1, PutAll },
477 { "LSR", 0x000006F, 0x42, 1, PutAll },
478 { "MVN", 0x1000000, 0x54, 0, PutBlockMove },
479 { "MVP", 0x1000000, 0x44, 0, PutBlockMove },
480 { "NOP", 0x0000001, 0xea, 0, PutAll },
481 { "ORA", 0x0b8f6fc, 0x00, 0, PutAll },
482 { "PEA", 0x0000008, 0xf4, 6, PutAll },
483 { "PEI", 0x0000400, 0xd4, 1, PutAll },
484 { "PER", 0x0040000, 0x62, 0, PutPCRel16 },
485 { "PHA", 0x0000001, 0x48, 0, PutAll },
486 { "PHB", 0x0000001, 0x8b, 0, PutAll },
487 { "PHD", 0x0000001, 0x0b, 0, PutAll },
488 { "PHK", 0x0000001, 0x4b, 0, PutAll },
489 { "PHP", 0x0000001, 0x08, 0, PutAll },
490 { "PHX", 0x0000001, 0xda, 0, PutAll },
491 { "PHY", 0x0000001, 0x5a, 0, PutAll },
492 { "PLA", 0x0000001, 0x68, 0, PutAll },
493 { "PLB", 0x0000001, 0xab, 0, PutAll },
494 { "PLD", 0x0000001, 0x2b, 0, PutAll },
495 { "PLP", 0x0000001, 0x28, 0, PutAll },
496 { "PLX", 0x0000001, 0xfa, 0, PutAll },
497 { "PLY", 0x0000001, 0x7a, 0, PutAll },
498 { "REP", 0x0800000, 0xc2, 1, PutREP },
499 { "ROL", 0x000006F, 0x22, 1, PutAll },
500 { "ROR", 0x000006F, 0x62, 1, PutAll },
501 { "RTI", 0x0000001, 0x40, 0, PutAll },
502 { "RTL", 0x0000001, 0x6b, 0, PutAll },
503 { "RTS", 0x0000001, 0x60, 0, PutRTS },
504 { "SBC", 0x0b8f6fc, 0xe0, 0, PutAll },
505 { "SEC", 0x0000001, 0x38, 0, PutAll },
506 { "SED", 0x0000001, 0xf8, 0, PutAll },
507 { "SEI", 0x0000001, 0x78, 0, PutAll },
508 { "SEP", 0x0800000, 0xe2, 1, PutSEP },
509 { "STA", 0x018f6fc, 0x80, 0, PutAll },
510 { "STP", 0x0000001, 0xdb, 0, PutAll },
511 { "STX", 0x000010c, 0x82, 1, PutAll },
512 { "STY", 0x000002c, 0x80, 1, PutAll },
513 { "STZ", 0x000006c, 0x04, 5, PutAll },
514 { "SWA", 0x0000001, 0xeb, 0, PutAll }, /* == XBA */
515 { "TAD", 0x0000001, 0x5b, 0, PutAll }, /* == TCD */
516 { "TAS", 0x0000001, 0x1b, 0, PutAll }, /* == TCS */
517 { "TAX", 0x0000001, 0xaa, 0, PutAll },
518 { "TAY", 0x0000001, 0xa8, 0, PutAll },
519 { "TCD", 0x0000001, 0x5b, 0, PutAll },
520 { "TCS", 0x0000001, 0x1b, 0, PutAll },
521 { "TDA", 0x0000001, 0x7b, 0, PutAll }, /* == TDC */
522 { "TDC", 0x0000001, 0x7b, 0, PutAll },
523 { "TRB", 0x000000c, 0x10, 1, PutAll },
524 { "TSA", 0x0000001, 0x3b, 0, PutAll }, /* == TSC */
525 { "TSB", 0x000000c, 0x00, 1, PutAll },
526 { "TSC", 0x0000001, 0x3b, 0, PutAll },
527 { "TSX", 0x0000001, 0xba, 0, PutAll },
528 { "TXA", 0x0000001, 0x8a, 0, PutAll },
529 { "TXS", 0x0000001, 0x9a, 0, PutAll },
530 { "TXY", 0x0000001, 0x9b, 0, PutAll },
531 { "TYA", 0x0000001, 0x98, 0, PutAll },
532 { "TYX", 0x0000001, 0xbb, 0, PutAll },
533 { "WAI", 0x0000001, 0xcb, 0, PutAll },
534 { "XBA", 0x0000001, 0xeb, 0, PutAll },
535 { "XCE", 0x0000001, 0xfb, 0, PutAll }
540 /* Table for the SUNPLUS CPU */
541 #include "sunplus.inc"
544 /* Instruction table for the SWEET16 pseudo CPU */
545 #define INS_COUNT_SWEET16 27
546 static const struct {
548 InsDesc Ins[INS_COUNT_SWEET16];
552 { "ADD", AMSW16_REG, 0xA0, 0, PutSweet16 },
553 { "BC", AMSW16_BRA, 0x03, 0, PutSweet16Branch },
554 { "BK", AMSW16_IMP, 0x0A, 0, PutSweet16 },
555 { "BM", AMSW16_BRA, 0x05, 0, PutSweet16Branch },
556 { "BM1", AMSW16_BRA, 0x08, 0, PutSweet16Branch },
557 { "BNC", AMSW16_BRA, 0x02, 0, PutSweet16Branch },
558 { "BNM1", AMSW16_BRA, 0x09, 0, PutSweet16Branch },
559 { "BNZ", AMSW16_BRA, 0x07, 0, PutSweet16Branch },
560 { "BP", AMSW16_BRA, 0x04, 0, PutSweet16Branch },
561 { "BR", AMSW16_BRA, 0x01, 0, PutSweet16Branch },
562 { "BS", AMSW16_BRA, 0x0B, 0, PutSweet16Branch },
563 { "BZ", AMSW16_BRA, 0x06, 0, PutSweet16Branch },
564 { "CPR", AMSW16_REG, 0xD0, 0, PutSweet16 },
565 { "DCR", AMSW16_REG, 0xF0, 0, PutSweet16 },
566 { "INR", AMSW16_REG, 0xE0, 0, PutSweet16 },
567 { "LD", AMSW16_REG | AMSW16_IND, 0x00, 1, PutSweet16 },
568 { "LDD", AMSW16_IND, 0x60, 0, PutSweet16 },
569 { "POP", AMSW16_IND, 0x80, 0, PutSweet16 },
570 { "POPD", AMSW16_IND, 0xC0, 0, PutSweet16 },
571 { "RS", AMSW16_IMP, 0x0B, 0, PutSweet16 },
572 { "RTN", AMSW16_IMP, 0x00, 0, PutSweet16 },
573 { "SET", AMSW16_IMM, 0x10, 0, PutSweet16 },
574 { "ST", AMSW16_REG | AMSW16_IND, 0x10, 1, PutSweet16 },
575 { "STD", AMSW16_IND, 0x70, 0, PutSweet16 },
576 { "STP", AMSW16_IND, 0x90, 0, PutSweet16 },
577 { "SUB", AMSW16_IMM, 0xB0, 0, PutSweet16 },
583 /* An array with instruction tables */
584 static const InsTable* InsTabs[CPU_COUNT] = {
585 (const InsTable*) &InsTabNone,
586 (const InsTable*) &InsTab6502,
587 (const InsTable*) &InsTab6502X,
588 (const InsTable*) &InsTab65SC02,
589 (const InsTable*) &InsTab65C02,
590 (const InsTable*) &InsTab65816,
592 (const InsTable*) &InsTabSunPlus,
596 (const InsTable*) &InsTabSweet16,
598 const InsTable* InsTab = (const InsTable*) &InsTab6502;
600 /* Table to build the effective 65xx opcode from a base opcode and an
603 static unsigned char EATab[9][AM65I_COUNT] = {
605 0x00, 0x00, 0x05, 0x0D, 0x0F, 0x15, 0x1D, 0x1F,
606 0x00, 0x19, 0x12, 0x00, 0x07, 0x11, 0x17, 0x01,
607 0x00, 0x00, 0x00, 0x03, 0x13, 0x09, 0x00, 0x09,
611 0x08, 0x08, 0x04, 0x0C, 0x00, 0x14, 0x1C, 0x00,
612 0x14, 0x1C, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00,
613 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
617 0x00, 0x00, 0x24, 0x2C, 0x0F, 0x34, 0x3C, 0x00,
618 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
619 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00,
623 0x3A, 0x3A, 0xC6, 0xCE, 0x00, 0xD6, 0xDE, 0x00,
624 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
625 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
629 0x1A, 0x1A, 0xE6, 0xEE, 0x00, 0xF6, 0xFE, 0x00,
630 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
631 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
635 0x00, 0x00, 0x60, 0x98, 0x00, 0x70, 0x9E, 0x00,
636 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
637 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
641 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
642 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
643 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
647 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
648 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
649 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
653 0x00, 0x40, 0x01, 0x41, 0x00, 0x09, 0x49, 0x00,
654 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00,
655 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
660 /* Table to build the effective SWEET16 opcode from a base opcode and an
663 static unsigned char Sweet16EATab[2][AMSW16I_COUNT] = {
665 0x00, 0x00, 0x00, 0x00, 0x00,
668 0x00, 0x00, 0x00, 0x40, 0x20,
672 /* Table that encodes the additional bytes for each 65xx instruction */
673 unsigned char ExtBytes[AM65I_COUNT] = {
678 3, /* Absolute long */
681 3, /* Absolute long,X */
690 2, /* (Absolute,X) */
691 1, /* Relative short */
692 2, /* Relative long */
695 1, /* Immidiate accu */
696 1, /* Immidiate index */
697 1, /* Immidiate byte */
701 /* Table that encodes the additional bytes for each SWEET16 instruction */
702 static unsigned char Sweet16ExtBytes[AMSW16I_COUNT] = {
712 /*****************************************************************************/
713 /* Handler functions for 6502 derivates */
714 /*****************************************************************************/
718 static int EvalEA (const InsDesc* Ins, EffAddr* A)
719 /* Evaluate the effective address. All fields in A will be valid after calling
720 * this function. The function returns true on success and false on errors.
723 /* Get the set of possible addressing modes */
726 /* From the possible addressing modes, remove the ones that are invalid
727 * for this instruction or CPU.
729 A->AddrModeSet &= Ins->AddrMode;
731 /* If we have an expression, check it and remove any addressing modes that
732 * are too small for the expression size. Since we have to study the
733 * expression anyway, do also replace it by a simpler one if possible.
739 /* Study the expression */
740 StudyExpr (A->Expr, &ED);
742 /* Simplify it if possible */
743 A->Expr = SimplifyExpr (A->Expr, &ED);
745 /* If we don't know how big the expression is, assume the default
746 * address size for data.
748 if (ED.AddrSize == ADDR_SIZE_DEFAULT) {
749 ED.AddrSize = DataAddrSize;
753 switch (ED.AddrSize) {
756 A->AddrModeSet &= ~AM65_SET_ZP;
760 A->AddrModeSet &= ~(AM65_SET_ZP | AM65_SET_ABS);
764 /* Free any resource associated with the expression desc */
768 /* Check if we have any adressing modes left */
769 if (A->AddrModeSet == 0) {
770 Error ("Illegal addressing mode");
773 A->AddrMode = BitFind (A->AddrModeSet);
774 A->AddrModeBit = (0x01UL << A->AddrMode);
776 /* If the instruction has a one byte operand and immediate addressing is
777 * allowed but not used, check for an operand expression in the form
778 * <label or >label, where label is a far or absolute label. If found,
779 * emit a warning. This warning protects against a typo, where the '#'
780 * for the immediate operand is omitted.
782 if (A->Expr && (Ins->AddrMode & AM65_IMM) &&
783 (A->AddrModeSet & (AM65_DIR | AM65_ABS | AM65_ABS_LONG)) &&
784 ExtBytes[A->AddrMode] == 1) {
786 /* Found, check the expression */
787 ExprNode* Left = A->Expr->Left;
788 if ((A->Expr->Op == EXPR_BYTE0 || A->Expr->Op == EXPR_BYTE1) &&
789 Left->Op == EXPR_SYMBOL &&
790 GetSymAddrSize (Left->V.Sym) != ADDR_SIZE_ZP) {
792 /* Output a warning */
793 Warning (1, "Suspicious address expression");
797 /* Build the opcode */
798 A->Opcode = Ins->BaseCode | EATab[Ins->ExtCode][A->AddrMode];
806 static void EmitCode (EffAddr* A)
807 /* Output code for the data in A */
809 /* Check how many extension bytes are needed and output the instruction */
810 switch (ExtBytes[A->AddrMode]) {
817 Emit1 (A->Opcode, A->Expr);
821 if (CPU == CPU_65816 && (A->AddrModeBit & (AM65_ABS | AM65_ABS_X | AM65_ABS_Y))) {
822 /* This is a 16 bit mode that uses an address. If in 65816,
823 * mode, force this address into 16 bit range to allow
824 * addressing inside a 64K segment.
826 Emit2 (A->Opcode, GenWordExpr (A->Expr));
828 Emit2 (A->Opcode, A->Expr);
834 Emit3 (A->Opcode, A->Expr);
838 Internal ("Invalid operand byte count: %u", ExtBytes[A->AddrMode]);
845 static long PutImmed8 (const InsDesc* Ins)
846 /* Parse and emit an immediate 8 bit instruction. Return the value of the
847 * operand if it's available and const.
853 /* Evaluate the addressing mode */
854 if (EvalEA (Ins, &A) == 0) {
855 /* An error occurred */
859 /* If we have an expression and it's const, get it's value */
861 (void) IsConstExpr (A.Expr, &Val);
864 /* Check how many extension bytes are needed and output the instruction */
865 switch (ExtBytes[A.AddrMode]) {
868 Emit1 (A.Opcode, A.Expr);
872 Internal ("Invalid operand byte count: %u", ExtBytes[A.AddrMode]);
875 /* Return the expression value */
881 static void PutPCRel8 (const InsDesc* Ins)
882 /* Handle branches with a 8 bit distance */
884 EmitPCRel (Ins->BaseCode, GenBranchExpr (2), 1);
889 static void PutPCRel16 (const InsDesc* Ins)
890 /* Handle branches with an 16 bit distance and PER */
892 EmitPCRel (Ins->BaseCode, GenBranchExpr (3), 2);
897 static void PutBlockMove (const InsDesc* Ins)
898 /* Handle the blockmove instructions */
900 Emit0 (Ins->BaseCode);
901 EmitByte (Expression ());
903 EmitByte (Expression ());
908 static void PutBitBranch (const InsDesc* Ins)
909 /* Handle 65C02 branch on bit condition */
911 Emit0 (Ins->BaseCode);
912 EmitByte (Expression ());
914 EmitSigned (GenBranchExpr (1), 1);
919 static void PutREP (const InsDesc* Ins)
920 /* Emit a REP instruction, track register sizes */
922 /* Use the generic handler */
923 long Val = PutImmed8 (Ins);
925 /* We track the status only for the 816 CPU and in smart mode */
926 if (CPU == CPU_65816 && SmartMode) {
928 /* Check the range for Val. */
930 /* We had an error */
931 Warning (1, "Cannot track processor status byte");
934 /* Index registers to 16 bit */
935 ExtBytes[AM65I_IMM_INDEX] = 2;
939 ExtBytes[AM65I_IMM_ACCU] = 2;
947 static void PutSEP (const InsDesc* Ins)
948 /* Emit a SEP instruction, track register sizes */
950 /* Use the generic handler */
951 long Val = PutImmed8 (Ins);
953 /* We track the status only for the 816 CPU and in smart mode */
954 if (CPU == CPU_65816 && SmartMode) {
956 /* Check the range for Val. */
958 /* We had an error */
959 Warning (1, "Cannot track processor status byte");
962 /* Index registers to 8 bit */
963 ExtBytes[AM65I_IMM_INDEX] = 1;
967 ExtBytes[AM65I_IMM_ACCU] = 1;
975 static void PutJMP (const InsDesc* Ins)
976 /* Handle the jump instruction for the 6502. Problem is that these chips have
977 * a bug: If the address crosses a page, the upper byte gets not corrected and
978 * the instruction will fail. The PutJmp function will add a linker assertion
979 * to check for this case and is otherwise identical to PutAll.
984 /* Evaluate the addressing mode used */
985 if (EvalEA (Ins, &A)) {
987 /* Check for indirect addressing */
988 if (A.AddrModeBit & AM65_ABS_IND) {
990 /* Compare the low byte of the expression to 0xFF to check for
991 * a page cross. Be sure to use a copy of the expression otherwise
992 * things will go weird later.
994 ExprNode* E = GenNE (GenByteExpr (CloneExpr (A.Expr)), 0xFF);
996 /* Generate the message */
997 unsigned Msg = GetStringId ("\"jmp (abs)\" across page border");
999 /* Generate the assertion */
1000 AddAssertion (E, ASSERT_ACT_WARN, Msg);
1003 /* No error, output code */
1010 static void PutRTS (const InsDesc* Ins attribute ((unused)))
1011 /* Handle the RTS instruction for the 816. In smart mode emit a RTL opcode if
1012 * the enclosing scope is FAR.
1015 if (SmartMode && CurrentScope->AddrSize == ADDR_SIZE_FAR) {
1016 Emit0 (0x6B); /* RTL */
1018 Emit0 (0x60); /* RTS */
1024 static void PutAll (const InsDesc* Ins)
1025 /* Handle all other instructions */
1029 /* Evaluate the addressing mode used */
1030 if (EvalEA (Ins, &A)) {
1031 /* No error, output code */
1038 /*****************************************************************************/
1039 /* Handler functions for SWEET16 */
1040 /*****************************************************************************/
1044 static void PutSweet16 (const InsDesc* Ins)
1045 /* Handle a generic sweet16 instruction */
1049 /* Evaluate the addressing mode used */
1052 /* From the possible addressing modes, remove the ones that are invalid
1053 * for this instruction or CPU.
1055 A.AddrModeSet &= Ins->AddrMode;
1057 /* Check if we have any adressing modes left */
1058 if (A.AddrModeSet == 0) {
1059 Error ("Illegal addressing mode");
1062 A.AddrMode = BitFind (A.AddrModeSet);
1063 A.AddrModeBit = (0x01UL << A.AddrMode);
1065 /* Build the opcode */
1066 A.Opcode = Ins->BaseCode | Sweet16EATab[Ins->ExtCode][A.AddrMode] | A.Reg;
1068 /* Check how many extension bytes are needed and output the instruction */
1069 switch (Sweet16ExtBytes[A.AddrMode]) {
1076 Emit1 (A.Opcode, A.Expr);
1080 Emit2 (A.Opcode, A.Expr);
1084 Internal ("Invalid operand byte count: %u", Sweet16ExtBytes[A.AddrMode]);
1091 static void PutSweet16Branch (const InsDesc* Ins)
1092 /* Handle a sweet16 branch instruction */
1094 EmitPCRel (Ins->BaseCode, GenBranchExpr (2), 1);
1099 /*****************************************************************************/
1101 /*****************************************************************************/
1105 static int CmpName (const void* Key, const void* Instr)
1106 /* Compare function for bsearch */
1108 return strcmp ((const char*)Key, ((const InsDesc*) Instr)->Mnemonic);
1113 void SetCPU (cpu_t NewCPU)
1116 /* Make sure the parameter is correct */
1117 CHECK (NewCPU < CPU_COUNT);
1119 /* Check if we have support for the new CPU, if so, use it */
1120 if (InsTabs[NewCPU]) {
1122 InsTab = InsTabs[CPU];
1124 Error ("CPU not supported");
1131 /* Return the current CPU */
1138 int FindInstruction (const char* Ident)
1139 /* Check if Ident is a valid mnemonic. If so, return the index in the
1140 * instruction table. If not, return -1.
1145 char Key[sizeof (ID->Mnemonic)];
1147 /* Shortcut for the "none" CPU: If there are no instructions to search
1148 * for, bail out early.
1150 if (InsTab->Count == 0) {
1155 /* Make a copy, and uppercase that copy */
1157 while (Ident[I] != '\0') {
1158 /* If the identifier is longer than the longest mnemonic, it cannot
1161 if (I >= sizeof (Key) - 1) {
1162 /* Not found, no need for further action */
1165 Key[I] = toupper ((unsigned char)Ident[I]);
1170 /* Search for the key */
1171 ID = bsearch (Key, InsTab->Ins, InsTab->Count, sizeof (InsDesc), CmpName);
1176 /* Found, return the entry */
1177 return ID - InsTab->Ins;
1183 void HandleInstruction (unsigned Index)
1184 /* Handle the mnemonic with the given index */
1187 PRECONDITION (Index < InsTab->Count);
1189 /* Skip the mnemonic token */
1192 /* Call the handler */
1193 InsTab->Ins[Index].Emit (&InsTab->Ins[Index]);