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 70
151 static const struct {
153 InsDesc Ins[INS_COUNT_6502X];
157 { "ADC", 0x080A26C, 0x60, 0, PutAll },
158 { "ALR", 0x0800000, 0x4B, 0, PutAll }, /* X */
159 { "ANC", 0x0800000, 0x0B, 0, PutAll }, /* X */
160 { "AND", 0x080A26C, 0x20, 0, PutAll },
161 { "ARR", 0x0800000, 0x6B, 0, PutAll }, /* X */
162 { "ASL", 0x000006e, 0x02, 1, PutAll },
163 { "AXS", 0x0800000, 0xCB, 0, PutAll }, /* X */
164 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
165 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
166 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
167 { "BIT", 0x000000C, 0x00, 2, PutAll },
168 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
169 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
170 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
171 { "BRK", 0x0000001, 0x00, 0, PutAll },
172 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
173 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
174 { "CLC", 0x0000001, 0x18, 0, PutAll },
175 { "CLD", 0x0000001, 0xd8, 0, PutAll },
176 { "CLI", 0x0000001, 0x58, 0, PutAll },
177 { "CLV", 0x0000001, 0xb8, 0, PutAll },
178 { "CMP", 0x080A26C, 0xc0, 0, PutAll },
179 { "CPX", 0x080000C, 0xe0, 1, PutAll },
180 { "CPY", 0x080000C, 0xc0, 1, PutAll },
181 { "DCP", 0x000A26C, 0xC3, 0, PutAll }, /* X */
182 { "DEC", 0x000006C, 0x00, 3, PutAll },
183 { "DEX", 0x0000001, 0xca, 0, PutAll },
184 { "DEY", 0x0000001, 0x88, 0, PutAll },
185 { "EOR", 0x080A26C, 0x40, 0, PutAll },
186 { "INC", 0x000006c, 0x00, 4, PutAll },
187 { "INX", 0x0000001, 0xe8, 0, PutAll },
188 { "INY", 0x0000001, 0xc8, 0, PutAll },
189 { "ISC", 0x000A26C, 0xE3, 0, PutAll }, /* X */
190 { "JAM", 0x0000001, 0x02, 0, PutAll }, /* X */
191 { "JMP", 0x0000808, 0x4c, 6, PutJMP },
192 { "JSR", 0x0000008, 0x20, 7, PutAll },
193 { "LAS", 0x0000200, 0xBB, 0, PutAll }, /* X */
194 { "LAX", 0x000A30C, 0xA3, 1, PutAll }, /* X */
195 { "LDA", 0x080A26C, 0xa0, 0, PutAll },
196 { "LDX", 0x080030C, 0xa2, 1, PutAll },
197 { "LDY", 0x080006C, 0xa0, 1, PutAll },
198 { "LSR", 0x000006F, 0x42, 1, PutAll },
199 { "NOP", 0x0000001, 0xea, 0, PutAll },
200 { "ORA", 0x080A26C, 0x00, 0, PutAll },
201 { "PHA", 0x0000001, 0x48, 0, PutAll },
202 { "PHP", 0x0000001, 0x08, 0, PutAll },
203 { "PLA", 0x0000001, 0x68, 0, PutAll },
204 { "PLP", 0x0000001, 0x28, 0, PutAll },
205 { "RLA", 0x000A26C, 0x23, 0, PutAll }, /* X */
206 { "ROL", 0x000006F, 0x22, 1, PutAll },
207 { "ROR", 0x000006F, 0x62, 1, PutAll },
208 { "RRA", 0x000A26C, 0x63, 0, PutAll }, /* X */
209 { "RTI", 0x0000001, 0x40, 0, PutAll },
210 { "RTS", 0x0000001, 0x60, 0, PutAll },
211 { "SAX", 0x000810C, 0x83, 1, PutAll }, /* X */
212 { "SBC", 0x080A26C, 0xe0, 0, PutAll },
213 { "SEC", 0x0000001, 0x38, 0, PutAll },
214 { "SED", 0x0000001, 0xf8, 0, PutAll },
215 { "SEI", 0x0000001, 0x78, 0, PutAll },
216 { "SLO", 0x000A26C, 0x03, 0, PutAll }, /* X */
217 { "SRE", 0x000A26C, 0x43, 0, PutAll }, /* X */
218 { "STA", 0x000A26C, 0x80, 0, PutAll },
219 { "STX", 0x000010c, 0x82, 1, PutAll },
220 { "STY", 0x000002c, 0x80, 1, PutAll },
221 { "TAX", 0x0000001, 0xaa, 0, PutAll },
222 { "TAY", 0x0000001, 0xa8, 0, PutAll },
223 { "TSX", 0x0000001, 0xba, 0, PutAll },
224 { "TXA", 0x0000001, 0x8a, 0, PutAll },
225 { "TXS", 0x0000001, 0x9a, 0, PutAll },
226 { "TYA", 0x0000001, 0x98, 0, PutAll }
230 /* Instruction table for the 65SC02 */
231 #define INS_COUNT_65SC02 66
232 static const struct {
234 InsDesc Ins[INS_COUNT_65SC02];
238 { "ADC", 0x080A66C, 0x60, 0, PutAll },
239 { "AND", 0x080A66C, 0x20, 0, PutAll },
240 { "ASL", 0x000006e, 0x02, 1, PutAll },
241 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
242 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
243 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
244 { "BIT", 0x0A0006C, 0x00, 2, PutAll },
245 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
246 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
247 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
248 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
249 { "BRK", 0x0000001, 0x00, 0, PutAll },
250 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
251 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
252 { "CLC", 0x0000001, 0x18, 0, PutAll },
253 { "CLD", 0x0000001, 0xd8, 0, PutAll },
254 { "CLI", 0x0000001, 0x58, 0, PutAll },
255 { "CLV", 0x0000001, 0xb8, 0, PutAll },
256 { "CMP", 0x080A66C, 0xc0, 0, PutAll },
257 { "CPX", 0x080000C, 0xe0, 1, PutAll },
258 { "CPY", 0x080000C, 0xc0, 1, PutAll },
259 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
260 { "DEC", 0x000006F, 0x00, 3, PutAll },
261 { "DEX", 0x0000001, 0xca, 0, PutAll },
262 { "DEY", 0x0000001, 0x88, 0, PutAll },
263 { "EOR", 0x080A66C, 0x40, 0, PutAll },
264 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
265 { "INC", 0x000006f, 0x00, 4, PutAll },
266 { "INX", 0x0000001, 0xe8, 0, PutAll },
267 { "INY", 0x0000001, 0xc8, 0, PutAll },
268 { "JMP", 0x0010808, 0x4c, 6, PutAll },
269 { "JSR", 0x0000008, 0x20, 7, PutAll },
270 { "LDA", 0x080A66C, 0xa0, 0, PutAll },
271 { "LDX", 0x080030C, 0xa2, 1, PutAll },
272 { "LDY", 0x080006C, 0xa0, 1, PutAll },
273 { "LSR", 0x000006F, 0x42, 1, PutAll },
274 { "NOP", 0x0000001, 0xea, 0, PutAll },
275 { "ORA", 0x080A66C, 0x00, 0, PutAll },
276 { "PHA", 0x0000001, 0x48, 0, PutAll },
277 { "PHP", 0x0000001, 0x08, 0, PutAll },
278 { "PHX", 0x0000001, 0xda, 0, PutAll },
279 { "PHY", 0x0000001, 0x5a, 0, PutAll },
280 { "PLA", 0x0000001, 0x68, 0, PutAll },
281 { "PLP", 0x0000001, 0x28, 0, PutAll },
282 { "PLX", 0x0000001, 0xfa, 0, PutAll },
283 { "PLY", 0x0000001, 0x7a, 0, PutAll },
284 { "ROL", 0x000006F, 0x22, 1, PutAll },
285 { "ROR", 0x000006F, 0x62, 1, PutAll },
286 { "RTI", 0x0000001, 0x40, 0, PutAll },
287 { "RTS", 0x0000001, 0x60, 0, PutAll },
288 { "SBC", 0x080A66C, 0xe0, 0, PutAll },
289 { "SEC", 0x0000001, 0x38, 0, PutAll },
290 { "SED", 0x0000001, 0xf8, 0, PutAll },
291 { "SEI", 0x0000001, 0x78, 0, PutAll },
292 { "STA", 0x000A66C, 0x80, 0, PutAll },
293 { "STX", 0x000010c, 0x82, 1, PutAll },
294 { "STY", 0x000002c, 0x80, 1, PutAll },
295 { "STZ", 0x000006c, 0x04, 5, PutAll },
296 { "TAX", 0x0000001, 0xaa, 0, PutAll },
297 { "TAY", 0x0000001, 0xa8, 0, PutAll },
298 { "TRB", 0x000000c, 0x10, 1, PutAll },
299 { "TSB", 0x000000c, 0x00, 1, PutAll },
300 { "TSX", 0x0000001, 0xba, 0, PutAll },
301 { "TXA", 0x0000001, 0x8a, 0, PutAll },
302 { "TXS", 0x0000001, 0x9a, 0, PutAll },
303 { "TYA", 0x0000001, 0x98, 0, PutAll }
307 /* Instruction table for the 65C02 */
308 #define INS_COUNT_65C02 98
309 static const struct {
311 InsDesc Ins[INS_COUNT_65C02];
315 { "ADC", 0x080A66C, 0x60, 0, PutAll },
316 { "AND", 0x080A66C, 0x20, 0, PutAll },
317 { "ASL", 0x000006e, 0x02, 1, PutAll },
318 { "BBR0", 0x0000000, 0x0F, 0, PutBitBranch },
319 { "BBR1", 0x0000000, 0x1F, 0, PutBitBranch },
320 { "BBR2", 0x0000000, 0x2F, 0, PutBitBranch },
321 { "BBR3", 0x0000000, 0x3F, 0, PutBitBranch },
322 { "BBR4", 0x0000000, 0x4F, 0, PutBitBranch },
323 { "BBR5", 0x0000000, 0x5F, 0, PutBitBranch },
324 { "BBR6", 0x0000000, 0x6F, 0, PutBitBranch },
325 { "BBR7", 0x0000000, 0x7F, 0, PutBitBranch },
326 { "BBS0", 0x0000000, 0x8F, 0, PutBitBranch },
327 { "BBS1", 0x0000000, 0x9F, 0, PutBitBranch },
328 { "BBS2", 0x0000000, 0xAF, 0, PutBitBranch },
329 { "BBS3", 0x0000000, 0xBF, 0, PutBitBranch },
330 { "BBS4", 0x0000000, 0xCF, 0, PutBitBranch },
331 { "BBS5", 0x0000000, 0xDF, 0, PutBitBranch },
332 { "BBS6", 0x0000000, 0xEF, 0, PutBitBranch },
333 { "BBS7", 0x0000000, 0xFF, 0, PutBitBranch },
334 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
335 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
336 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
337 { "BIT", 0x0A0006C, 0x00, 2, PutAll },
338 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
339 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
340 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
341 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
342 { "BRK", 0x0000001, 0x00, 0, PutAll },
343 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
344 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
345 { "CLC", 0x0000001, 0x18, 0, PutAll },
346 { "CLD", 0x0000001, 0xd8, 0, PutAll },
347 { "CLI", 0x0000001, 0x58, 0, PutAll },
348 { "CLV", 0x0000001, 0xb8, 0, PutAll },
349 { "CMP", 0x080A66C, 0xc0, 0, PutAll },
350 { "CPX", 0x080000C, 0xe0, 1, PutAll },
351 { "CPY", 0x080000C, 0xc0, 1, PutAll },
352 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
353 { "DEC", 0x000006F, 0x00, 3, PutAll },
354 { "DEX", 0x0000001, 0xca, 0, PutAll },
355 { "DEY", 0x0000001, 0x88, 0, PutAll },
356 { "EOR", 0x080A66C, 0x40, 0, PutAll },
357 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
358 { "INC", 0x000006f, 0x00, 4, PutAll },
359 { "INX", 0x0000001, 0xe8, 0, PutAll },
360 { "INY", 0x0000001, 0xc8, 0, PutAll },
361 { "JMP", 0x0010808, 0x4c, 6, PutAll },
362 { "JSR", 0x0000008, 0x20, 7, PutAll },
363 { "LDA", 0x080A66C, 0xa0, 0, PutAll },
364 { "LDX", 0x080030C, 0xa2, 1, PutAll },
365 { "LDY", 0x080006C, 0xa0, 1, PutAll },
366 { "LSR", 0x000006F, 0x42, 1, PutAll },
367 { "NOP", 0x0000001, 0xea, 0, PutAll },
368 { "ORA", 0x080A66C, 0x00, 0, PutAll },
369 { "PHA", 0x0000001, 0x48, 0, PutAll },
370 { "PHP", 0x0000001, 0x08, 0, PutAll },
371 { "PHX", 0x0000001, 0xda, 0, PutAll },
372 { "PHY", 0x0000001, 0x5a, 0, PutAll },
373 { "PLA", 0x0000001, 0x68, 0, PutAll },
374 { "PLP", 0x0000001, 0x28, 0, PutAll },
375 { "PLX", 0x0000001, 0xfa, 0, PutAll },
376 { "PLY", 0x0000001, 0x7a, 0, PutAll },
377 { "RMB0", 0x0000004, 0x07, 1, PutAll },
378 { "RMB1", 0x0000004, 0x17, 1, PutAll },
379 { "RMB2", 0x0000004, 0x27, 1, PutAll },
380 { "RMB3", 0x0000004, 0x37, 1, PutAll },
381 { "RMB4", 0x0000004, 0x47, 1, PutAll },
382 { "RMB5", 0x0000004, 0x57, 1, PutAll },
383 { "RMB6", 0x0000004, 0x67, 1, PutAll },
384 { "RMB7", 0x0000004, 0x77, 1, PutAll },
385 { "ROL", 0x000006F, 0x22, 1, PutAll },
386 { "ROR", 0x000006F, 0x62, 1, PutAll },
387 { "RTI", 0x0000001, 0x40, 0, PutAll },
388 { "RTS", 0x0000001, 0x60, 0, PutAll },
389 { "SBC", 0x080A66C, 0xe0, 0, PutAll },
390 { "SEC", 0x0000001, 0x38, 0, PutAll },
391 { "SED", 0x0000001, 0xf8, 0, PutAll },
392 { "SEI", 0x0000001, 0x78, 0, PutAll },
393 { "SMB0", 0x0000004, 0x87, 1, PutAll },
394 { "SMB1", 0x0000004, 0x97, 1, PutAll },
395 { "SMB2", 0x0000004, 0xA7, 1, PutAll },
396 { "SMB3", 0x0000004, 0xB7, 1, PutAll },
397 { "SMB4", 0x0000004, 0xC7, 1, PutAll },
398 { "SMB5", 0x0000004, 0xD7, 1, PutAll },
399 { "SMB6", 0x0000004, 0xE7, 1, PutAll },
400 { "SMB7", 0x0000004, 0xF7, 1, PutAll },
401 { "STA", 0x000A66C, 0x80, 0, PutAll },
402 { "STX", 0x000010c, 0x82, 1, PutAll },
403 { "STY", 0x000002c, 0x80, 1, PutAll },
404 { "STZ", 0x000006c, 0x04, 5, PutAll },
405 { "TAX", 0x0000001, 0xaa, 0, PutAll },
406 { "TAY", 0x0000001, 0xa8, 0, PutAll },
407 { "TRB", 0x000000c, 0x10, 1, PutAll },
408 { "TSB", 0x000000c, 0x00, 1, PutAll },
409 { "TSX", 0x0000001, 0xba, 0, PutAll },
410 { "TXA", 0x0000001, 0x8a, 0, PutAll },
411 { "TXS", 0x0000001, 0x9a, 0, PutAll },
412 { "TYA", 0x0000001, 0x98, 0, PutAll }
416 /* Instruction table for the 65816 */
417 #define INS_COUNT_65816 101
418 static const struct {
420 InsDesc Ins[INS_COUNT_65816];
424 { "ADC", 0x0b8f6fc, 0x60, 0, PutAll },
425 { "AND", 0x0b8f6fc, 0x20, 0, PutAll },
426 { "ASL", 0x000006e, 0x02, 1, PutAll },
427 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
428 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
429 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
430 { "BGE", 0x0020000, 0xb0, 0, PutPCRel8 }, /* == BCS */
431 { "BIT", 0x0a0006c, 0x00, 2, PutAll },
432 { "BLT", 0x0020000, 0x90, 0, PutPCRel8 }, /* == BCC */
433 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
434 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
435 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
436 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
437 { "BRK", 0x0000001, 0x00, 0, PutAll },
438 { "BRL", 0x0040000, 0x82, 0, PutPCRel16 },
439 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
440 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
441 { "CLC", 0x0000001, 0x18, 0, PutAll },
442 { "CLD", 0x0000001, 0xd8, 0, PutAll },
443 { "CLI", 0x0000001, 0x58, 0, PutAll },
444 { "CLV", 0x0000001, 0xb8, 0, PutAll },
445 { "CMP", 0x0b8f6fc, 0xc0, 0, PutAll },
446 { "COP", 0x0000004, 0x02, 6, PutAll },
447 { "CPA", 0x0b8f6fc, 0xc0, 0, PutAll }, /* == CMP */
448 { "CPX", 0x0c0000c, 0xe0, 1, PutAll },
449 { "CPY", 0x0c0000c, 0xc0, 1, PutAll },
450 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
451 { "DEC", 0x000006F, 0x00, 3, PutAll },
452 { "DEX", 0x0000001, 0xca, 0, PutAll },
453 { "DEY", 0x0000001, 0x88, 0, PutAll },
454 { "EOR", 0x0b8f6fc, 0x40, 0, PutAll },
455 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
456 { "INC", 0x000006F, 0x00, 4, PutAll },
457 { "INX", 0x0000001, 0xe8, 0, PutAll },
458 { "INY", 0x0000001, 0xc8, 0, PutAll },
459 { "JML", 0x0000810, 0x5c, 1, PutAll },
460 { "JMP", 0x0010818, 0x4c, 6, PutAll },
461 { "JSL", 0x0000010, 0x20, 7, PutAll },
462 { "JSR", 0x0010018, 0x20, 7, PutAll },
463 { "LDA", 0x0b8f6fc, 0xa0, 0, PutAll },
464 { "LDX", 0x0c0030c, 0xa2, 1, PutAll },
465 { "LDY", 0x0c0006c, 0xa0, 1, PutAll },
466 { "LSR", 0x000006F, 0x42, 1, PutAll },
467 { "MVN", 0x1000000, 0x54, 0, PutBlockMove },
468 { "MVP", 0x1000000, 0x44, 0, PutBlockMove },
469 { "NOP", 0x0000001, 0xea, 0, PutAll },
470 { "ORA", 0x0b8f6fc, 0x00, 0, PutAll },
471 { "PEA", 0x0000008, 0xf4, 6, PutAll },
472 { "PEI", 0x0000400, 0xd4, 1, PutAll },
473 { "PER", 0x0040000, 0x62, 0, PutPCRel16 },
474 { "PHA", 0x0000001, 0x48, 0, PutAll },
475 { "PHB", 0x0000001, 0x8b, 0, PutAll },
476 { "PHD", 0x0000001, 0x0b, 0, PutAll },
477 { "PHK", 0x0000001, 0x4b, 0, PutAll },
478 { "PHP", 0x0000001, 0x08, 0, PutAll },
479 { "PHX", 0x0000001, 0xda, 0, PutAll },
480 { "PHY", 0x0000001, 0x5a, 0, PutAll },
481 { "PLA", 0x0000001, 0x68, 0, PutAll },
482 { "PLB", 0x0000001, 0xab, 0, PutAll },
483 { "PLD", 0x0000001, 0x2b, 0, PutAll },
484 { "PLP", 0x0000001, 0x28, 0, PutAll },
485 { "PLX", 0x0000001, 0xfa, 0, PutAll },
486 { "PLY", 0x0000001, 0x7a, 0, PutAll },
487 { "REP", 0x0800000, 0xc2, 1, PutREP },
488 { "ROL", 0x000006F, 0x22, 1, PutAll },
489 { "ROR", 0x000006F, 0x62, 1, PutAll },
490 { "RTI", 0x0000001, 0x40, 0, PutAll },
491 { "RTL", 0x0000001, 0x6b, 0, PutAll },
492 { "RTS", 0x0000001, 0x60, 0, PutRTS },
493 { "SBC", 0x0b8f6fc, 0xe0, 0, PutAll },
494 { "SEC", 0x0000001, 0x38, 0, PutAll },
495 { "SED", 0x0000001, 0xf8, 0, PutAll },
496 { "SEI", 0x0000001, 0x78, 0, PutAll },
497 { "SEP", 0x0800000, 0xe2, 1, PutSEP },
498 { "STA", 0x018f6fc, 0x80, 0, PutAll },
499 { "STP", 0x0000001, 0xdb, 0, PutAll },
500 { "STX", 0x000010c, 0x82, 1, PutAll },
501 { "STY", 0x000002c, 0x80, 1, PutAll },
502 { "STZ", 0x000006c, 0x04, 5, PutAll },
503 { "SWA", 0x0000001, 0xeb, 0, PutAll }, /* == XBA */
504 { "TAD", 0x0000001, 0x5b, 0, PutAll }, /* == TCD */
505 { "TAS", 0x0000001, 0x1b, 0, PutAll }, /* == TCS */
506 { "TAX", 0x0000001, 0xaa, 0, PutAll },
507 { "TAY", 0x0000001, 0xa8, 0, PutAll },
508 { "TCD", 0x0000001, 0x5b, 0, PutAll },
509 { "TCS", 0x0000001, 0x1b, 0, PutAll },
510 { "TDA", 0x0000001, 0x7b, 0, PutAll }, /* == TDC */
511 { "TDC", 0x0000001, 0x7b, 0, PutAll },
512 { "TRB", 0x000000c, 0x10, 1, PutAll },
513 { "TSA", 0x0000001, 0x3b, 0, PutAll }, /* == TSC */
514 { "TSB", 0x000000c, 0x00, 1, PutAll },
515 { "TSC", 0x0000001, 0x3b, 0, PutAll },
516 { "TSX", 0x0000001, 0xba, 0, PutAll },
517 { "TXA", 0x0000001, 0x8a, 0, PutAll },
518 { "TXS", 0x0000001, 0x9a, 0, PutAll },
519 { "TXY", 0x0000001, 0x9b, 0, PutAll },
520 { "TYA", 0x0000001, 0x98, 0, PutAll },
521 { "TYX", 0x0000001, 0xbb, 0, PutAll },
522 { "WAI", 0x0000001, 0xcb, 0, PutAll },
523 { "XBA", 0x0000001, 0xeb, 0, PutAll },
524 { "XCE", 0x0000001, 0xfb, 0, PutAll }
529 /* Table for the SUNPLUS CPU */
530 #include "sunplus.inc"
535 /* An array with instruction tables */
536 static const InsTable* InsTabs[CPU_COUNT] = {
537 (const InsTable*) &InsTab6502,
538 (const InsTable*) &InsTab6502X,
539 (const InsTable*) &InsTab65SC02,
540 (const InsTable*) &InsTab65C02,
541 (const InsTable*) &InsTab65816,
543 (const InsTable*) &InsTabSunPlus,
546 const InsTable* InsTab = (const InsTable*) &InsTab6502;
548 /* Table to build the effective opcode from a base opcode and an addressing
551 unsigned char EATab [9][AMI_COUNT] = {
553 0x00, 0x00, 0x05, 0x0D, 0x0F, 0x15, 0x1D, 0x1F,
554 0x00, 0x19, 0x12, 0x00, 0x07, 0x11, 0x17, 0x01,
555 0x00, 0x00, 0x00, 0x03, 0x13, 0x09, 0x00, 0x09,
559 0x08, 0x08, 0x04, 0x0C, 0x00, 0x14, 0x1C, 0x00,
560 0x14, 0x1C, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00,
561 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
565 0x00, 0x00, 0x24, 0x2C, 0x0F, 0x34, 0x3C, 0x00,
566 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
567 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00,
571 0x3A, 0x3A, 0xC6, 0xCE, 0x00, 0xD6, 0xDE, 0x00,
572 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
573 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
577 0x1A, 0x1A, 0xE6, 0xEE, 0x00, 0xF6, 0xFE, 0x00,
578 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
579 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
583 0x00, 0x00, 0x60, 0x98, 0x00, 0x70, 0x9E, 0x00,
584 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
585 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
589 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
590 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
591 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
595 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
596 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
597 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
601 0x00, 0x40, 0x01, 0x41, 0x00, 0x09, 0x49, 0x00,
602 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00,
603 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
608 /* Table that encodes the additional bytes for each instruction */
609 unsigned char ExtBytes [AMI_COUNT] = {
614 3, /* Absolute long */
617 3, /* Absolute long,X */
626 2, /* (Absolute,X) */
627 1, /* Relative short */
628 2, /* Relative long */
631 1, /* Immidiate accu */
632 1, /* Immidiate index */
633 1, /* Immidiate byte */
639 /*****************************************************************************/
640 /* Handler functions */
641 /*****************************************************************************/
645 static int EvalEA (const InsDesc* Ins, EffAddr* A)
646 /* Evaluate the effective address. All fields in A will be valid after calling
647 * this function. The function returns true on success and false on errors.
650 /* Get the set of possible addressing modes */
653 /* From the possible addressing modes, remove the ones that are invalid
654 * for this instruction or CPU.
656 A->AddrModeSet &= Ins->AddrMode;
658 /* If we have an expression, check it and remove any addressing modes that
659 * are too small for the expression size. Since we have to study the
660 * expression anyway, do also replace it by a simpler one if possible.
666 /* Study the expression */
667 StudyExpr (A->Expr, &ED);
669 /* Simplify it if possible */
670 A->Expr = SimplifyExpr (A->Expr, &ED);
672 /* If we don't know how big the expression is, assume the default
673 * address size for data.
675 if (ED.AddrSize == ADDR_SIZE_DEFAULT) {
676 ED.AddrSize = DataAddrSize;
680 switch (ED.AddrSize) {
683 A->AddrModeSet &= ~AM_SET_ZP;
687 A->AddrModeSet &= ~(AM_SET_ZP | AM_SET_ABS);
691 /* Free any resource associated with the expression desc */
695 /* Check if we have any adressing modes left */
696 if (A->AddrModeSet == 0) {
697 Error ("Illegal addressing mode");
700 A->AddrMode = BitFind (A->AddrModeSet);
701 A->AddrModeBit = (0x01UL << A->AddrMode);
703 /* If the instruction has a one byte operand and immediate addressing is
704 * allowed but not used, check for an operand expression in the form
705 * <label or >label, where label is a far or absolute label. If found,
706 * emit a warning. This warning protects against a typo, where the '#'
707 * for the immediate operand is omitted.
709 if (A->Expr && (Ins->AddrMode & AM_IMM) &&
710 (A->AddrModeSet & (AM_DIR | AM_ABS | AM_ABS_LONG)) &&
711 ExtBytes[A->AddrMode] == 1) {
713 /* Found, check the expression */
714 ExprNode* Left = A->Expr->Left;
715 if ((A->Expr->Op == EXPR_BYTE0 || A->Expr->Op == EXPR_BYTE1) &&
716 Left->Op == EXPR_SYMBOL &&
717 GetSymAddrSize (Left->V.Sym) != ADDR_SIZE_ZP) {
719 /* Output a warning */
720 Warning (1, "Suspicious address expression");
724 /* Build the opcode */
725 A->Opcode = Ins->BaseCode | EATab[Ins->ExtCode][A->AddrMode];
733 static void EmitCode (EffAddr* A)
734 /* Output code for the data in A */
736 /* Check how many extension bytes are needed and output the instruction */
737 switch (ExtBytes[A->AddrMode]) {
744 Emit1 (A->Opcode, A->Expr);
748 if (CPU == CPU_65816 && (A->AddrModeBit & (AM_ABS | AM_ABS_X | AM_ABS_Y))) {
749 /* This is a 16 bit mode that uses an address. If in 65816,
750 * mode, force this address into 16 bit range to allow
751 * addressing inside a 64K segment.
753 Emit2 (A->Opcode, GenWordExpr (A->Expr));
755 Emit2 (A->Opcode, A->Expr);
761 Emit3 (A->Opcode, A->Expr);
765 Internal ("Invalid operand byte count: %u", ExtBytes[A->AddrMode]);
772 static long PutImmed8 (const InsDesc* Ins)
773 /* Parse and emit an immediate 8 bit instruction. Return the value of the
774 * operand if it's available and const.
780 /* Evaluate the addressing mode */
781 if (EvalEA (Ins, &A) == 0) {
782 /* An error occurred */
786 /* If we have an expression and it's const, get it's value */
788 (void) IsConstExpr (A.Expr, &Val);
791 /* Check how many extension bytes are needed and output the instruction */
792 switch (ExtBytes[A.AddrMode]) {
795 Emit1 (A.Opcode, A.Expr);
799 Internal ("Invalid operand byte count: %u", ExtBytes[A.AddrMode]);
802 /* Return the expression value */
808 static void PutPCRel8 (const InsDesc* Ins)
809 /* Handle branches with a 8 bit distance */
811 EmitPCRel (Ins->BaseCode, GenBranchExpr (2), 1);
816 static void PutPCRel16 (const InsDesc* Ins)
817 /* Handle branches with an 16 bit distance and PER */
819 EmitPCRel (Ins->BaseCode, GenBranchExpr (3), 2);
824 static void PutBlockMove (const InsDesc* Ins)
825 /* Handle the blockmove instructions */
827 Emit0 (Ins->BaseCode);
828 EmitByte (Expression ());
830 EmitByte (Expression ());
835 static void PutBitBranch (const InsDesc* Ins)
836 /* Handle 65C02 branch on bit condition */
838 Emit0 (Ins->BaseCode);
839 EmitByte (Expression ());
841 EmitSigned (GenBranchExpr (1), 1);
846 static void PutREP (const InsDesc* Ins)
847 /* Emit a REP instruction, track register sizes */
849 /* Use the generic handler */
850 long Val = PutImmed8 (Ins);
852 /* We track the status only for the 816 CPU and in smart mode */
853 if (CPU == CPU_65816 && SmartMode) {
855 /* Check the range for Val. */
857 /* We had an error */
858 Warning (1, "Cannot track processor status byte");
861 /* Index registers to 16 bit */
862 ExtBytes[AMI_IMM_INDEX] = 2;
866 ExtBytes[AMI_IMM_ACCU] = 2;
874 static void PutSEP (const InsDesc* Ins)
875 /* Emit a SEP instruction, track register sizes */
877 /* Use the generic handler */
878 long Val = PutImmed8 (Ins);
880 /* We track the status only for the 816 CPU and in smart mode */
881 if (CPU == CPU_65816 && SmartMode) {
883 /* Check the range for Val. */
885 /* We had an error */
886 Warning (1, "Cannot track processor status byte");
889 /* Index registers to 8 bit */
890 ExtBytes [AMI_IMM_INDEX] = 1;
894 ExtBytes [AMI_IMM_ACCU] = 1;
902 static void PutJMP (const InsDesc* Ins)
903 /* Handle the jump instruction for the 6502. Problem is that these chips have
904 * a bug: If the address crosses a page, the upper byte gets not corrected and
905 * the instruction will fail. The PutJmp function will add a linker assertion
906 * to check for this case and is otherwise identical to PutAll.
911 /* Evaluate the addressing mode used */
912 if (EvalEA (Ins, &A)) {
914 /* Check for indirect addressing */
915 if (A.AddrModeBit & AM_ABS_IND) {
917 /* Compare the low byte of the expression to 0xFF to check for
918 * a page cross. Be sure to use a copy of the expression otherwise
919 * things will go weird later.
921 ExprNode* E = GenNE (GenByteExpr (CloneExpr (A.Expr)), 0xFF);
923 /* Generate the message */
924 unsigned Msg = GetStringId ("\"jmp (abs)\" across page border");
926 /* Generate the assertion */
927 AddAssertion (E, ASSERT_ACT_WARN, Msg);
930 /* No error, output code */
937 static void PutRTS (const InsDesc* Ins attribute ((unused)))
938 /* Handle the RTS instruction for the 816. In smart mode emit a RTL opcode if
939 * the enclosing scope is FAR.
942 if (SmartMode && CurrentScope->AddrSize == ADDR_SIZE_FAR) {
943 Emit0 (0x6B); /* RTL */
945 Emit0 (0x60); /* RTS */
951 static void PutAll (const InsDesc* Ins)
952 /* Handle all other instructions */
956 /* Evaluate the addressing mode used */
957 if (EvalEA (Ins, &A)) {
958 /* No error, output code */
965 /*****************************************************************************/
967 /*****************************************************************************/
971 static int CmpName (const void* Key, const void* Instr)
972 /* Compare function for bsearch */
974 return strcmp ((const char*)Key, ((const InsDesc*) Instr)->Mnemonic);
979 void SetCPU (cpu_t NewCPU)
982 /* Make sure the parameter is correct */
983 CHECK (NewCPU < CPU_COUNT);
985 /* Check if we have support for the new CPU, if so, use it */
986 if (InsTabs[NewCPU]) {
988 InsTab = InsTabs[CPU];
990 Error ("CPU not supported");
997 /* Return the current CPU */
1004 int FindInstruction (const char* Ident)
1005 /* Check if Ident is a valid mnemonic. If so, return the index in the
1006 * instruction table. If not, return -1.
1011 char Key[sizeof (ID->Mnemonic)];
1013 /* Make a copy, and uppercase that copy */
1015 while (Ident[I] != '\0') {
1016 /* If the identifier is longer than the longest mnemonic, it cannot
1019 if (I >= sizeof (Key) - 1) {
1020 /* Not found, no need for further action */
1023 Key[I] = toupper ((unsigned char)Ident[I]);
1028 /* Search for the key */
1029 ID = bsearch (Key, InsTab->Ins, InsTab->Count, sizeof (InsDesc), CmpName);
1034 /* Found, return the entry */
1035 return ID - InsTab->Ins;
1041 void HandleInstruction (unsigned Index)
1042 /* Handle the mnemonic with the given index */
1045 PRECONDITION (Index < InsTab->Count);
1047 /* Skip the mnemonic token */
1050 /* Call the handler */
1051 InsTab->Ins[Index].Emit (&InsTab->Ins[Index]);