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 /*****************************************************************************/
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 PutBitBranch (const InsDesc* Ins);
70 static void PutREP (const InsDesc* Ins);
71 static void PutSEP (const InsDesc* Ins);
72 static void PutJmp (const InsDesc* Ins);
73 static void PutAll (const InsDesc* Ins);
77 /* Instruction table for the 6502 */
78 #define INS_COUNT_6502 56
81 InsDesc Ins[INS_COUNT_6502];
85 { "ADC", 0x080A26C, 0x60, 0, PutAll },
86 { "AND", 0x080A26C, 0x20, 0, PutAll },
87 { "ASL", 0x000006e, 0x02, 1, PutAll },
88 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
89 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
90 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
91 { "BIT", 0x000000C, 0x00, 2, PutAll },
92 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
93 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
94 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
95 { "BRK", 0x0000001, 0x00, 0, PutAll },
96 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
97 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
98 { "CLC", 0x0000001, 0x18, 0, PutAll },
99 { "CLD", 0x0000001, 0xd8, 0, PutAll },
100 { "CLI", 0x0000001, 0x58, 0, PutAll },
101 { "CLV", 0x0000001, 0xb8, 0, PutAll },
102 { "CMP", 0x080A26C, 0xc0, 0, PutAll },
103 { "CPX", 0x080000C, 0xe0, 1, PutAll },
104 { "CPY", 0x080000C, 0xc0, 1, PutAll },
105 { "DEC", 0x000006C, 0x00, 3, PutAll },
106 { "DEX", 0x0000001, 0xca, 0, PutAll },
107 { "DEY", 0x0000001, 0x88, 0, PutAll },
108 { "EOR", 0x080A26C, 0x40, 0, PutAll },
109 { "INC", 0x000006c, 0x00, 4, PutAll },
110 { "INX", 0x0000001, 0xe8, 0, PutAll },
111 { "INY", 0x0000001, 0xc8, 0, PutAll },
112 { "JMP", 0x0000808, 0x4c, 6, PutJmp },
113 { "JSR", 0x0000008, 0x20, 7, PutAll },
114 { "LDA", 0x080A26C, 0xa0, 0, PutAll },
115 { "LDX", 0x080030C, 0xa2, 1, PutAll },
116 { "LDY", 0x080006C, 0xa0, 1, PutAll },
117 { "LSR", 0x000006F, 0x42, 1, PutAll },
118 { "NOP", 0x0000001, 0xea, 0, PutAll },
119 { "ORA", 0x080A26C, 0x00, 0, PutAll },
120 { "PHA", 0x0000001, 0x48, 0, PutAll },
121 { "PHP", 0x0000001, 0x08, 0, PutAll },
122 { "PLA", 0x0000001, 0x68, 0, PutAll },
123 { "PLP", 0x0000001, 0x28, 0, PutAll },
124 { "ROL", 0x000006F, 0x22, 1, PutAll },
125 { "ROR", 0x000006F, 0x62, 1, PutAll },
126 { "RTI", 0x0000001, 0x40, 0, PutAll },
127 { "RTS", 0x0000001, 0x60, 0, PutAll },
128 { "SBC", 0x080A26C, 0xe0, 0, PutAll },
129 { "SEC", 0x0000001, 0x38, 0, PutAll },
130 { "SED", 0x0000001, 0xf8, 0, PutAll },
131 { "SEI", 0x0000001, 0x78, 0, PutAll },
132 { "STA", 0x000A26C, 0x80, 0, PutAll },
133 { "STX", 0x000010c, 0x82, 1, PutAll },
134 { "STY", 0x000002c, 0x80, 1, PutAll },
135 { "TAX", 0x0000001, 0xaa, 0, PutAll },
136 { "TAY", 0x0000001, 0xa8, 0, PutAll },
137 { "TSX", 0x0000001, 0xba, 0, PutAll },
138 { "TXA", 0x0000001, 0x8a, 0, PutAll },
139 { "TXS", 0x0000001, 0x9a, 0, PutAll },
140 { "TYA", 0x0000001, 0x98, 0, PutAll }
144 /* Instruction table for the 65SC02 */
145 #define INS_COUNT_65SC02 66
146 static const struct {
148 InsDesc Ins[INS_COUNT_65SC02];
152 { "ADC", 0x080A66C, 0x60, 0, PutAll },
153 { "AND", 0x080A66C, 0x20, 0, PutAll },
154 { "ASL", 0x000006e, 0x02, 1, PutAll },
155 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
156 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
157 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
158 { "BIT", 0x0A0006C, 0x00, 2, PutAll },
159 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
160 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
161 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
162 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
163 { "BRK", 0x0000001, 0x00, 0, PutAll },
164 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
165 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
166 { "CLC", 0x0000001, 0x18, 0, PutAll },
167 { "CLD", 0x0000001, 0xd8, 0, PutAll },
168 { "CLI", 0x0000001, 0x58, 0, PutAll },
169 { "CLV", 0x0000001, 0xb8, 0, PutAll },
170 { "CMP", 0x080A66C, 0xc0, 0, PutAll },
171 { "CPX", 0x080000C, 0xe0, 1, PutAll },
172 { "CPY", 0x080000C, 0xc0, 1, PutAll },
173 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
174 { "DEC", 0x000006F, 0x00, 3, PutAll },
175 { "DEX", 0x0000001, 0xca, 0, PutAll },
176 { "DEY", 0x0000001, 0x88, 0, PutAll },
177 { "EOR", 0x080A66C, 0x40, 0, PutAll },
178 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
179 { "INC", 0x000006f, 0x00, 4, PutAll },
180 { "INX", 0x0000001, 0xe8, 0, PutAll },
181 { "INY", 0x0000001, 0xc8, 0, PutAll },
182 { "JMP", 0x0010808, 0x4c, 6, PutAll },
183 { "JSR", 0x0000008, 0x20, 7, PutAll },
184 { "LDA", 0x080A66C, 0xa0, 0, PutAll },
185 { "LDX", 0x080030C, 0xa2, 1, PutAll },
186 { "LDY", 0x080006C, 0xa0, 1, PutAll },
187 { "LSR", 0x000006F, 0x42, 1, PutAll },
188 { "NOP", 0x0000001, 0xea, 0, PutAll },
189 { "ORA", 0x080A66C, 0x00, 0, PutAll },
190 { "PHA", 0x0000001, 0x48, 0, PutAll },
191 { "PHP", 0x0000001, 0x08, 0, PutAll },
192 { "PHX", 0x0000001, 0xda, 0, PutAll },
193 { "PHY", 0x0000001, 0x5a, 0, PutAll },
194 { "PLA", 0x0000001, 0x68, 0, PutAll },
195 { "PLP", 0x0000001, 0x28, 0, PutAll },
196 { "PLX", 0x0000001, 0xfa, 0, PutAll },
197 { "PLY", 0x0000001, 0x7a, 0, PutAll },
198 { "ROL", 0x000006F, 0x22, 1, PutAll },
199 { "ROR", 0x000006F, 0x62, 1, PutAll },
200 { "RTI", 0x0000001, 0x40, 0, PutAll },
201 { "RTS", 0x0000001, 0x60, 0, PutAll },
202 { "SBC", 0x080A66C, 0xe0, 0, PutAll },
203 { "SEC", 0x0000001, 0x38, 0, PutAll },
204 { "SED", 0x0000001, 0xf8, 0, PutAll },
205 { "SEI", 0x0000001, 0x78, 0, PutAll },
206 { "STA", 0x000A66C, 0x80, 0, PutAll },
207 { "STX", 0x000010c, 0x82, 1, PutAll },
208 { "STY", 0x000002c, 0x80, 1, PutAll },
209 { "STZ", 0x000006c, 0x04, 5, PutAll },
210 { "TAX", 0x0000001, 0xaa, 0, PutAll },
211 { "TAY", 0x0000001, 0xa8, 0, PutAll },
212 { "TRB", 0x000000c, 0x10, 1, PutAll },
213 { "TSB", 0x000000c, 0x00, 1, PutAll },
214 { "TSX", 0x0000001, 0xba, 0, PutAll },
215 { "TXA", 0x0000001, 0x8a, 0, PutAll },
216 { "TXS", 0x0000001, 0x9a, 0, PutAll },
217 { "TYA", 0x0000001, 0x98, 0, PutAll }
221 /* Instruction table for the 65C02 */
222 #define INS_COUNT_65C02 98
223 static const struct {
225 InsDesc Ins[INS_COUNT_65C02];
229 { "ADC", 0x080A66C, 0x60, 0, PutAll },
230 { "AND", 0x080A66C, 0x20, 0, PutAll },
231 { "ASL", 0x000006e, 0x02, 1, PutAll },
232 { "BBR0", 0x0000000, 0x0F, 0, PutBitBranch },
233 { "BBR1", 0x0000000, 0x1F, 0, PutBitBranch },
234 { "BBR2", 0x0000000, 0x2F, 0, PutBitBranch },
235 { "BBR3", 0x0000000, 0x3F, 0, PutBitBranch },
236 { "BBR4", 0x0000000, 0x4F, 0, PutBitBranch },
237 { "BBR5", 0x0000000, 0x5F, 0, PutBitBranch },
238 { "BBR6", 0x0000000, 0x6F, 0, PutBitBranch },
239 { "BBR7", 0x0000000, 0x7F, 0, PutBitBranch },
240 { "BBS0", 0x0000000, 0x8F, 0, PutBitBranch },
241 { "BBS1", 0x0000000, 0x9F, 0, PutBitBranch },
242 { "BBS2", 0x0000000, 0xAF, 0, PutBitBranch },
243 { "BBS3", 0x0000000, 0xBF, 0, PutBitBranch },
244 { "BBS4", 0x0000000, 0xCF, 0, PutBitBranch },
245 { "BBS5", 0x0000000, 0xDF, 0, PutBitBranch },
246 { "BBS6", 0x0000000, 0xEF, 0, PutBitBranch },
247 { "BBS7", 0x0000000, 0xFF, 0, PutBitBranch },
248 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
249 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
250 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
251 { "BIT", 0x0A0006C, 0x00, 2, PutAll },
252 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
253 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
254 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
255 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
256 { "BRK", 0x0000001, 0x00, 0, PutAll },
257 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
258 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
259 { "CLC", 0x0000001, 0x18, 0, PutAll },
260 { "CLD", 0x0000001, 0xd8, 0, PutAll },
261 { "CLI", 0x0000001, 0x58, 0, PutAll },
262 { "CLV", 0x0000001, 0xb8, 0, PutAll },
263 { "CMP", 0x080A66C, 0xc0, 0, PutAll },
264 { "CPX", 0x080000C, 0xe0, 1, PutAll },
265 { "CPY", 0x080000C, 0xc0, 1, PutAll },
266 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
267 { "DEC", 0x000006F, 0x00, 3, PutAll },
268 { "DEX", 0x0000001, 0xca, 0, PutAll },
269 { "DEY", 0x0000001, 0x88, 0, PutAll },
270 { "EOR", 0x080A66C, 0x40, 0, PutAll },
271 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
272 { "INC", 0x000006f, 0x00, 4, PutAll },
273 { "INX", 0x0000001, 0xe8, 0, PutAll },
274 { "INY", 0x0000001, 0xc8, 0, PutAll },
275 { "JMP", 0x0010808, 0x4c, 6, PutAll },
276 { "JSR", 0x0000008, 0x20, 7, PutAll },
277 { "LDA", 0x080A66C, 0xa0, 0, PutAll },
278 { "LDX", 0x080030C, 0xa2, 1, PutAll },
279 { "LDY", 0x080006C, 0xa0, 1, PutAll },
280 { "LSR", 0x000006F, 0x42, 1, PutAll },
281 { "NOP", 0x0000001, 0xea, 0, PutAll },
282 { "ORA", 0x080A66C, 0x00, 0, PutAll },
283 { "PHA", 0x0000001, 0x48, 0, PutAll },
284 { "PHP", 0x0000001, 0x08, 0, PutAll },
285 { "PHX", 0x0000001, 0xda, 0, PutAll },
286 { "PHY", 0x0000001, 0x5a, 0, PutAll },
287 { "PLA", 0x0000001, 0x68, 0, PutAll },
288 { "PLP", 0x0000001, 0x28, 0, PutAll },
289 { "PLX", 0x0000001, 0xfa, 0, PutAll },
290 { "PLY", 0x0000001, 0x7a, 0, PutAll },
291 { "RMB0", 0x0000004, 0x07, 1, PutAll },
292 { "RMB1", 0x0000004, 0x17, 1, PutAll },
293 { "RMB2", 0x0000004, 0x27, 1, PutAll },
294 { "RMB3", 0x0000004, 0x37, 1, PutAll },
295 { "RMB4", 0x0000004, 0x47, 1, PutAll },
296 { "RMB5", 0x0000004, 0x57, 1, PutAll },
297 { "RMB6", 0x0000004, 0x67, 1, PutAll },
298 { "RMB7", 0x0000004, 0x77, 1, PutAll },
299 { "ROL", 0x000006F, 0x22, 1, PutAll },
300 { "ROR", 0x000006F, 0x62, 1, PutAll },
301 { "RTI", 0x0000001, 0x40, 0, PutAll },
302 { "RTS", 0x0000001, 0x60, 0, PutAll },
303 { "SBC", 0x080A66C, 0xe0, 0, PutAll },
304 { "SEC", 0x0000001, 0x38, 0, PutAll },
305 { "SED", 0x0000001, 0xf8, 0, PutAll },
306 { "SEI", 0x0000001, 0x78, 0, PutAll },
307 { "SMB0", 0x0000004, 0x87, 1, PutAll },
308 { "SMB1", 0x0000004, 0x97, 1, PutAll },
309 { "SMB2", 0x0000004, 0xA7, 1, PutAll },
310 { "SMB3", 0x0000004, 0xB7, 1, PutAll },
311 { "SMB4", 0x0000004, 0xC7, 1, PutAll },
312 { "SMB5", 0x0000004, 0xD7, 1, PutAll },
313 { "SMB6", 0x0000004, 0xE7, 1, PutAll },
314 { "SMB7", 0x0000004, 0xF7, 1, PutAll },
315 { "STA", 0x000A66C, 0x80, 0, PutAll },
316 { "STX", 0x000010c, 0x82, 1, PutAll },
317 { "STY", 0x000002c, 0x80, 1, PutAll },
318 { "STZ", 0x000006c, 0x04, 5, PutAll },
319 { "TAX", 0x0000001, 0xaa, 0, PutAll },
320 { "TAY", 0x0000001, 0xa8, 0, PutAll },
321 { "TRB", 0x000000c, 0x10, 1, PutAll },
322 { "TSB", 0x000000c, 0x00, 1, PutAll },
323 { "TSX", 0x0000001, 0xba, 0, PutAll },
324 { "TXA", 0x0000001, 0x8a, 0, PutAll },
325 { "TXS", 0x0000001, 0x9a, 0, PutAll },
326 { "TYA", 0x0000001, 0x98, 0, PutAll }
330 /* Instruction table for the 65816 */
331 #define INS_COUNT_65816 101
332 static const struct {
334 InsDesc Ins[INS_COUNT_65816];
338 { "ADC", 0x0b8f6fc, 0x60, 0, PutAll },
339 { "AND", 0x0b8f6fc, 0x20, 0, PutAll },
340 { "ASL", 0x000006e, 0x02, 1, PutAll },
341 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
342 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
343 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
344 { "BGE", 0x0020000, 0xb0, 0, PutPCRel8 }, /* == BCS */
345 { "BIT", 0x0a0006c, 0x00, 2, PutAll },
346 { "BLT", 0x0020000, 0x90, 0, PutPCRel8 }, /* == BCC */
347 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
348 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
349 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
350 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
351 { "BRK", 0x0000001, 0x00, 0, PutAll },
352 { "BRL", 0x0040000, 0x82, 0, PutPCRel16 },
353 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
354 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
355 { "CLC", 0x0000001, 0x18, 0, PutAll },
356 { "CLD", 0x0000001, 0xd8, 0, PutAll },
357 { "CLI", 0x0000001, 0x58, 0, PutAll },
358 { "CLV", 0x0000001, 0xb8, 0, PutAll },
359 { "CMP", 0x0b8f6fc, 0xc0, 0, PutAll },
360 { "COP", 0x0000004, 0x02, 6, PutAll },
361 { "CPA", 0x0b8f6fc, 0xc0, 0, PutAll }, /* == CMP */
362 { "CPX", 0x0c0000c, 0xe0, 1, PutAll },
363 { "CPY", 0x0c0000c, 0xc0, 1, PutAll },
364 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
365 { "DEC", 0x000006F, 0x00, 3, PutAll },
366 { "DEX", 0x0000001, 0xca, 0, PutAll },
367 { "DEY", 0x0000001, 0x88, 0, PutAll },
368 { "EOR", 0x0b8f6fc, 0x40, 0, PutAll },
369 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
370 { "INC", 0x000006F, 0x00, 4, PutAll },
371 { "INX", 0x0000001, 0xe8, 0, PutAll },
372 { "INY", 0x0000001, 0xc8, 0, PutAll },
373 { "JML", 0x0000810, 0x5c, 1, PutAll },
374 { "JMP", 0x0010818, 0x4c, 6, PutAll },
375 { "JSL", 0x0000010, 0x20, 7, PutAll },
376 { "JSR", 0x0010018, 0x20, 7, PutAll },
377 { "LDA", 0x0b8f6fc, 0xa0, 0, PutAll },
378 { "LDX", 0x0c0030c, 0xa2, 1, PutAll },
379 { "LDY", 0x0c0006c, 0xa0, 1, PutAll },
380 { "LSR", 0x000006F, 0x42, 1, PutAll },
381 { "MVN", 0x1000000, 0x54, 0, PutBlockMove },
382 { "MVP", 0x1000000, 0x44, 0, PutBlockMove },
383 { "NOP", 0x0000001, 0xea, 0, PutAll },
384 { "ORA", 0x0b8f6fc, 0x00, 0, PutAll },
385 { "PEA", 0x0000008, 0xf4, 6, PutAll },
386 { "PEI", 0x0000400, 0xd4, 1, PutAll },
387 { "PER", 0x0040000, 0x62, 0, PutPCRel16 },
388 { "PHA", 0x0000001, 0x48, 0, PutAll },
389 { "PHB", 0x0000001, 0x8b, 0, PutAll },
390 { "PHD", 0x0000001, 0x0b, 0, PutAll },
391 { "PHK", 0x0000001, 0x4b, 0, PutAll },
392 { "PHP", 0x0000001, 0x08, 0, PutAll },
393 { "PHX", 0x0000001, 0xda, 0, PutAll },
394 { "PHY", 0x0000001, 0x5a, 0, PutAll },
395 { "PLA", 0x0000001, 0x68, 0, PutAll },
396 { "PLB", 0x0000001, 0xab, 0, PutAll },
397 { "PLD", 0x0000001, 0x2b, 0, PutAll },
398 { "PLP", 0x0000001, 0x28, 0, PutAll },
399 { "PLX", 0x0000001, 0xfa, 0, PutAll },
400 { "PLY", 0x0000001, 0x7a, 0, PutAll },
401 { "REP", 0x0800000, 0xc2, 1, PutREP },
402 { "ROL", 0x000006F, 0x22, 1, PutAll },
403 { "ROR", 0x000006F, 0x62, 1, PutAll },
404 { "RTI", 0x0000001, 0x40, 0, PutAll },
405 { "RTL", 0x0000001, 0x6b, 0, PutAll },
406 { "RTS", 0x0000001, 0x60, 0, PutAll },
407 { "SBC", 0x0b8f6fc, 0xe0, 0, PutAll },
408 { "SEC", 0x0000001, 0x38, 0, PutAll },
409 { "SED", 0x0000001, 0xf8, 0, PutAll },
410 { "SEI", 0x0000001, 0x78, 0, PutAll },
411 { "SEP", 0x0800000, 0xe2, 1, PutSEP },
412 { "STA", 0x018f6fc, 0x80, 0, PutAll },
413 { "STP", 0x0000001, 0xdb, 0, PutAll },
414 { "STX", 0x000010c, 0x82, 1, PutAll },
415 { "STY", 0x000002c, 0x80, 1, PutAll },
416 { "STZ", 0x000006c, 0x04, 5, PutAll },
417 { "SWA", 0x0000001, 0xeb, 0, PutAll }, /* == XBA */
418 { "TAD", 0x0000001, 0x5b, 0, PutAll }, /* == TCD */
419 { "TAS", 0x0000001, 0x1b, 0, PutAll }, /* == TCS */
420 { "TAX", 0x0000001, 0xaa, 0, PutAll },
421 { "TAY", 0x0000001, 0xa8, 0, PutAll },
422 { "TCD", 0x0000001, 0x5b, 0, PutAll },
423 { "TCS", 0x0000001, 0x1b, 0, PutAll },
424 { "TDA", 0x0000001, 0x7b, 0, PutAll }, /* == TDC */
425 { "TDC", 0x0000001, 0x7b, 0, PutAll },
426 { "TRB", 0x000000c, 0x10, 1, PutAll },
427 { "TSA", 0x0000001, 0x3b, 0, PutAll }, /* == TSC */
428 { "TSB", 0x000000c, 0x00, 1, PutAll },
429 { "TSC", 0x0000001, 0x3b, 0, PutAll },
430 { "TSX", 0x0000001, 0xba, 0, PutAll },
431 { "TXA", 0x0000001, 0x8a, 0, PutAll },
432 { "TXS", 0x0000001, 0x9a, 0, PutAll },
433 { "TXY", 0x0000001, 0x9b, 0, PutAll },
434 { "TYA", 0x0000001, 0x98, 0, PutAll },
435 { "TYX", 0x0000001, 0xbb, 0, PutAll },
436 { "WAI", 0x0000001, 0xcb, 0, PutAll },
437 { "XBA", 0x0000001, 0xeb, 0, PutAll },
438 { "XCE", 0x0000001, 0xfb, 0, PutAll }
443 /* Table for the SUNPLUS CPU */
444 #include "sunplus.inc"
449 /* An array with instruction tables */
450 static const InsTable* InsTabs[CPU_COUNT] = {
451 (const InsTable*) &InsTab6502,
452 (const InsTable*) &InsTab65SC02,
453 (const InsTable*) &InsTab65C02,
454 (const InsTable*) &InsTab65816,
456 (const InsTable*) &InsTabSunPlus,
459 const InsTable* InsTab = (const InsTable*) &InsTab6502;
461 /* Table to build the effective opcode from a base opcode and an addressing
464 unsigned char EATab [9][AMI_COUNT] = {
466 0x00, 0x00, 0x05, 0x0D, 0x0F, 0x15, 0x1D, 0x1F,
467 0x00, 0x19, 0x12, 0x00, 0x07, 0x11, 0x17, 0x01,
468 0x00, 0x00, 0x00, 0x03, 0x13, 0x09, 0x00, 0x09,
472 0x08, 0x08, 0x04, 0x0C, 0x00, 0x14, 0x1C, 0x00,
473 0x14, 0x1C, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
474 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
478 0x00, 0x00, 0x24, 0x2C, 0x0F, 0x34, 0x3C, 0x00,
479 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
480 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00,
484 0x3A, 0x3A, 0xC6, 0xCE, 0x00, 0xD6, 0xDE, 0x00,
485 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
486 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
490 0x1A, 0x1A, 0xE6, 0xEE, 0x00, 0xF6, 0xFE, 0x00,
491 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
492 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
496 0x00, 0x00, 0x60, 0x98, 0x00, 0x70, 0x9E, 0x00,
497 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
498 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
502 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
503 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
504 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
508 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
509 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
510 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
514 0x00, 0x40, 0x01, 0x41, 0x00, 0x09, 0x49, 0x00,
515 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00,
516 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
521 /* Table that encodes the additional bytes for each instruction */
522 unsigned char ExtBytes [AMI_COUNT] = {
527 3, /* Absolute long */
530 3, /* Absolute long,X */
539 2, /* (Absolute,X) */
540 1, /* Relative short */
541 2, /* Relative long */
544 1, /* Immidiate accu */
545 1, /* Immidiate index */
546 1, /* Immidiate byte */
552 /*****************************************************************************/
553 /* Handler functions */
554 /*****************************************************************************/
558 static int EvalEA (const InsDesc* Ins, EffAddr* A)
559 /* Evaluate the effective address. All fields in A will be valid after calling
560 * this function. The function returns true on success and false on errors.
563 /* Get the set of possible addressing modes */
566 /* From the possible addressing modes, remove the ones that are invalid
567 * for this instruction or CPU.
569 A->AddrModeSet &= Ins->AddrMode;
571 /* If we have possible zero page addressing modes, and the expression
572 * involved (if any) is not in byte range, remove the zero page addressing
575 if (A->Expr && (A->AddrModeSet & AM_ZP) && !IsByteExpr (A->Expr)) {
576 A->AddrModeSet &= ~AM_ZP;
579 /* Check if we have any adressing modes left */
580 if (A->AddrModeSet == 0) {
581 Error ("Illegal addressing mode");
584 A->AddrMode = BitFind (A->AddrModeSet);
585 A->AddrModeBit = (0x01UL << A->AddrMode);
587 /* If the instruction has a one byte operand and immediate addressing is
588 * allowed but not used, check for an operand expression in the form
589 * <label or >label, where label is a far or absolute label. If found,
590 * emit a warning. This warning protects against a typo, where the '#'
591 * for the immediate operand is omitted.
593 if (A->Expr && (Ins->AddrMode & AM_IMM) &&
594 (A->AddrModeSet & (AM_DIR | AM_ABS | AM_ABS_LONG)) &&
595 ExtBytes[A->AddrMode] == 1) {
597 /* Found, check the expression */
598 ExprNode* Left = A->Expr->Left;
599 if ((A->Expr->Op == EXPR_BYTE0 || A->Expr->Op == EXPR_BYTE1) &&
600 Left->Op == EXPR_SYMBOL &&
601 !SymIsZP (Left->V.Sym)) {
603 /* Output a warning */
604 Warning (1, "Suspicious address expression");
608 /* Build the opcode */
609 A->Opcode = Ins->BaseCode | EATab[Ins->ExtCode][A->AddrMode];
617 static void EmitCode (EffAddr* A)
618 /* Output code for the data in A */
620 /* Check how many extension bytes are needed and output the instruction */
621 switch (ExtBytes[A->AddrMode]) {
628 Emit1 (A->Opcode, A->Expr);
632 if (CPU == CPU_65816 && (A->AddrModeBit & (AM_ABS | AM_ABS_X | AM_ABS_Y))) {
633 /* This is a 16 bit mode that uses an address. If in 65816,
634 * mode, force this address into 16 bit range to allow
635 * addressing inside a 64K segment.
637 Emit2 (A->Opcode, GenWordExpr (A->Expr));
639 Emit2 (A->Opcode, A->Expr);
645 /* Separate bank given */
646 Emit3b (A->Opcode, A->Expr, A->Bank);
648 /* One far argument */
649 Emit3 (A->Opcode, A->Expr);
654 Internal ("Invalid operand byte count: %u", ExtBytes[A->AddrMode]);
661 static long PutImmed8 (const InsDesc* Ins)
662 /* Parse and emit an immediate 8 bit instruction. Return the value of the
663 * operand if it's available and const.
669 /* Evaluate the addressing mode */
670 if (EvalEA (Ins, &A) == 0) {
671 /* An error occurred */
675 /* If we have an expression and it's const, get it's value */
677 (void) IsConstExpr (A.Expr, &Val);
680 /* Check how many extension bytes are needed and output the instruction */
681 switch (ExtBytes[A.AddrMode]) {
684 Emit1 (A.Opcode, A.Expr);
688 Internal ("Invalid operand byte count: %u", ExtBytes[A.AddrMode]);
691 /* Return the expression value */
697 static void PutPCRel8 (const InsDesc* Ins)
698 /* Handle branches with a 8 bit distance */
700 EmitPCRel (Ins->BaseCode, GenBranchExpr (2), 1);
705 static void PutPCRel16 (const InsDesc* Ins)
706 /* Handle branches with an 16 bit distance and PER */
708 EmitPCRel (Ins->BaseCode, GenBranchExpr (3), 2);
713 static void PutBlockMove (const InsDesc* Ins)
714 /* Handle the blockmove instructions */
716 Emit0 (Ins->BaseCode);
717 EmitByte (Expression ());
719 EmitByte (Expression ());
724 static void PutBitBranch (const InsDesc* Ins)
725 /* Handle 65C02 branch on bit condition */
727 Emit0 (Ins->BaseCode);
728 EmitByte (Expression ());
730 EmitSigned (GenBranchExpr (1), 1);
735 static void PutREP (const InsDesc* Ins)
736 /* Emit a REP instruction, track register sizes */
738 /* Use the generic handler */
739 long Val = PutImmed8 (Ins);
741 /* We track the status only for the 816 CPU and in smart mode */
742 if (CPU == CPU_65816 && SmartMode) {
744 /* Check the range for Val. */
746 /* We had an error */
747 Warning (1, "Cannot track processor status byte");
750 /* Index registers to 16 bit */
751 ExtBytes[AMI_IMM_INDEX] = 2;
755 ExtBytes[AMI_IMM_ACCU] = 2;
763 static void PutSEP (const InsDesc* Ins)
764 /* Emit a SEP instruction, track register sizes */
766 /* Use the generic handler */
767 long Val = PutImmed8 (Ins);
769 /* We track the status only for the 816 CPU and in smart mode */
770 if (CPU == CPU_65816 && SmartMode) {
772 /* Check the range for Val. */
774 /* We had an error */
775 Warning (1, "Cannot track processor status byte");
778 /* Index registers to 8 bit */
779 ExtBytes [AMI_IMM_INDEX] = 1;
783 ExtBytes [AMI_IMM_ACCU] = 1;
791 static void PutJmp (const InsDesc* Ins)
792 /* Handle the jump instruction for the 6502. Problem is that these chips have
793 * a bug: If the address crosses a page, the upper byte gets not corrected and
794 * the instruction will fail. The PutJmp function will add a linker assertion
795 * to check for this case and is otherwise identical to PutAll.
800 /* Evaluate the addressing mode used */
801 if (EvalEA (Ins, &A)) {
803 /* Check for indirect addressing */
804 if (A.AddrModeBit & AM_ABS_IND) {
806 /* Compare the low byte of the expression to 0xFF to check for
807 * a page cross. Be sure to use a copy of the expression otherwise
808 * things will go weird later.
810 ExprNode* E = GenNE (GenByteExpr (CloneExpr (A.Expr)), 0xFF);
812 /* Generate the message */
813 unsigned Msg = GetStringId ("\"jmp (abs)\" across page border");
815 /* Generate the assertion */
816 AddAssertion (E, ASSERT_ACT_WARN, Msg);
819 /* No error, output code */
826 static void PutAll (const InsDesc* Ins)
827 /* Handle all other instructions */
831 /* Evaluate the addressing mode used */
832 if (EvalEA (Ins, &A)) {
833 /* No error, output code */
840 /*****************************************************************************/
842 /*****************************************************************************/
846 static int CmpName (const void* Key, const void* Instr)
847 /* Compare function for bsearch */
849 return strcmp ((const char*)Key, ((const InsDesc*) Instr)->Mnemonic);
854 void SetCPU (cpu_t NewCPU)
857 /* Make sure the parameter is correct */
858 CHECK (NewCPU < CPU_COUNT);
860 /* Check if we have support for the new CPU, if so, use it */
861 if (InsTabs[NewCPU]) {
863 InsTab = InsTabs[CPU];
865 Error ("CPU not supported");
872 /* Return the current CPU */
879 int FindInstruction (const char* Ident)
880 /* Check if Ident is a valid mnemonic. If so, return the index in the
881 * instruction table. If not, return -1.
886 char Key[sizeof (ID->Mnemonic)];
888 /* Make a copy, and uppercase that copy */
890 while (Ident[I] != '\0') {
891 /* If the identifier is longer than the longest mnemonic, it cannot
894 if (I >= sizeof (Key) - 1) {
895 /* Not found, no need for further action */
898 Key[I] = toupper ((unsigned char)Ident[I]);
903 /* Search for the key */
904 ID = bsearch (Key, InsTab->Ins, InsTab->Count, sizeof (InsDesc), CmpName);
909 /* Found, return the entry */
910 return ID - InsTab->Ins;
916 void HandleInstruction (unsigned Index)
917 /* Handle the mnemonic with the given index */
920 PRECONDITION (Index < InsTab->Count);
922 /* Skip the mnemonic token */
925 /* Call the handler */
926 InsTab->Ins[Index].Emit (&InsTab->Ins[Index]);