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 65SC02 */
150 #define INS_COUNT_65SC02 66
151 static const struct {
153 InsDesc Ins[INS_COUNT_65SC02];
157 { "ADC", 0x080A66C, 0x60, 0, PutAll },
158 { "AND", 0x080A66C, 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", 0x0A0006C, 0x00, 2, PutAll },
164 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
165 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
166 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
167 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
168 { "BRK", 0x0000001, 0x00, 0, PutAll },
169 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
170 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
171 { "CLC", 0x0000001, 0x18, 0, PutAll },
172 { "CLD", 0x0000001, 0xd8, 0, PutAll },
173 { "CLI", 0x0000001, 0x58, 0, PutAll },
174 { "CLV", 0x0000001, 0xb8, 0, PutAll },
175 { "CMP", 0x080A66C, 0xc0, 0, PutAll },
176 { "CPX", 0x080000C, 0xe0, 1, PutAll },
177 { "CPY", 0x080000C, 0xc0, 1, PutAll },
178 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
179 { "DEC", 0x000006F, 0x00, 3, PutAll },
180 { "DEX", 0x0000001, 0xca, 0, PutAll },
181 { "DEY", 0x0000001, 0x88, 0, PutAll },
182 { "EOR", 0x080A66C, 0x40, 0, PutAll },
183 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
184 { "INC", 0x000006f, 0x00, 4, PutAll },
185 { "INX", 0x0000001, 0xe8, 0, PutAll },
186 { "INY", 0x0000001, 0xc8, 0, PutAll },
187 { "JMP", 0x0010808, 0x4c, 6, PutAll },
188 { "JSR", 0x0000008, 0x20, 7, PutAll },
189 { "LDA", 0x080A66C, 0xa0, 0, PutAll },
190 { "LDX", 0x080030C, 0xa2, 1, PutAll },
191 { "LDY", 0x080006C, 0xa0, 1, PutAll },
192 { "LSR", 0x000006F, 0x42, 1, PutAll },
193 { "NOP", 0x0000001, 0xea, 0, PutAll },
194 { "ORA", 0x080A66C, 0x00, 0, PutAll },
195 { "PHA", 0x0000001, 0x48, 0, PutAll },
196 { "PHP", 0x0000001, 0x08, 0, PutAll },
197 { "PHX", 0x0000001, 0xda, 0, PutAll },
198 { "PHY", 0x0000001, 0x5a, 0, PutAll },
199 { "PLA", 0x0000001, 0x68, 0, PutAll },
200 { "PLP", 0x0000001, 0x28, 0, PutAll },
201 { "PLX", 0x0000001, 0xfa, 0, PutAll },
202 { "PLY", 0x0000001, 0x7a, 0, PutAll },
203 { "ROL", 0x000006F, 0x22, 1, PutAll },
204 { "ROR", 0x000006F, 0x62, 1, PutAll },
205 { "RTI", 0x0000001, 0x40, 0, PutAll },
206 { "RTS", 0x0000001, 0x60, 0, PutAll },
207 { "SBC", 0x080A66C, 0xe0, 0, PutAll },
208 { "SEC", 0x0000001, 0x38, 0, PutAll },
209 { "SED", 0x0000001, 0xf8, 0, PutAll },
210 { "SEI", 0x0000001, 0x78, 0, PutAll },
211 { "STA", 0x000A66C, 0x80, 0, PutAll },
212 { "STX", 0x000010c, 0x82, 1, PutAll },
213 { "STY", 0x000002c, 0x80, 1, PutAll },
214 { "STZ", 0x000006c, 0x04, 5, PutAll },
215 { "TAX", 0x0000001, 0xaa, 0, PutAll },
216 { "TAY", 0x0000001, 0xa8, 0, PutAll },
217 { "TRB", 0x000000c, 0x10, 1, PutAll },
218 { "TSB", 0x000000c, 0x00, 1, PutAll },
219 { "TSX", 0x0000001, 0xba, 0, PutAll },
220 { "TXA", 0x0000001, 0x8a, 0, PutAll },
221 { "TXS", 0x0000001, 0x9a, 0, PutAll },
222 { "TYA", 0x0000001, 0x98, 0, PutAll }
226 /* Instruction table for the 65C02 */
227 #define INS_COUNT_65C02 98
228 static const struct {
230 InsDesc Ins[INS_COUNT_65C02];
234 { "ADC", 0x080A66C, 0x60, 0, PutAll },
235 { "AND", 0x080A66C, 0x20, 0, PutAll },
236 { "ASL", 0x000006e, 0x02, 1, PutAll },
237 { "BBR0", 0x0000000, 0x0F, 0, PutBitBranch },
238 { "BBR1", 0x0000000, 0x1F, 0, PutBitBranch },
239 { "BBR2", 0x0000000, 0x2F, 0, PutBitBranch },
240 { "BBR3", 0x0000000, 0x3F, 0, PutBitBranch },
241 { "BBR4", 0x0000000, 0x4F, 0, PutBitBranch },
242 { "BBR5", 0x0000000, 0x5F, 0, PutBitBranch },
243 { "BBR6", 0x0000000, 0x6F, 0, PutBitBranch },
244 { "BBR7", 0x0000000, 0x7F, 0, PutBitBranch },
245 { "BBS0", 0x0000000, 0x8F, 0, PutBitBranch },
246 { "BBS1", 0x0000000, 0x9F, 0, PutBitBranch },
247 { "BBS2", 0x0000000, 0xAF, 0, PutBitBranch },
248 { "BBS3", 0x0000000, 0xBF, 0, PutBitBranch },
249 { "BBS4", 0x0000000, 0xCF, 0, PutBitBranch },
250 { "BBS5", 0x0000000, 0xDF, 0, PutBitBranch },
251 { "BBS6", 0x0000000, 0xEF, 0, PutBitBranch },
252 { "BBS7", 0x0000000, 0xFF, 0, PutBitBranch },
253 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
254 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
255 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
256 { "BIT", 0x0A0006C, 0x00, 2, PutAll },
257 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
258 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
259 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
260 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
261 { "BRK", 0x0000001, 0x00, 0, PutAll },
262 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
263 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
264 { "CLC", 0x0000001, 0x18, 0, PutAll },
265 { "CLD", 0x0000001, 0xd8, 0, PutAll },
266 { "CLI", 0x0000001, 0x58, 0, PutAll },
267 { "CLV", 0x0000001, 0xb8, 0, PutAll },
268 { "CMP", 0x080A66C, 0xc0, 0, PutAll },
269 { "CPX", 0x080000C, 0xe0, 1, PutAll },
270 { "CPY", 0x080000C, 0xc0, 1, PutAll },
271 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
272 { "DEC", 0x000006F, 0x00, 3, PutAll },
273 { "DEX", 0x0000001, 0xca, 0, PutAll },
274 { "DEY", 0x0000001, 0x88, 0, PutAll },
275 { "EOR", 0x080A66C, 0x40, 0, PutAll },
276 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
277 { "INC", 0x000006f, 0x00, 4, PutAll },
278 { "INX", 0x0000001, 0xe8, 0, PutAll },
279 { "INY", 0x0000001, 0xc8, 0, PutAll },
280 { "JMP", 0x0010808, 0x4c, 6, PutAll },
281 { "JSR", 0x0000008, 0x20, 7, PutAll },
282 { "LDA", 0x080A66C, 0xa0, 0, PutAll },
283 { "LDX", 0x080030C, 0xa2, 1, PutAll },
284 { "LDY", 0x080006C, 0xa0, 1, PutAll },
285 { "LSR", 0x000006F, 0x42, 1, PutAll },
286 { "NOP", 0x0000001, 0xea, 0, PutAll },
287 { "ORA", 0x080A66C, 0x00, 0, PutAll },
288 { "PHA", 0x0000001, 0x48, 0, PutAll },
289 { "PHP", 0x0000001, 0x08, 0, PutAll },
290 { "PHX", 0x0000001, 0xda, 0, PutAll },
291 { "PHY", 0x0000001, 0x5a, 0, PutAll },
292 { "PLA", 0x0000001, 0x68, 0, PutAll },
293 { "PLP", 0x0000001, 0x28, 0, PutAll },
294 { "PLX", 0x0000001, 0xfa, 0, PutAll },
295 { "PLY", 0x0000001, 0x7a, 0, PutAll },
296 { "RMB0", 0x0000004, 0x07, 1, PutAll },
297 { "RMB1", 0x0000004, 0x17, 1, PutAll },
298 { "RMB2", 0x0000004, 0x27, 1, PutAll },
299 { "RMB3", 0x0000004, 0x37, 1, PutAll },
300 { "RMB4", 0x0000004, 0x47, 1, PutAll },
301 { "RMB5", 0x0000004, 0x57, 1, PutAll },
302 { "RMB6", 0x0000004, 0x67, 1, PutAll },
303 { "RMB7", 0x0000004, 0x77, 1, PutAll },
304 { "ROL", 0x000006F, 0x22, 1, PutAll },
305 { "ROR", 0x000006F, 0x62, 1, PutAll },
306 { "RTI", 0x0000001, 0x40, 0, PutAll },
307 { "RTS", 0x0000001, 0x60, 0, PutAll },
308 { "SBC", 0x080A66C, 0xe0, 0, PutAll },
309 { "SEC", 0x0000001, 0x38, 0, PutAll },
310 { "SED", 0x0000001, 0xf8, 0, PutAll },
311 { "SEI", 0x0000001, 0x78, 0, PutAll },
312 { "SMB0", 0x0000004, 0x87, 1, PutAll },
313 { "SMB1", 0x0000004, 0x97, 1, PutAll },
314 { "SMB2", 0x0000004, 0xA7, 1, PutAll },
315 { "SMB3", 0x0000004, 0xB7, 1, PutAll },
316 { "SMB4", 0x0000004, 0xC7, 1, PutAll },
317 { "SMB5", 0x0000004, 0xD7, 1, PutAll },
318 { "SMB6", 0x0000004, 0xE7, 1, PutAll },
319 { "SMB7", 0x0000004, 0xF7, 1, PutAll },
320 { "STA", 0x000A66C, 0x80, 0, PutAll },
321 { "STX", 0x000010c, 0x82, 1, PutAll },
322 { "STY", 0x000002c, 0x80, 1, PutAll },
323 { "STZ", 0x000006c, 0x04, 5, PutAll },
324 { "TAX", 0x0000001, 0xaa, 0, PutAll },
325 { "TAY", 0x0000001, 0xa8, 0, PutAll },
326 { "TRB", 0x000000c, 0x10, 1, PutAll },
327 { "TSB", 0x000000c, 0x00, 1, PutAll },
328 { "TSX", 0x0000001, 0xba, 0, PutAll },
329 { "TXA", 0x0000001, 0x8a, 0, PutAll },
330 { "TXS", 0x0000001, 0x9a, 0, PutAll },
331 { "TYA", 0x0000001, 0x98, 0, PutAll }
335 /* Instruction table for the 65816 */
336 #define INS_COUNT_65816 101
337 static const struct {
339 InsDesc Ins[INS_COUNT_65816];
343 { "ADC", 0x0b8f6fc, 0x60, 0, PutAll },
344 { "AND", 0x0b8f6fc, 0x20, 0, PutAll },
345 { "ASL", 0x000006e, 0x02, 1, PutAll },
346 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
347 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
348 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
349 { "BGE", 0x0020000, 0xb0, 0, PutPCRel8 }, /* == BCS */
350 { "BIT", 0x0a0006c, 0x00, 2, PutAll },
351 { "BLT", 0x0020000, 0x90, 0, PutPCRel8 }, /* == BCC */
352 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
353 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
354 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
355 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
356 { "BRK", 0x0000001, 0x00, 0, PutAll },
357 { "BRL", 0x0040000, 0x82, 0, PutPCRel16 },
358 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
359 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
360 { "CLC", 0x0000001, 0x18, 0, PutAll },
361 { "CLD", 0x0000001, 0xd8, 0, PutAll },
362 { "CLI", 0x0000001, 0x58, 0, PutAll },
363 { "CLV", 0x0000001, 0xb8, 0, PutAll },
364 { "CMP", 0x0b8f6fc, 0xc0, 0, PutAll },
365 { "COP", 0x0000004, 0x02, 6, PutAll },
366 { "CPA", 0x0b8f6fc, 0xc0, 0, PutAll }, /* == CMP */
367 { "CPX", 0x0c0000c, 0xe0, 1, PutAll },
368 { "CPY", 0x0c0000c, 0xc0, 1, PutAll },
369 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
370 { "DEC", 0x000006F, 0x00, 3, PutAll },
371 { "DEX", 0x0000001, 0xca, 0, PutAll },
372 { "DEY", 0x0000001, 0x88, 0, PutAll },
373 { "EOR", 0x0b8f6fc, 0x40, 0, PutAll },
374 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
375 { "INC", 0x000006F, 0x00, 4, PutAll },
376 { "INX", 0x0000001, 0xe8, 0, PutAll },
377 { "INY", 0x0000001, 0xc8, 0, PutAll },
378 { "JML", 0x0000810, 0x5c, 1, PutAll },
379 { "JMP", 0x0010818, 0x4c, 6, PutAll },
380 { "JSL", 0x0000010, 0x20, 7, PutAll },
381 { "JSR", 0x0010018, 0x20, 7, PutAll },
382 { "LDA", 0x0b8f6fc, 0xa0, 0, PutAll },
383 { "LDX", 0x0c0030c, 0xa2, 1, PutAll },
384 { "LDY", 0x0c0006c, 0xa0, 1, PutAll },
385 { "LSR", 0x000006F, 0x42, 1, PutAll },
386 { "MVN", 0x1000000, 0x54, 0, PutBlockMove },
387 { "MVP", 0x1000000, 0x44, 0, PutBlockMove },
388 { "NOP", 0x0000001, 0xea, 0, PutAll },
389 { "ORA", 0x0b8f6fc, 0x00, 0, PutAll },
390 { "PEA", 0x0000008, 0xf4, 6, PutAll },
391 { "PEI", 0x0000400, 0xd4, 1, PutAll },
392 { "PER", 0x0040000, 0x62, 0, PutPCRel16 },
393 { "PHA", 0x0000001, 0x48, 0, PutAll },
394 { "PHB", 0x0000001, 0x8b, 0, PutAll },
395 { "PHD", 0x0000001, 0x0b, 0, PutAll },
396 { "PHK", 0x0000001, 0x4b, 0, PutAll },
397 { "PHP", 0x0000001, 0x08, 0, PutAll },
398 { "PHX", 0x0000001, 0xda, 0, PutAll },
399 { "PHY", 0x0000001, 0x5a, 0, PutAll },
400 { "PLA", 0x0000001, 0x68, 0, PutAll },
401 { "PLB", 0x0000001, 0xab, 0, PutAll },
402 { "PLD", 0x0000001, 0x2b, 0, PutAll },
403 { "PLP", 0x0000001, 0x28, 0, PutAll },
404 { "PLX", 0x0000001, 0xfa, 0, PutAll },
405 { "PLY", 0x0000001, 0x7a, 0, PutAll },
406 { "REP", 0x0800000, 0xc2, 1, PutREP },
407 { "ROL", 0x000006F, 0x22, 1, PutAll },
408 { "ROR", 0x000006F, 0x62, 1, PutAll },
409 { "RTI", 0x0000001, 0x40, 0, PutAll },
410 { "RTL", 0x0000001, 0x6b, 0, PutAll },
411 { "RTS", 0x0000001, 0x60, 0, PutRTS },
412 { "SBC", 0x0b8f6fc, 0xe0, 0, PutAll },
413 { "SEC", 0x0000001, 0x38, 0, PutAll },
414 { "SED", 0x0000001, 0xf8, 0, PutAll },
415 { "SEI", 0x0000001, 0x78, 0, PutAll },
416 { "SEP", 0x0800000, 0xe2, 1, PutSEP },
417 { "STA", 0x018f6fc, 0x80, 0, PutAll },
418 { "STP", 0x0000001, 0xdb, 0, PutAll },
419 { "STX", 0x000010c, 0x82, 1, PutAll },
420 { "STY", 0x000002c, 0x80, 1, PutAll },
421 { "STZ", 0x000006c, 0x04, 5, PutAll },
422 { "SWA", 0x0000001, 0xeb, 0, PutAll }, /* == XBA */
423 { "TAD", 0x0000001, 0x5b, 0, PutAll }, /* == TCD */
424 { "TAS", 0x0000001, 0x1b, 0, PutAll }, /* == TCS */
425 { "TAX", 0x0000001, 0xaa, 0, PutAll },
426 { "TAY", 0x0000001, 0xa8, 0, PutAll },
427 { "TCD", 0x0000001, 0x5b, 0, PutAll },
428 { "TCS", 0x0000001, 0x1b, 0, PutAll },
429 { "TDA", 0x0000001, 0x7b, 0, PutAll }, /* == TDC */
430 { "TDC", 0x0000001, 0x7b, 0, PutAll },
431 { "TRB", 0x000000c, 0x10, 1, PutAll },
432 { "TSA", 0x0000001, 0x3b, 0, PutAll }, /* == TSC */
433 { "TSB", 0x000000c, 0x00, 1, PutAll },
434 { "TSC", 0x0000001, 0x3b, 0, PutAll },
435 { "TSX", 0x0000001, 0xba, 0, PutAll },
436 { "TXA", 0x0000001, 0x8a, 0, PutAll },
437 { "TXS", 0x0000001, 0x9a, 0, PutAll },
438 { "TXY", 0x0000001, 0x9b, 0, PutAll },
439 { "TYA", 0x0000001, 0x98, 0, PutAll },
440 { "TYX", 0x0000001, 0xbb, 0, PutAll },
441 { "WAI", 0x0000001, 0xcb, 0, PutAll },
442 { "XBA", 0x0000001, 0xeb, 0, PutAll },
443 { "XCE", 0x0000001, 0xfb, 0, PutAll }
448 /* Table for the SUNPLUS CPU */
449 #include "sunplus.inc"
454 /* An array with instruction tables */
455 static const InsTable* InsTabs[CPU_COUNT] = {
456 (const InsTable*) &InsTab6502,
457 (const InsTable*) &InsTab65SC02,
458 (const InsTable*) &InsTab65C02,
459 (const InsTable*) &InsTab65816,
461 (const InsTable*) &InsTabSunPlus,
464 const InsTable* InsTab = (const InsTable*) &InsTab6502;
466 /* Table to build the effective opcode from a base opcode and an addressing
469 unsigned char EATab [9][AMI_COUNT] = {
471 0x00, 0x00, 0x05, 0x0D, 0x0F, 0x15, 0x1D, 0x1F,
472 0x00, 0x19, 0x12, 0x00, 0x07, 0x11, 0x17, 0x01,
473 0x00, 0x00, 0x00, 0x03, 0x13, 0x09, 0x00, 0x09,
477 0x08, 0x08, 0x04, 0x0C, 0x00, 0x14, 0x1C, 0x00,
478 0x14, 0x1C, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
479 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
483 0x00, 0x00, 0x24, 0x2C, 0x0F, 0x34, 0x3C, 0x00,
484 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
485 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00,
489 0x3A, 0x3A, 0xC6, 0xCE, 0x00, 0xD6, 0xDE, 0x00,
490 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
491 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
495 0x1A, 0x1A, 0xE6, 0xEE, 0x00, 0xF6, 0xFE, 0x00,
496 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
497 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
501 0x00, 0x00, 0x60, 0x98, 0x00, 0x70, 0x9E, 0x00,
502 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
503 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
507 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
508 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
509 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
513 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
514 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
515 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
519 0x00, 0x40, 0x01, 0x41, 0x00, 0x09, 0x49, 0x00,
520 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00,
521 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
526 /* Table that encodes the additional bytes for each instruction */
527 unsigned char ExtBytes [AMI_COUNT] = {
532 3, /* Absolute long */
535 3, /* Absolute long,X */
544 2, /* (Absolute,X) */
545 1, /* Relative short */
546 2, /* Relative long */
549 1, /* Immidiate accu */
550 1, /* Immidiate index */
551 1, /* Immidiate byte */
557 /*****************************************************************************/
558 /* Handler functions */
559 /*****************************************************************************/
563 static int EvalEA (const InsDesc* Ins, EffAddr* A)
564 /* Evaluate the effective address. All fields in A will be valid after calling
565 * this function. The function returns true on success and false on errors.
568 /* Get the set of possible addressing modes */
571 /* From the possible addressing modes, remove the ones that are invalid
572 * for this instruction or CPU.
574 A->AddrModeSet &= Ins->AddrMode;
576 /* If we have an expression, check it and remove any addressing modes that
577 * are too small for the expression size. Since we have to study the
578 * expression anyway, do also replace it by a simpler one if possible.
584 /* Study the expression */
585 StudyExpr (A->Expr, &ED);
587 /* Simplify it if possible */
588 A->Expr = SimplifyExpr (A->Expr, &ED);
590 /* If we don't know how big the expression is, assume the default
591 * address size for data.
593 if (ED.AddrSize == ADDR_SIZE_DEFAULT) {
594 ED.AddrSize = DataAddrSize;
598 switch (ED.AddrSize) {
601 A->AddrModeSet &= ~AM_SET_ZP;
605 A->AddrModeSet &= ~(AM_SET_ZP | AM_SET_ABS);
609 /* Free any resource associated with the expression desc */
613 /* Check if we have any adressing modes left */
614 if (A->AddrModeSet == 0) {
615 Error ("Illegal addressing mode");
618 A->AddrMode = BitFind (A->AddrModeSet);
619 A->AddrModeBit = (0x01UL << A->AddrMode);
621 /* If the instruction has a one byte operand and immediate addressing is
622 * allowed but not used, check for an operand expression in the form
623 * <label or >label, where label is a far or absolute label. If found,
624 * emit a warning. This warning protects against a typo, where the '#'
625 * for the immediate operand is omitted.
627 if (A->Expr && (Ins->AddrMode & AM_IMM) &&
628 (A->AddrModeSet & (AM_DIR | AM_ABS | AM_ABS_LONG)) &&
629 ExtBytes[A->AddrMode] == 1) {
631 /* Found, check the expression */
632 ExprNode* Left = A->Expr->Left;
633 if ((A->Expr->Op == EXPR_BYTE0 || A->Expr->Op == EXPR_BYTE1) &&
634 Left->Op == EXPR_SYMBOL &&
635 GetSymAddrSize (Left->V.Sym) != ADDR_SIZE_ZP) {
637 /* Output a warning */
638 Warning (1, "Suspicious address expression");
642 /* Build the opcode */
643 A->Opcode = Ins->BaseCode | EATab[Ins->ExtCode][A->AddrMode];
651 static void EmitCode (EffAddr* A)
652 /* Output code for the data in A */
654 /* Check how many extension bytes are needed and output the instruction */
655 switch (ExtBytes[A->AddrMode]) {
662 Emit1 (A->Opcode, A->Expr);
666 if (CPU == CPU_65816 && (A->AddrModeBit & (AM_ABS | AM_ABS_X | AM_ABS_Y))) {
667 /* This is a 16 bit mode that uses an address. If in 65816,
668 * mode, force this address into 16 bit range to allow
669 * addressing inside a 64K segment.
671 Emit2 (A->Opcode, GenWordExpr (A->Expr));
673 Emit2 (A->Opcode, A->Expr);
679 Emit3 (A->Opcode, A->Expr);
683 Internal ("Invalid operand byte count: %u", ExtBytes[A->AddrMode]);
690 static long PutImmed8 (const InsDesc* Ins)
691 /* Parse and emit an immediate 8 bit instruction. Return the value of the
692 * operand if it's available and const.
698 /* Evaluate the addressing mode */
699 if (EvalEA (Ins, &A) == 0) {
700 /* An error occurred */
704 /* If we have an expression and it's const, get it's value */
706 (void) IsConstExpr (A.Expr, &Val);
709 /* Check how many extension bytes are needed and output the instruction */
710 switch (ExtBytes[A.AddrMode]) {
713 Emit1 (A.Opcode, A.Expr);
717 Internal ("Invalid operand byte count: %u", ExtBytes[A.AddrMode]);
720 /* Return the expression value */
726 static void PutPCRel8 (const InsDesc* Ins)
727 /* Handle branches with a 8 bit distance */
729 EmitPCRel (Ins->BaseCode, GenBranchExpr (2), 1);
734 static void PutPCRel16 (const InsDesc* Ins)
735 /* Handle branches with an 16 bit distance and PER */
737 EmitPCRel (Ins->BaseCode, GenBranchExpr (3), 2);
742 static void PutBlockMove (const InsDesc* Ins)
743 /* Handle the blockmove instructions */
745 Emit0 (Ins->BaseCode);
746 EmitByte (Expression ());
748 EmitByte (Expression ());
753 static void PutBitBranch (const InsDesc* Ins)
754 /* Handle 65C02 branch on bit condition */
756 Emit0 (Ins->BaseCode);
757 EmitByte (Expression ());
759 EmitSigned (GenBranchExpr (1), 1);
764 static void PutREP (const InsDesc* Ins)
765 /* Emit a REP instruction, track register sizes */
767 /* Use the generic handler */
768 long Val = PutImmed8 (Ins);
770 /* We track the status only for the 816 CPU and in smart mode */
771 if (CPU == CPU_65816 && SmartMode) {
773 /* Check the range for Val. */
775 /* We had an error */
776 Warning (1, "Cannot track processor status byte");
779 /* Index registers to 16 bit */
780 ExtBytes[AMI_IMM_INDEX] = 2;
784 ExtBytes[AMI_IMM_ACCU] = 2;
792 static void PutSEP (const InsDesc* Ins)
793 /* Emit a SEP instruction, track register sizes */
795 /* Use the generic handler */
796 long Val = PutImmed8 (Ins);
798 /* We track the status only for the 816 CPU and in smart mode */
799 if (CPU == CPU_65816 && SmartMode) {
801 /* Check the range for Val. */
803 /* We had an error */
804 Warning (1, "Cannot track processor status byte");
807 /* Index registers to 8 bit */
808 ExtBytes [AMI_IMM_INDEX] = 1;
812 ExtBytes [AMI_IMM_ACCU] = 1;
820 static void PutJMP (const InsDesc* Ins)
821 /* Handle the jump instruction for the 6502. Problem is that these chips have
822 * a bug: If the address crosses a page, the upper byte gets not corrected and
823 * the instruction will fail. The PutJmp function will add a linker assertion
824 * to check for this case and is otherwise identical to PutAll.
829 /* Evaluate the addressing mode used */
830 if (EvalEA (Ins, &A)) {
832 /* Check for indirect addressing */
833 if (A.AddrModeBit & AM_ABS_IND) {
835 /* Compare the low byte of the expression to 0xFF to check for
836 * a page cross. Be sure to use a copy of the expression otherwise
837 * things will go weird later.
839 ExprNode* E = GenNE (GenByteExpr (CloneExpr (A.Expr)), 0xFF);
841 /* Generate the message */
842 unsigned Msg = GetStringId ("\"jmp (abs)\" across page border");
844 /* Generate the assertion */
845 AddAssertion (E, ASSERT_ACT_WARN, Msg);
848 /* No error, output code */
855 static void PutRTS (const InsDesc* Ins attribute ((unused)))
856 /* Handle the RTS instruction for the 816. In smart mode emit a RTL opcode if
857 * the enclosing scope is FAR.
860 if (SmartMode && CurrentScope->AddrSize == ADDR_SIZE_FAR) {
861 Emit0 (0x6B); /* RTL */
863 Emit0 (0x60); /* RTS */
869 static void PutAll (const InsDesc* Ins)
870 /* Handle all other instructions */
874 /* Evaluate the addressing mode used */
875 if (EvalEA (Ins, &A)) {
876 /* No error, output code */
883 /*****************************************************************************/
885 /*****************************************************************************/
889 static int CmpName (const void* Key, const void* Instr)
890 /* Compare function for bsearch */
892 return strcmp ((const char*)Key, ((const InsDesc*) Instr)->Mnemonic);
897 void SetCPU (cpu_t NewCPU)
900 /* Make sure the parameter is correct */
901 CHECK (NewCPU < CPU_COUNT);
903 /* Check if we have support for the new CPU, if so, use it */
904 if (InsTabs[NewCPU]) {
906 InsTab = InsTabs[CPU];
908 Error ("CPU not supported");
915 /* Return the current CPU */
922 int FindInstruction (const char* Ident)
923 /* Check if Ident is a valid mnemonic. If so, return the index in the
924 * instruction table. If not, return -1.
929 char Key[sizeof (ID->Mnemonic)];
931 /* Make a copy, and uppercase that copy */
933 while (Ident[I] != '\0') {
934 /* If the identifier is longer than the longest mnemonic, it cannot
937 if (I >= sizeof (Key) - 1) {
938 /* Not found, no need for further action */
941 Key[I] = toupper ((unsigned char)Ident[I]);
946 /* Search for the key */
947 ID = bsearch (Key, InsTab->Ins, InsTab->Count, sizeof (InsDesc), CmpName);
952 /* Found, return the entry */
953 return ID - InsTab->Ins;
959 void HandleInstruction (unsigned Index)
960 /* Handle the mnemonic with the given index */
963 PRECONDITION (Index < InsTab->Count);
965 /* Skip the mnemonic token */
968 /* Call the handler */
969 InsTab->Ins[Index].Emit (&InsTab->Ins[Index]);