1 /*****************************************************************************/
5 /* Instruction encoding for the ca65 macroassembler */
9 /* (C) 1998-2003 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"
58 #include "studyexpr.h"
63 /*****************************************************************************/
65 /*****************************************************************************/
69 /* Forwards for handler functions */
70 static void PutPCRel8 (const InsDesc* Ins);
71 static void PutPCRel16 (const InsDesc* Ins);
72 static void PutBlockMove (const InsDesc* Ins);
73 static void PutBitBranch (const InsDesc* Ins);
74 static void PutREP (const InsDesc* Ins);
75 static void PutSEP (const InsDesc* Ins);
76 static void PutJMP (const InsDesc* Ins);
77 static void PutRTS (const InsDesc* Ins);
78 static void PutAll (const InsDesc* Ins);
82 /* Instruction table for the 6502 */
83 #define INS_COUNT_6502 56
86 InsDesc Ins[INS_COUNT_6502];
90 { "ADC", 0x080A26C, 0x60, 0, PutAll },
91 { "AND", 0x080A26C, 0x20, 0, PutAll },
92 { "ASL", 0x000006e, 0x02, 1, PutAll },
93 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
94 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
95 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
96 { "BIT", 0x000000C, 0x00, 2, PutAll },
97 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
98 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
99 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
100 { "BRK", 0x0000001, 0x00, 0, PutAll },
101 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
102 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
103 { "CLC", 0x0000001, 0x18, 0, PutAll },
104 { "CLD", 0x0000001, 0xd8, 0, PutAll },
105 { "CLI", 0x0000001, 0x58, 0, PutAll },
106 { "CLV", 0x0000001, 0xb8, 0, PutAll },
107 { "CMP", 0x080A26C, 0xc0, 0, PutAll },
108 { "CPX", 0x080000C, 0xe0, 1, PutAll },
109 { "CPY", 0x080000C, 0xc0, 1, PutAll },
110 { "DEC", 0x000006C, 0x00, 3, PutAll },
111 { "DEX", 0x0000001, 0xca, 0, PutAll },
112 { "DEY", 0x0000001, 0x88, 0, PutAll },
113 { "EOR", 0x080A26C, 0x40, 0, PutAll },
114 { "INC", 0x000006c, 0x00, 4, PutAll },
115 { "INX", 0x0000001, 0xe8, 0, PutAll },
116 { "INY", 0x0000001, 0xc8, 0, PutAll },
117 { "JMP", 0x0000808, 0x4c, 6, PutJMP },
118 { "JSR", 0x0000008, 0x20, 7, PutAll },
119 { "LDA", 0x080A26C, 0xa0, 0, PutAll },
120 { "LDX", 0x080030C, 0xa2, 1, PutAll },
121 { "LDY", 0x080006C, 0xa0, 1, PutAll },
122 { "LSR", 0x000006F, 0x42, 1, PutAll },
123 { "NOP", 0x0000001, 0xea, 0, PutAll },
124 { "ORA", 0x080A26C, 0x00, 0, PutAll },
125 { "PHA", 0x0000001, 0x48, 0, PutAll },
126 { "PHP", 0x0000001, 0x08, 0, PutAll },
127 { "PLA", 0x0000001, 0x68, 0, PutAll },
128 { "PLP", 0x0000001, 0x28, 0, PutAll },
129 { "ROL", 0x000006F, 0x22, 1, PutAll },
130 { "ROR", 0x000006F, 0x62, 1, PutAll },
131 { "RTI", 0x0000001, 0x40, 0, PutAll },
132 { "RTS", 0x0000001, 0x60, 0, PutAll },
133 { "SBC", 0x080A26C, 0xe0, 0, PutAll },
134 { "SEC", 0x0000001, 0x38, 0, PutAll },
135 { "SED", 0x0000001, 0xf8, 0, PutAll },
136 { "SEI", 0x0000001, 0x78, 0, PutAll },
137 { "STA", 0x000A26C, 0x80, 0, PutAll },
138 { "STX", 0x000010c, 0x82, 1, PutAll },
139 { "STY", 0x000002c, 0x80, 1, PutAll },
140 { "TAX", 0x0000001, 0xaa, 0, PutAll },
141 { "TAY", 0x0000001, 0xa8, 0, PutAll },
142 { "TSX", 0x0000001, 0xba, 0, PutAll },
143 { "TXA", 0x0000001, 0x8a, 0, PutAll },
144 { "TXS", 0x0000001, 0x9a, 0, PutAll },
145 { "TYA", 0x0000001, 0x98, 0, PutAll }
149 /* Instruction table for the 6502 with illegal instructions */
150 #define INS_COUNT_6502X 57
151 static const struct {
153 InsDesc Ins[INS_COUNT_6502X];
157 { "ADC", 0x080A26C, 0x60, 0, PutAll },
158 { "AND", 0x080A26C, 0x20, 0, PutAll },
159 { "ASL", 0x000006e, 0x02, 1, PutAll },
160 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
161 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
162 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
163 { "BIT", 0x000000C, 0x00, 2, PutAll },
164 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
165 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
166 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
167 { "BRK", 0x0000001, 0x00, 0, PutAll },
168 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
169 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
170 { "CLC", 0x0000001, 0x18, 0, PutAll },
171 { "CLD", 0x0000001, 0xd8, 0, PutAll },
172 { "CLI", 0x0000001, 0x58, 0, PutAll },
173 { "CLV", 0x0000001, 0xb8, 0, PutAll },
174 { "CMP", 0x080A26C, 0xc0, 0, PutAll },
175 { "CPX", 0x080000C, 0xe0, 1, PutAll },
176 { "CPY", 0x080000C, 0xc0, 1, PutAll },
177 { "DEC", 0x000006C, 0x00, 3, PutAll },
178 { "DEX", 0x0000001, 0xca, 0, PutAll },
179 { "DEY", 0x0000001, 0x88, 0, PutAll },
180 { "EOR", 0x080A26C, 0x40, 0, PutAll },
181 { "INC", 0x000006c, 0x00, 4, PutAll },
182 { "INX", 0x0000001, 0xe8, 0, PutAll },
183 { "INY", 0x0000001, 0xc8, 0, PutAll },
184 { "JAM", 0x0000001, 0x02, 0, PutAll }, /* X */
185 { "JMP", 0x0000808, 0x4c, 6, PutJMP },
186 { "JSR", 0x0000008, 0x20, 7, PutAll },
187 { "LDA", 0x080A26C, 0xa0, 0, PutAll },
188 { "LDX", 0x080030C, 0xa2, 1, PutAll },
189 { "LDY", 0x080006C, 0xa0, 1, PutAll },
190 { "LSR", 0x000006F, 0x42, 1, PutAll },
191 { "NOP", 0x0000001, 0xea, 0, PutAll },
192 { "ORA", 0x080A26C, 0x00, 0, PutAll },
193 { "PHA", 0x0000001, 0x48, 0, PutAll },
194 { "PHP", 0x0000001, 0x08, 0, PutAll },
195 { "PLA", 0x0000001, 0x68, 0, PutAll },
196 { "PLP", 0x0000001, 0x28, 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", 0x080A26C, 0xe0, 0, PutAll },
202 { "SEC", 0x0000001, 0x38, 0, PutAll },
203 { "SED", 0x0000001, 0xf8, 0, PutAll },
204 { "SEI", 0x0000001, 0x78, 0, PutAll },
205 { "STA", 0x000A26C, 0x80, 0, PutAll },
206 { "STX", 0x000010c, 0x82, 1, PutAll },
207 { "STY", 0x000002c, 0x80, 1, PutAll },
208 { "TAX", 0x0000001, 0xaa, 0, PutAll },
209 { "TAY", 0x0000001, 0xa8, 0, PutAll },
210 { "TSX", 0x0000001, 0xba, 0, PutAll },
211 { "TXA", 0x0000001, 0x8a, 0, PutAll },
212 { "TXS", 0x0000001, 0x9a, 0, PutAll },
213 { "TYA", 0x0000001, 0x98, 0, PutAll }
217 /* Instruction table for the 65SC02 */
218 #define INS_COUNT_65SC02 66
219 static const struct {
221 InsDesc Ins[INS_COUNT_65SC02];
225 { "ADC", 0x080A66C, 0x60, 0, PutAll },
226 { "AND", 0x080A66C, 0x20, 0, PutAll },
227 { "ASL", 0x000006e, 0x02, 1, PutAll },
228 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
229 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
230 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
231 { "BIT", 0x0A0006C, 0x00, 2, PutAll },
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 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
238 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
239 { "CLC", 0x0000001, 0x18, 0, PutAll },
240 { "CLD", 0x0000001, 0xd8, 0, PutAll },
241 { "CLI", 0x0000001, 0x58, 0, PutAll },
242 { "CLV", 0x0000001, 0xb8, 0, PutAll },
243 { "CMP", 0x080A66C, 0xc0, 0, PutAll },
244 { "CPX", 0x080000C, 0xe0, 1, PutAll },
245 { "CPY", 0x080000C, 0xc0, 1, PutAll },
246 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
247 { "DEC", 0x000006F, 0x00, 3, PutAll },
248 { "DEX", 0x0000001, 0xca, 0, PutAll },
249 { "DEY", 0x0000001, 0x88, 0, PutAll },
250 { "EOR", 0x080A66C, 0x40, 0, PutAll },
251 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
252 { "INC", 0x000006f, 0x00, 4, PutAll },
253 { "INX", 0x0000001, 0xe8, 0, PutAll },
254 { "INY", 0x0000001, 0xc8, 0, PutAll },
255 { "JMP", 0x0010808, 0x4c, 6, PutAll },
256 { "JSR", 0x0000008, 0x20, 7, PutAll },
257 { "LDA", 0x080A66C, 0xa0, 0, PutAll },
258 { "LDX", 0x080030C, 0xa2, 1, PutAll },
259 { "LDY", 0x080006C, 0xa0, 1, PutAll },
260 { "LSR", 0x000006F, 0x42, 1, PutAll },
261 { "NOP", 0x0000001, 0xea, 0, PutAll },
262 { "ORA", 0x080A66C, 0x00, 0, PutAll },
263 { "PHA", 0x0000001, 0x48, 0, PutAll },
264 { "PHP", 0x0000001, 0x08, 0, PutAll },
265 { "PHX", 0x0000001, 0xda, 0, PutAll },
266 { "PHY", 0x0000001, 0x5a, 0, PutAll },
267 { "PLA", 0x0000001, 0x68, 0, PutAll },
268 { "PLP", 0x0000001, 0x28, 0, PutAll },
269 { "PLX", 0x0000001, 0xfa, 0, PutAll },
270 { "PLY", 0x0000001, 0x7a, 0, PutAll },
271 { "ROL", 0x000006F, 0x22, 1, PutAll },
272 { "ROR", 0x000006F, 0x62, 1, PutAll },
273 { "RTI", 0x0000001, 0x40, 0, PutAll },
274 { "RTS", 0x0000001, 0x60, 0, PutAll },
275 { "SBC", 0x080A66C, 0xe0, 0, PutAll },
276 { "SEC", 0x0000001, 0x38, 0, PutAll },
277 { "SED", 0x0000001, 0xf8, 0, PutAll },
278 { "SEI", 0x0000001, 0x78, 0, PutAll },
279 { "STA", 0x000A66C, 0x80, 0, PutAll },
280 { "STX", 0x000010c, 0x82, 1, PutAll },
281 { "STY", 0x000002c, 0x80, 1, PutAll },
282 { "STZ", 0x000006c, 0x04, 5, PutAll },
283 { "TAX", 0x0000001, 0xaa, 0, PutAll },
284 { "TAY", 0x0000001, 0xa8, 0, PutAll },
285 { "TRB", 0x000000c, 0x10, 1, PutAll },
286 { "TSB", 0x000000c, 0x00, 1, PutAll },
287 { "TSX", 0x0000001, 0xba, 0, PutAll },
288 { "TXA", 0x0000001, 0x8a, 0, PutAll },
289 { "TXS", 0x0000001, 0x9a, 0, PutAll },
290 { "TYA", 0x0000001, 0x98, 0, PutAll }
294 /* Instruction table for the 65C02 */
295 #define INS_COUNT_65C02 98
296 static const struct {
298 InsDesc Ins[INS_COUNT_65C02];
302 { "ADC", 0x080A66C, 0x60, 0, PutAll },
303 { "AND", 0x080A66C, 0x20, 0, PutAll },
304 { "ASL", 0x000006e, 0x02, 1, PutAll },
305 { "BBR0", 0x0000000, 0x0F, 0, PutBitBranch },
306 { "BBR1", 0x0000000, 0x1F, 0, PutBitBranch },
307 { "BBR2", 0x0000000, 0x2F, 0, PutBitBranch },
308 { "BBR3", 0x0000000, 0x3F, 0, PutBitBranch },
309 { "BBR4", 0x0000000, 0x4F, 0, PutBitBranch },
310 { "BBR5", 0x0000000, 0x5F, 0, PutBitBranch },
311 { "BBR6", 0x0000000, 0x6F, 0, PutBitBranch },
312 { "BBR7", 0x0000000, 0x7F, 0, PutBitBranch },
313 { "BBS0", 0x0000000, 0x8F, 0, PutBitBranch },
314 { "BBS1", 0x0000000, 0x9F, 0, PutBitBranch },
315 { "BBS2", 0x0000000, 0xAF, 0, PutBitBranch },
316 { "BBS3", 0x0000000, 0xBF, 0, PutBitBranch },
317 { "BBS4", 0x0000000, 0xCF, 0, PutBitBranch },
318 { "BBS5", 0x0000000, 0xDF, 0, PutBitBranch },
319 { "BBS6", 0x0000000, 0xEF, 0, PutBitBranch },
320 { "BBS7", 0x0000000, 0xFF, 0, PutBitBranch },
321 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
322 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
323 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
324 { "BIT", 0x0A0006C, 0x00, 2, PutAll },
325 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
326 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
327 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
328 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
329 { "BRK", 0x0000001, 0x00, 0, PutAll },
330 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
331 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
332 { "CLC", 0x0000001, 0x18, 0, PutAll },
333 { "CLD", 0x0000001, 0xd8, 0, PutAll },
334 { "CLI", 0x0000001, 0x58, 0, PutAll },
335 { "CLV", 0x0000001, 0xb8, 0, PutAll },
336 { "CMP", 0x080A66C, 0xc0, 0, PutAll },
337 { "CPX", 0x080000C, 0xe0, 1, PutAll },
338 { "CPY", 0x080000C, 0xc0, 1, PutAll },
339 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
340 { "DEC", 0x000006F, 0x00, 3, PutAll },
341 { "DEX", 0x0000001, 0xca, 0, PutAll },
342 { "DEY", 0x0000001, 0x88, 0, PutAll },
343 { "EOR", 0x080A66C, 0x40, 0, PutAll },
344 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
345 { "INC", 0x000006f, 0x00, 4, PutAll },
346 { "INX", 0x0000001, 0xe8, 0, PutAll },
347 { "INY", 0x0000001, 0xc8, 0, PutAll },
348 { "JMP", 0x0010808, 0x4c, 6, PutAll },
349 { "JSR", 0x0000008, 0x20, 7, PutAll },
350 { "LDA", 0x080A66C, 0xa0, 0, PutAll },
351 { "LDX", 0x080030C, 0xa2, 1, PutAll },
352 { "LDY", 0x080006C, 0xa0, 1, PutAll },
353 { "LSR", 0x000006F, 0x42, 1, PutAll },
354 { "NOP", 0x0000001, 0xea, 0, PutAll },
355 { "ORA", 0x080A66C, 0x00, 0, PutAll },
356 { "PHA", 0x0000001, 0x48, 0, PutAll },
357 { "PHP", 0x0000001, 0x08, 0, PutAll },
358 { "PHX", 0x0000001, 0xda, 0, PutAll },
359 { "PHY", 0x0000001, 0x5a, 0, PutAll },
360 { "PLA", 0x0000001, 0x68, 0, PutAll },
361 { "PLP", 0x0000001, 0x28, 0, PutAll },
362 { "PLX", 0x0000001, 0xfa, 0, PutAll },
363 { "PLY", 0x0000001, 0x7a, 0, PutAll },
364 { "RMB0", 0x0000004, 0x07, 1, PutAll },
365 { "RMB1", 0x0000004, 0x17, 1, PutAll },
366 { "RMB2", 0x0000004, 0x27, 1, PutAll },
367 { "RMB3", 0x0000004, 0x37, 1, PutAll },
368 { "RMB4", 0x0000004, 0x47, 1, PutAll },
369 { "RMB5", 0x0000004, 0x57, 1, PutAll },
370 { "RMB6", 0x0000004, 0x67, 1, PutAll },
371 { "RMB7", 0x0000004, 0x77, 1, PutAll },
372 { "ROL", 0x000006F, 0x22, 1, PutAll },
373 { "ROR", 0x000006F, 0x62, 1, PutAll },
374 { "RTI", 0x0000001, 0x40, 0, PutAll },
375 { "RTS", 0x0000001, 0x60, 0, PutAll },
376 { "SBC", 0x080A66C, 0xe0, 0, PutAll },
377 { "SEC", 0x0000001, 0x38, 0, PutAll },
378 { "SED", 0x0000001, 0xf8, 0, PutAll },
379 { "SEI", 0x0000001, 0x78, 0, PutAll },
380 { "SMB0", 0x0000004, 0x87, 1, PutAll },
381 { "SMB1", 0x0000004, 0x97, 1, PutAll },
382 { "SMB2", 0x0000004, 0xA7, 1, PutAll },
383 { "SMB3", 0x0000004, 0xB7, 1, PutAll },
384 { "SMB4", 0x0000004, 0xC7, 1, PutAll },
385 { "SMB5", 0x0000004, 0xD7, 1, PutAll },
386 { "SMB6", 0x0000004, 0xE7, 1, PutAll },
387 { "SMB7", 0x0000004, 0xF7, 1, PutAll },
388 { "STA", 0x000A66C, 0x80, 0, PutAll },
389 { "STX", 0x000010c, 0x82, 1, PutAll },
390 { "STY", 0x000002c, 0x80, 1, PutAll },
391 { "STZ", 0x000006c, 0x04, 5, PutAll },
392 { "TAX", 0x0000001, 0xaa, 0, PutAll },
393 { "TAY", 0x0000001, 0xa8, 0, PutAll },
394 { "TRB", 0x000000c, 0x10, 1, PutAll },
395 { "TSB", 0x000000c, 0x00, 1, PutAll },
396 { "TSX", 0x0000001, 0xba, 0, PutAll },
397 { "TXA", 0x0000001, 0x8a, 0, PutAll },
398 { "TXS", 0x0000001, 0x9a, 0, PutAll },
399 { "TYA", 0x0000001, 0x98, 0, PutAll }
403 /* Instruction table for the 65816 */
404 #define INS_COUNT_65816 101
405 static const struct {
407 InsDesc Ins[INS_COUNT_65816];
411 { "ADC", 0x0b8f6fc, 0x60, 0, PutAll },
412 { "AND", 0x0b8f6fc, 0x20, 0, PutAll },
413 { "ASL", 0x000006e, 0x02, 1, PutAll },
414 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
415 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
416 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
417 { "BGE", 0x0020000, 0xb0, 0, PutPCRel8 }, /* == BCS */
418 { "BIT", 0x0a0006c, 0x00, 2, PutAll },
419 { "BLT", 0x0020000, 0x90, 0, PutPCRel8 }, /* == BCC */
420 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
421 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
422 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
423 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
424 { "BRK", 0x0000001, 0x00, 0, PutAll },
425 { "BRL", 0x0040000, 0x82, 0, PutPCRel16 },
426 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
427 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
428 { "CLC", 0x0000001, 0x18, 0, PutAll },
429 { "CLD", 0x0000001, 0xd8, 0, PutAll },
430 { "CLI", 0x0000001, 0x58, 0, PutAll },
431 { "CLV", 0x0000001, 0xb8, 0, PutAll },
432 { "CMP", 0x0b8f6fc, 0xc0, 0, PutAll },
433 { "COP", 0x0000004, 0x02, 6, PutAll },
434 { "CPA", 0x0b8f6fc, 0xc0, 0, PutAll }, /* == CMP */
435 { "CPX", 0x0c0000c, 0xe0, 1, PutAll },
436 { "CPY", 0x0c0000c, 0xc0, 1, PutAll },
437 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
438 { "DEC", 0x000006F, 0x00, 3, PutAll },
439 { "DEX", 0x0000001, 0xca, 0, PutAll },
440 { "DEY", 0x0000001, 0x88, 0, PutAll },
441 { "EOR", 0x0b8f6fc, 0x40, 0, PutAll },
442 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
443 { "INC", 0x000006F, 0x00, 4, PutAll },
444 { "INX", 0x0000001, 0xe8, 0, PutAll },
445 { "INY", 0x0000001, 0xc8, 0, PutAll },
446 { "JML", 0x0000810, 0x5c, 1, PutAll },
447 { "JMP", 0x0010818, 0x4c, 6, PutAll },
448 { "JSL", 0x0000010, 0x20, 7, PutAll },
449 { "JSR", 0x0010018, 0x20, 7, PutAll },
450 { "LDA", 0x0b8f6fc, 0xa0, 0, PutAll },
451 { "LDX", 0x0c0030c, 0xa2, 1, PutAll },
452 { "LDY", 0x0c0006c, 0xa0, 1, PutAll },
453 { "LSR", 0x000006F, 0x42, 1, PutAll },
454 { "MVN", 0x1000000, 0x54, 0, PutBlockMove },
455 { "MVP", 0x1000000, 0x44, 0, PutBlockMove },
456 { "NOP", 0x0000001, 0xea, 0, PutAll },
457 { "ORA", 0x0b8f6fc, 0x00, 0, PutAll },
458 { "PEA", 0x0000008, 0xf4, 6, PutAll },
459 { "PEI", 0x0000400, 0xd4, 1, PutAll },
460 { "PER", 0x0040000, 0x62, 0, PutPCRel16 },
461 { "PHA", 0x0000001, 0x48, 0, PutAll },
462 { "PHB", 0x0000001, 0x8b, 0, PutAll },
463 { "PHD", 0x0000001, 0x0b, 0, PutAll },
464 { "PHK", 0x0000001, 0x4b, 0, PutAll },
465 { "PHP", 0x0000001, 0x08, 0, PutAll },
466 { "PHX", 0x0000001, 0xda, 0, PutAll },
467 { "PHY", 0x0000001, 0x5a, 0, PutAll },
468 { "PLA", 0x0000001, 0x68, 0, PutAll },
469 { "PLB", 0x0000001, 0xab, 0, PutAll },
470 { "PLD", 0x0000001, 0x2b, 0, PutAll },
471 { "PLP", 0x0000001, 0x28, 0, PutAll },
472 { "PLX", 0x0000001, 0xfa, 0, PutAll },
473 { "PLY", 0x0000001, 0x7a, 0, PutAll },
474 { "REP", 0x0800000, 0xc2, 1, PutREP },
475 { "ROL", 0x000006F, 0x22, 1, PutAll },
476 { "ROR", 0x000006F, 0x62, 1, PutAll },
477 { "RTI", 0x0000001, 0x40, 0, PutAll },
478 { "RTL", 0x0000001, 0x6b, 0, PutAll },
479 { "RTS", 0x0000001, 0x60, 0, PutRTS },
480 { "SBC", 0x0b8f6fc, 0xe0, 0, PutAll },
481 { "SEC", 0x0000001, 0x38, 0, PutAll },
482 { "SED", 0x0000001, 0xf8, 0, PutAll },
483 { "SEI", 0x0000001, 0x78, 0, PutAll },
484 { "SEP", 0x0800000, 0xe2, 1, PutSEP },
485 { "STA", 0x018f6fc, 0x80, 0, PutAll },
486 { "STP", 0x0000001, 0xdb, 0, PutAll },
487 { "STX", 0x000010c, 0x82, 1, PutAll },
488 { "STY", 0x000002c, 0x80, 1, PutAll },
489 { "STZ", 0x000006c, 0x04, 5, PutAll },
490 { "SWA", 0x0000001, 0xeb, 0, PutAll }, /* == XBA */
491 { "TAD", 0x0000001, 0x5b, 0, PutAll }, /* == TCD */
492 { "TAS", 0x0000001, 0x1b, 0, PutAll }, /* == TCS */
493 { "TAX", 0x0000001, 0xaa, 0, PutAll },
494 { "TAY", 0x0000001, 0xa8, 0, PutAll },
495 { "TCD", 0x0000001, 0x5b, 0, PutAll },
496 { "TCS", 0x0000001, 0x1b, 0, PutAll },
497 { "TDA", 0x0000001, 0x7b, 0, PutAll }, /* == TDC */
498 { "TDC", 0x0000001, 0x7b, 0, PutAll },
499 { "TRB", 0x000000c, 0x10, 1, PutAll },
500 { "TSA", 0x0000001, 0x3b, 0, PutAll }, /* == TSC */
501 { "TSB", 0x000000c, 0x00, 1, PutAll },
502 { "TSC", 0x0000001, 0x3b, 0, PutAll },
503 { "TSX", 0x0000001, 0xba, 0, PutAll },
504 { "TXA", 0x0000001, 0x8a, 0, PutAll },
505 { "TXS", 0x0000001, 0x9a, 0, PutAll },
506 { "TXY", 0x0000001, 0x9b, 0, PutAll },
507 { "TYA", 0x0000001, 0x98, 0, PutAll },
508 { "TYX", 0x0000001, 0xbb, 0, PutAll },
509 { "WAI", 0x0000001, 0xcb, 0, PutAll },
510 { "XBA", 0x0000001, 0xeb, 0, PutAll },
511 { "XCE", 0x0000001, 0xfb, 0, PutAll }
516 /* Table for the SUNPLUS CPU */
517 #include "sunplus.inc"
522 /* An array with instruction tables */
523 static const InsTable* InsTabs[CPU_COUNT] = {
524 (const InsTable*) &InsTab6502,
525 (const InsTable*) &InsTab6502X,
526 (const InsTable*) &InsTab65SC02,
527 (const InsTable*) &InsTab65C02,
528 (const InsTable*) &InsTab65816,
530 (const InsTable*) &InsTabSunPlus,
533 const InsTable* InsTab = (const InsTable*) &InsTab6502;
535 /* Table to build the effective opcode from a base opcode and an addressing
538 unsigned char EATab [9][AMI_COUNT] = {
540 0x00, 0x00, 0x05, 0x0D, 0x0F, 0x15, 0x1D, 0x1F,
541 0x00, 0x19, 0x12, 0x00, 0x07, 0x11, 0x17, 0x01,
542 0x00, 0x00, 0x00, 0x03, 0x13, 0x09, 0x00, 0x09,
546 0x08, 0x08, 0x04, 0x0C, 0x00, 0x14, 0x1C, 0x00,
547 0x14, 0x1C, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
548 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
552 0x00, 0x00, 0x24, 0x2C, 0x0F, 0x34, 0x3C, 0x00,
553 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
554 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00,
558 0x3A, 0x3A, 0xC6, 0xCE, 0x00, 0xD6, 0xDE, 0x00,
559 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
560 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
564 0x1A, 0x1A, 0xE6, 0xEE, 0x00, 0xF6, 0xFE, 0x00,
565 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
566 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
570 0x00, 0x00, 0x60, 0x98, 0x00, 0x70, 0x9E, 0x00,
571 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
572 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
576 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
577 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
578 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
582 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
583 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
584 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
588 0x00, 0x40, 0x01, 0x41, 0x00, 0x09, 0x49, 0x00,
589 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00,
590 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
595 /* Table that encodes the additional bytes for each instruction */
596 unsigned char ExtBytes [AMI_COUNT] = {
601 3, /* Absolute long */
604 3, /* Absolute long,X */
613 2, /* (Absolute,X) */
614 1, /* Relative short */
615 2, /* Relative long */
618 1, /* Immidiate accu */
619 1, /* Immidiate index */
620 1, /* Immidiate byte */
626 /*****************************************************************************/
627 /* Handler functions */
628 /*****************************************************************************/
632 static int EvalEA (const InsDesc* Ins, EffAddr* A)
633 /* Evaluate the effective address. All fields in A will be valid after calling
634 * this function. The function returns true on success and false on errors.
637 /* Get the set of possible addressing modes */
640 /* From the possible addressing modes, remove the ones that are invalid
641 * for this instruction or CPU.
643 A->AddrModeSet &= Ins->AddrMode;
645 /* If we have an expression, check it and remove any addressing modes that
646 * are too small for the expression size. Since we have to study the
647 * expression anyway, do also replace it by a simpler one if possible.
653 /* Study the expression */
654 StudyExpr (A->Expr, &ED);
656 /* Simplify it if possible */
657 A->Expr = SimplifyExpr (A->Expr, &ED);
659 /* If we don't know how big the expression is, assume the default
660 * address size for data.
662 if (ED.AddrSize == ADDR_SIZE_DEFAULT) {
663 ED.AddrSize = DataAddrSize;
667 switch (ED.AddrSize) {
670 A->AddrModeSet &= ~AM_SET_ZP;
674 A->AddrModeSet &= ~(AM_SET_ZP | AM_SET_ABS);
678 /* Free any resource associated with the expression desc */
682 /* Check if we have any adressing modes left */
683 if (A->AddrModeSet == 0) {
684 Error ("Illegal addressing mode");
687 A->AddrMode = BitFind (A->AddrModeSet);
688 A->AddrModeBit = (0x01UL << A->AddrMode);
690 /* If the instruction has a one byte operand and immediate addressing is
691 * allowed but not used, check for an operand expression in the form
692 * <label or >label, where label is a far or absolute label. If found,
693 * emit a warning. This warning protects against a typo, where the '#'
694 * for the immediate operand is omitted.
696 if (A->Expr && (Ins->AddrMode & AM_IMM) &&
697 (A->AddrModeSet & (AM_DIR | AM_ABS | AM_ABS_LONG)) &&
698 ExtBytes[A->AddrMode] == 1) {
700 /* Found, check the expression */
701 ExprNode* Left = A->Expr->Left;
702 if ((A->Expr->Op == EXPR_BYTE0 || A->Expr->Op == EXPR_BYTE1) &&
703 Left->Op == EXPR_SYMBOL &&
704 GetSymAddrSize (Left->V.Sym) != ADDR_SIZE_ZP) {
706 /* Output a warning */
707 Warning (1, "Suspicious address expression");
711 /* Build the opcode */
712 A->Opcode = Ins->BaseCode | EATab[Ins->ExtCode][A->AddrMode];
720 static void EmitCode (EffAddr* A)
721 /* Output code for the data in A */
723 /* Check how many extension bytes are needed and output the instruction */
724 switch (ExtBytes[A->AddrMode]) {
731 Emit1 (A->Opcode, A->Expr);
735 if (CPU == CPU_65816 && (A->AddrModeBit & (AM_ABS | AM_ABS_X | AM_ABS_Y))) {
736 /* This is a 16 bit mode that uses an address. If in 65816,
737 * mode, force this address into 16 bit range to allow
738 * addressing inside a 64K segment.
740 Emit2 (A->Opcode, GenWordExpr (A->Expr));
742 Emit2 (A->Opcode, A->Expr);
748 Emit3 (A->Opcode, A->Expr);
752 Internal ("Invalid operand byte count: %u", ExtBytes[A->AddrMode]);
759 static long PutImmed8 (const InsDesc* Ins)
760 /* Parse and emit an immediate 8 bit instruction. Return the value of the
761 * operand if it's available and const.
767 /* Evaluate the addressing mode */
768 if (EvalEA (Ins, &A) == 0) {
769 /* An error occurred */
773 /* If we have an expression and it's const, get it's value */
775 (void) IsConstExpr (A.Expr, &Val);
778 /* Check how many extension bytes are needed and output the instruction */
779 switch (ExtBytes[A.AddrMode]) {
782 Emit1 (A.Opcode, A.Expr);
786 Internal ("Invalid operand byte count: %u", ExtBytes[A.AddrMode]);
789 /* Return the expression value */
795 static void PutPCRel8 (const InsDesc* Ins)
796 /* Handle branches with a 8 bit distance */
798 EmitPCRel (Ins->BaseCode, GenBranchExpr (2), 1);
803 static void PutPCRel16 (const InsDesc* Ins)
804 /* Handle branches with an 16 bit distance and PER */
806 EmitPCRel (Ins->BaseCode, GenBranchExpr (3), 2);
811 static void PutBlockMove (const InsDesc* Ins)
812 /* Handle the blockmove instructions */
814 Emit0 (Ins->BaseCode);
815 EmitByte (Expression ());
817 EmitByte (Expression ());
822 static void PutBitBranch (const InsDesc* Ins)
823 /* Handle 65C02 branch on bit condition */
825 Emit0 (Ins->BaseCode);
826 EmitByte (Expression ());
828 EmitSigned (GenBranchExpr (1), 1);
833 static void PutREP (const InsDesc* Ins)
834 /* Emit a REP instruction, track register sizes */
836 /* Use the generic handler */
837 long Val = PutImmed8 (Ins);
839 /* We track the status only for the 816 CPU and in smart mode */
840 if (CPU == CPU_65816 && SmartMode) {
842 /* Check the range for Val. */
844 /* We had an error */
845 Warning (1, "Cannot track processor status byte");
848 /* Index registers to 16 bit */
849 ExtBytes[AMI_IMM_INDEX] = 2;
853 ExtBytes[AMI_IMM_ACCU] = 2;
861 static void PutSEP (const InsDesc* Ins)
862 /* Emit a SEP instruction, track register sizes */
864 /* Use the generic handler */
865 long Val = PutImmed8 (Ins);
867 /* We track the status only for the 816 CPU and in smart mode */
868 if (CPU == CPU_65816 && SmartMode) {
870 /* Check the range for Val. */
872 /* We had an error */
873 Warning (1, "Cannot track processor status byte");
876 /* Index registers to 8 bit */
877 ExtBytes [AMI_IMM_INDEX] = 1;
881 ExtBytes [AMI_IMM_ACCU] = 1;
889 static void PutJMP (const InsDesc* Ins)
890 /* Handle the jump instruction for the 6502. Problem is that these chips have
891 * a bug: If the address crosses a page, the upper byte gets not corrected and
892 * the instruction will fail. The PutJmp function will add a linker assertion
893 * to check for this case and is otherwise identical to PutAll.
898 /* Evaluate the addressing mode used */
899 if (EvalEA (Ins, &A)) {
901 /* Check for indirect addressing */
902 if (A.AddrModeBit & AM_ABS_IND) {
904 /* Compare the low byte of the expression to 0xFF to check for
905 * a page cross. Be sure to use a copy of the expression otherwise
906 * things will go weird later.
908 ExprNode* E = GenNE (GenByteExpr (CloneExpr (A.Expr)), 0xFF);
910 /* Generate the message */
911 unsigned Msg = GetStringId ("\"jmp (abs)\" across page border");
913 /* Generate the assertion */
914 AddAssertion (E, ASSERT_ACT_WARN, Msg);
917 /* No error, output code */
924 static void PutRTS (const InsDesc* Ins attribute ((unused)))
925 /* Handle the RTS instruction for the 816. In smart mode emit a RTL opcode if
926 * the enclosing scope is FAR.
929 if (SmartMode && CurrentScope->AddrSize == ADDR_SIZE_FAR) {
930 Emit0 (0x6B); /* RTL */
932 Emit0 (0x60); /* RTS */
938 static void PutAll (const InsDesc* Ins)
939 /* Handle all other instructions */
943 /* Evaluate the addressing mode used */
944 if (EvalEA (Ins, &A)) {
945 /* No error, output code */
952 /*****************************************************************************/
954 /*****************************************************************************/
958 static int CmpName (const void* Key, const void* Instr)
959 /* Compare function for bsearch */
961 return strcmp ((const char*)Key, ((const InsDesc*) Instr)->Mnemonic);
966 void SetCPU (cpu_t NewCPU)
969 /* Make sure the parameter is correct */
970 CHECK (NewCPU < CPU_COUNT);
972 /* Check if we have support for the new CPU, if so, use it */
973 if (InsTabs[NewCPU]) {
975 InsTab = InsTabs[CPU];
977 Error ("CPU not supported");
984 /* Return the current CPU */
991 int FindInstruction (const char* Ident)
992 /* Check if Ident is a valid mnemonic. If so, return the index in the
993 * instruction table. If not, return -1.
998 char Key[sizeof (ID->Mnemonic)];
1000 /* Make a copy, and uppercase that copy */
1002 while (Ident[I] != '\0') {
1003 /* If the identifier is longer than the longest mnemonic, it cannot
1006 if (I >= sizeof (Key) - 1) {
1007 /* Not found, no need for further action */
1010 Key[I] = toupper ((unsigned char)Ident[I]);
1015 /* Search for the key */
1016 ID = bsearch (Key, InsTab->Ins, InsTab->Count, sizeof (InsDesc), CmpName);
1021 /* Found, return the entry */
1022 return ID - InsTab->Ins;
1028 void HandleInstruction (unsigned Index)
1029 /* Handle the mnemonic with the given index */
1032 PRECONDITION (Index < InsTab->Count);
1034 /* Skip the mnemonic token */
1037 /* Call the handler */
1038 InsTab->Ins[Index].Emit (&InsTab->Ins[Index]);