1/*****************************************************************************/
2/* */
3/* instr.c */
4/* */
5/* Instruction encoding for the ca65 macroassembler */
6/* */
7/* */
8/* */
9/* (C) 1998-2012, Ullrich von Bassewitz */
10/* Roemerstrasse 52 */
11/* D-70794 Filderstadt */
12/* EMail: uz@cc65.org */
13/* */
14/* */
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. */
18/* */
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: */
22/* */
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 */
30/* distribution. */
31/* */
32/*****************************************************************************/
33
34
35
36#include <stdlib.h>
37#include <string.h>
38#include <ctype.h>
39
40/* common */
41#include "addrsize.h"
42#include "attrib.h"
43#include "bitops.h"
44#include "check.h"
45#include "mmodel.h"
46
47/* ca65 */
48#include "asserts.h"
49#include "ea.h"
50#include "ea65.h"
51#include "easw16.h"
52#include "error.h"
53#include "expr.h"
54#include "global.h"
55#include "instr.h"
56#include "nexttok.h"
57#include "objcode.h"
58#include "spool.h"
59#include "studyexpr.h"
60#include "symtab.h"
61
62
63
64/*****************************************************************************/
65/* Forwards */
66/*****************************************************************************/
67
68
69
70static void PutPCRel8 (const InsDesc* Ins);
71/* Handle branches with a 8 bit distance */
72
73static void PutPCRel16 (const InsDesc* Ins);
74/* Handle branches with an 16 bit distance and PER */
75
76static void PutPCRel4510 (const InsDesc* Ins);
77/* Handle branches with a 16 bit distance for 4510 */
78
79static void PutBlockMove (const InsDesc* Ins);
80/* Handle the blockmove instructions (65816) */
81
82static void PutBlockTransfer (const InsDesc* Ins);
83/* Handle the block transfer instructions (HuC6280) */
84
85static void PutBitBranch (const InsDesc* Ins);
86/* Handle 65C02 branch on bit condition */
87
88static void PutREP (const InsDesc* Ins);
89/* Emit a REP instruction, track register sizes */
90
91static void PutSEP (const InsDesc* Ins);
92/* Emit a SEP instruction (65816), track register sizes */
93
94static void PutTAMn (const InsDesc* Ins);
95/* Emit a TAMn instruction (HuC6280). Since this is a two byte instruction with
96** implicit addressing mode, the opcode byte in the table is actually the
97** second operand byte. The TAM instruction is the more generic form, it takes
98** an immediate argument.
99*/
100
101static void PutTMA (const InsDesc* Ins);
102/* Emit a TMA instruction (HuC6280) with an immediate argument. Only one bit
103** in the argument byte may be set.
104*/
105
106static void PutTMAn (const InsDesc* Ins);
107/* Emit a TMAn instruction (HuC6280). Since this is a two byte instruction with
108** implicit addressing mode, the opcode byte in the table is actually the
109** second operand byte. The TAM instruction is the more generic form, it takes
110** an immediate argument.
111*/
112
113static void PutTST (const InsDesc* Ins);
114/* Emit a TST instruction (HuC6280). */
115
116static void PutJMP (const InsDesc* Ins);
117/* Handle the jump instruction for the 6502. Problem is that these chips have
118** a bug: If the address crosses a page, the upper byte gets not corrected and
119** the instruction will fail. The PutJmp function will add a linker assertion
120** to check for this case and is otherwise identical to PutAll.
121*/
122
123static void PutRTS (const InsDesc* Ins attribute ((unused)));
124/* Handle the RTS instruction for the 816. In smart mode emit a RTL opcode if
125** the enclosing scope is FAR.
126*/
127
128static void PutAll (const InsDesc* Ins);
129/* Handle all other instructions */
130
131static void Put4510 (const InsDesc* Ins);
132/* Handle instructions of 4510 not matching any EATab */
133
134static void PutSweet16 (const InsDesc* Ins);
135/* Handle a generic sweet16 instruction */
136
137static void PutSweet16Branch (const InsDesc* Ins);
138/* Handle a sweet16 branch instruction */
139
140
141
142/*****************************************************************************/
143/* Data */
144/*****************************************************************************/
145
146
147
148/* Empty instruction table */
149static const struct {
150 unsigned Count;
151} InsTabNone = {
152 0
153};
154
155/* Instruction table for the 6502 */
156static const struct {
157 unsigned Count;
158 InsDesc Ins[56];
159} InsTab6502 = {
160 sizeof (InsTab6502.Ins) / sizeof (InsTab6502.Ins[0]),
161 {
162 { "ADC", 0x080A26C, 0x60, 0, PutAll },
163 { "AND", 0x080A26C, 0x20, 0, PutAll },
164 { "ASL", 0x000006e, 0x02, 1, PutAll },
165 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
166 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
167 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
168 { "BIT", 0x000000C, 0x00, 2, PutAll },
169 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
170 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
171 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
172 { "BRK", 0x0000001, 0x00, 0, PutAll },
173 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
174 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
175 { "CLC", 0x0000001, 0x18, 0, PutAll },
176 { "CLD", 0x0000001, 0xd8, 0, PutAll },
177 { "CLI", 0x0000001, 0x58, 0, PutAll },
178 { "CLV", 0x0000001, 0xb8, 0, PutAll },
179 { "CMP", 0x080A26C, 0xc0, 0, PutAll },
180 { "CPX", 0x080000C, 0xe0, 1, PutAll },
181 { "CPY", 0x080000C, 0xc0, 1, PutAll },
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 { "JMP", 0x0000808, 0x4c, 6, PutJMP },
190 { "JSR", 0x0000008, 0x20, 7, PutAll },
191 { "LDA", 0x080A26C, 0xa0, 0, PutAll },
192 { "LDX", 0x080030C, 0xa2, 1, PutAll },
193 { "LDY", 0x080006C, 0xa0, 1, PutAll },
194 { "LSR", 0x000006F, 0x42, 1, PutAll },
195 { "NOP", 0x0000001, 0xea, 0, PutAll },
196 { "ORA", 0x080A26C, 0x00, 0, PutAll },
197 { "PHA", 0x0000001, 0x48, 0, PutAll },
198 { "PHP", 0x0000001, 0x08, 0, PutAll },
199 { "PLA", 0x0000001, 0x68, 0, PutAll },
200 { "PLP", 0x0000001, 0x28, 0, PutAll },
201 { "ROL", 0x000006F, 0x22, 1, PutAll },
202 { "ROR", 0x000006F, 0x62, 1, PutAll },
203 { "RTI", 0x0000001, 0x40, 0, PutAll },
204 { "RTS", 0x0000001, 0x60, 0, PutAll },
205 { "SBC", 0x080A26C, 0xe0, 0, PutAll },
206 { "SEC", 0x0000001, 0x38, 0, PutAll },
207 { "SED", 0x0000001, 0xf8, 0, PutAll },
208 { "SEI", 0x0000001, 0x78, 0, PutAll },
209 { "STA", 0x000A26C, 0x80, 0, PutAll },
210 { "STX", 0x000010c, 0x82, 1, PutAll },
211 { "STY", 0x000002c, 0x80, 1, PutAll },
212 { "TAX", 0x0000001, 0xaa, 0, PutAll },
213 { "TAY", 0x0000001, 0xa8, 0, 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 }
218 }
219};
220
221/* Instruction table for the 6502 with illegal instructions */
222static const struct {
223 unsigned Count;
224 InsDesc Ins[75];
225} InsTab6502X = {
226 sizeof (InsTab6502X.Ins) / sizeof (InsTab6502X.Ins[0]),
227 {
228 { "ADC", 0x080A26C, 0x60, 0, PutAll },
229 { "ALR", 0x0800000, 0x4B, 0, PutAll }, /* X */
230 { "ANC", 0x0800000, 0x0B, 0, PutAll }, /* X */
231 { "AND", 0x080A26C, 0x20, 0, PutAll },
232 { "ANE", 0x0800000, 0x8B, 0, PutAll }, /* X */
233 { "ARR", 0x0800000, 0x6B, 0, PutAll }, /* X */
234 { "ASL", 0x000006e, 0x02, 1, PutAll },
235 { "AXS", 0x0800000, 0xCB, 0, PutAll }, /* X */
236 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
237 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
238 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
239 { "BIT", 0x000000C, 0x00, 2, PutAll },
240 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
241 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
242 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
243 { "BRK", 0x0000001, 0x00, 0, PutAll },
244 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
245 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
246 { "CLC", 0x0000001, 0x18, 0, PutAll },
247 { "CLD", 0x0000001, 0xd8, 0, PutAll },
248 { "CLI", 0x0000001, 0x58, 0, PutAll },
249 { "CLV", 0x0000001, 0xb8, 0, PutAll },
250 { "CMP", 0x080A26C, 0xc0, 0, PutAll },
251 { "CPX", 0x080000C, 0xe0, 1, PutAll },
252 { "CPY", 0x080000C, 0xc0, 1, PutAll },
253 { "DCP", 0x000A26C, 0xC3, 0, PutAll }, /* X */
254 { "DEC", 0x000006C, 0x00, 3, PutAll },
255 { "DEX", 0x0000001, 0xca, 0, PutAll },
256 { "DEY", 0x0000001, 0x88, 0, PutAll },
257 { "EOR", 0x080A26C, 0x40, 0, PutAll },
258 { "INC", 0x000006c, 0x00, 4, PutAll },
259 { "INX", 0x0000001, 0xe8, 0, PutAll },
260 { "INY", 0x0000001, 0xc8, 0, PutAll },
261 { "ISC", 0x000A26C, 0xE3, 0, PutAll }, /* X */
262 { "JAM", 0x0000001, 0x02, 0, PutAll }, /* X */
263 { "JMP", 0x0000808, 0x4c, 6, PutJMP },
264 { "JSR", 0x0000008, 0x20, 7, PutAll },
265 { "LAS", 0x0000200, 0xBB, 0, PutAll }, /* X */
266 { "LAX", 0x080A30C, 0xA3, 11, PutAll }, /* X */
267 { "LDA", 0x080A26C, 0xa0, 0, PutAll },
268 { "LDX", 0x080030C, 0xa2, 1, PutAll },
269 { "LDY", 0x080006C, 0xa0, 1, PutAll },
270 { "LSR", 0x000006F, 0x42, 1, PutAll },
271 { "NOP", 0x080006D, 0x00, 10, PutAll }, /* X */
272 { "ORA", 0x080A26C, 0x00, 0, PutAll },
273 { "PHA", 0x0000001, 0x48, 0, PutAll },
274 { "PHP", 0x0000001, 0x08, 0, PutAll },
275 { "PLA", 0x0000001, 0x68, 0, PutAll },
276 { "PLP", 0x0000001, 0x28, 0, PutAll },
277 { "RLA", 0x000A26C, 0x23, 0, PutAll }, /* X */
278 { "ROL", 0x000006F, 0x22, 1, PutAll },
279 { "ROR", 0x000006F, 0x62, 1, PutAll },
280 { "RRA", 0x000A26C, 0x63, 0, PutAll }, /* X */
281 { "RTI", 0x0000001, 0x40, 0, PutAll },
282 { "RTS", 0x0000001, 0x60, 0, PutAll },
283 { "SAX", 0x000810C, 0x83, 1, PutAll }, /* X */
284 { "SBC", 0x080A26C, 0xe0, 0, PutAll },
285 { "SEC", 0x0000001, 0x38, 0, PutAll },
286 { "SED", 0x0000001, 0xf8, 0, PutAll },
287 { "SEI", 0x0000001, 0x78, 0, PutAll },
288 { "SHA", 0x0002200, 0x93, 1, PutAll }, /* X */
289 { "SHX", 0x0000200, 0x9e, 1, PutAll }, /* X */
290 { "SHY", 0x0000040, 0x9c, 1, PutAll }, /* X */
291 { "SLO", 0x000A26C, 0x03, 0, PutAll }, /* X */
292 { "SRE", 0x000A26C, 0x43, 0, PutAll }, /* X */
293 { "STA", 0x000A26C, 0x80, 0, PutAll },
294 { "STX", 0x000010c, 0x82, 1, PutAll },
295 { "STY", 0x000002c, 0x80, 1, PutAll },
296 { "TAS", 0x0000200, 0x9b, 0, PutAll }, /* X */
297 { "TAX", 0x0000001, 0xaa, 0, PutAll },
298 { "TAY", 0x0000001, 0xa8, 0, PutAll },
299 { "TSX", 0x0000001, 0xba, 0, PutAll },
300 { "TXA", 0x0000001, 0x8a, 0, PutAll },
301 { "TXS", 0x0000001, 0x9a, 0, PutAll },
302 { "TYA", 0x0000001, 0x98, 0, PutAll }
303 }
304};
305
306/* Instruction table for the 65SC02 */
307static const struct {
308 unsigned Count;
309 InsDesc Ins[66];
310} InsTab65SC02 = {
311 sizeof (InsTab65SC02.Ins) / sizeof (InsTab65SC02.Ins[0]),
312 {
313 { "ADC", 0x080A66C, 0x60, 0, PutAll },
314 { "AND", 0x080A66C, 0x20, 0, PutAll },
315 { "ASL", 0x000006e, 0x02, 1, PutAll },
316 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
317 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
318 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
319 { "BIT", 0x0A0006C, 0x00, 2, PutAll },
320 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
321 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
322 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
323 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
324 { "BRK", 0x0000001, 0x00, 0, PutAll },
325 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
326 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
327 { "CLC", 0x0000001, 0x18, 0, PutAll },
328 { "CLD", 0x0000001, 0xd8, 0, PutAll },
329 { "CLI", 0x0000001, 0x58, 0, PutAll },
330 { "CLV", 0x0000001, 0xb8, 0, PutAll },
331 { "CMP", 0x080A66C, 0xc0, 0, PutAll },
332 { "CPX", 0x080000C, 0xe0, 1, PutAll },
333 { "CPY", 0x080000C, 0xc0, 1, PutAll },
334 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
335 { "DEC", 0x000006F, 0x00, 3, PutAll },
336 { "DEX", 0x0000001, 0xca, 0, PutAll },
337 { "DEY", 0x0000001, 0x88, 0, PutAll },
338 { "EOR", 0x080A66C, 0x40, 0, PutAll },
339 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
340 { "INC", 0x000006f, 0x00, 4, PutAll },
341 { "INX", 0x0000001, 0xe8, 0, PutAll },
342 { "INY", 0x0000001, 0xc8, 0, PutAll },
343 { "JMP", 0x0010808, 0x4c, 6, PutAll },
344 { "JSR", 0x0000008, 0x20, 7, PutAll },
345 { "LDA", 0x080A66C, 0xa0, 0, PutAll },
346 { "LDX", 0x080030C, 0xa2, 1, PutAll },
347 { "LDY", 0x080006C, 0xa0, 1, PutAll },
348 { "LSR", 0x000006F, 0x42, 1, PutAll },
349 { "NOP", 0x0000001, 0xea, 0, PutAll },
350 { "ORA", 0x080A66C, 0x00, 0, PutAll },
351 { "PHA", 0x0000001, 0x48, 0, PutAll },
352 { "PHP", 0x0000001, 0x08, 0, PutAll },
353 { "PHX", 0x0000001, 0xda, 0, PutAll },
354 { "PHY", 0x0000001, 0x5a, 0, PutAll },
355 { "PLA", 0x0000001, 0x68, 0, PutAll },
356 { "PLP", 0x0000001, 0x28, 0, PutAll },
357 { "PLX", 0x0000001, 0xfa, 0, PutAll },
358 { "PLY", 0x0000001, 0x7a, 0, PutAll },
359 { "ROL", 0x000006F, 0x22, 1, PutAll },
360 { "ROR", 0x000006F, 0x62, 1, PutAll },
361 { "RTI", 0x0000001, 0x40, 0, PutAll },
362 { "RTS", 0x0000001, 0x60, 0, PutAll },
363 { "SBC", 0x080A66C, 0xe0, 0, PutAll },
364 { "SEC", 0x0000001, 0x38, 0, PutAll },
365 { "SED", 0x0000001, 0xf8, 0, PutAll },
366 { "SEI", 0x0000001, 0x78, 0, PutAll },
367 { "STA", 0x000A66C, 0x80, 0, PutAll },
368 { "STX", 0x000010c, 0x82, 1, PutAll },
369 { "STY", 0x000002c, 0x80, 1, PutAll },
370 { "STZ", 0x000006c, 0x04, 5, PutAll },
371 { "TAX", 0x0000001, 0xaa, 0, PutAll },
372 { "TAY", 0x0000001, 0xa8, 0, PutAll },
373 { "TRB", 0x000000c, 0x10, 1, PutAll },
374 { "TSB", 0x000000c, 0x00, 1, PutAll },
375 { "TSX", 0x0000001, 0xba, 0, PutAll },
376 { "TXA", 0x0000001, 0x8a, 0, PutAll },
377 { "TXS", 0x0000001, 0x9a, 0, PutAll },
378 { "TYA", 0x0000001, 0x98, 0, PutAll }
379 }
380};
381
382/* Instruction table for the 65C02 */
383static const struct {
384 unsigned Count;
385 InsDesc Ins[100];
386} InsTab65C02 = {
387 sizeof (InsTab65C02.Ins) / sizeof (InsTab65C02.Ins[0]),
388 {
389 { "ADC", 0x080A66C, 0x60, 0, PutAll },
390 { "AND", 0x080A66C, 0x20, 0, PutAll },
391 { "ASL", 0x000006e, 0x02, 1, PutAll },
392 { "BBR0", 0x0000000, 0x0F, 0, PutBitBranch },
393 { "BBR1", 0x0000000, 0x1F, 0, PutBitBranch },
394 { "BBR2", 0x0000000, 0x2F, 0, PutBitBranch },
395 { "BBR3", 0x0000000, 0x3F, 0, PutBitBranch },
396 { "BBR4", 0x0000000, 0x4F, 0, PutBitBranch },
397 { "BBR5", 0x0000000, 0x5F, 0, PutBitBranch },
398 { "BBR6", 0x0000000, 0x6F, 0, PutBitBranch },
399 { "BBR7", 0x0000000, 0x7F, 0, PutBitBranch },
400 { "BBS0", 0x0000000, 0x8F, 0, PutBitBranch },
401 { "BBS1", 0x0000000, 0x9F, 0, PutBitBranch },
402 { "BBS2", 0x0000000, 0xAF, 0, PutBitBranch },
403 { "BBS3", 0x0000000, 0xBF, 0, PutBitBranch },
404 { "BBS4", 0x0000000, 0xCF, 0, PutBitBranch },
405 { "BBS5", 0x0000000, 0xDF, 0, PutBitBranch },
406 { "BBS6", 0x0000000, 0xEF, 0, PutBitBranch },
407 { "BBS7", 0x0000000, 0xFF, 0, PutBitBranch },
408 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
409 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
410 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
411 { "BIT", 0x0A0006C, 0x00, 2, PutAll },
412 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
413 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
414 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
415 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
416 { "BRK", 0x0000001, 0x00, 0, PutAll },
417 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
418 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
419 { "CLC", 0x0000001, 0x18, 0, PutAll },
420 { "CLD", 0x0000001, 0xd8, 0, PutAll },
421 { "CLI", 0x0000001, 0x58, 0, PutAll },
422 { "CLV", 0x0000001, 0xb8, 0, PutAll },
423 { "CMP", 0x080A66C, 0xc0, 0, PutAll },
424 { "CPX", 0x080000C, 0xe0, 1, PutAll },
425 { "CPY", 0x080000C, 0xc0, 1, PutAll },
426 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
427 { "DEC", 0x000006F, 0x00, 3, PutAll },
428 { "DEX", 0x0000001, 0xca, 0, PutAll },
429 { "DEY", 0x0000001, 0x88, 0, PutAll },
430 { "EOR", 0x080A66C, 0x40, 0, PutAll },
431 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
432 { "INC", 0x000006f, 0x00, 4, PutAll },
433 { "INX", 0x0000001, 0xe8, 0, PutAll },
434 { "INY", 0x0000001, 0xc8, 0, PutAll },
435 { "JMP", 0x0010808, 0x4c, 6, PutAll },
436 { "JSR", 0x0000008, 0x20, 7, PutAll },
437 { "LDA", 0x080A66C, 0xa0, 0, PutAll },
438 { "LDX", 0x080030C, 0xa2, 1, PutAll },
439 { "LDY", 0x080006C, 0xa0, 1, PutAll },
440 { "LSR", 0x000006F, 0x42, 1, PutAll },
441 { "NOP", 0x0000001, 0xea, 0, PutAll },
442 { "ORA", 0x080A66C, 0x00, 0, PutAll },
443 { "PHA", 0x0000001, 0x48, 0, PutAll },
444 { "PHP", 0x0000001, 0x08, 0, PutAll },
445 { "PHX", 0x0000001, 0xda, 0, PutAll },
446 { "PHY", 0x0000001, 0x5a, 0, PutAll },
447 { "PLA", 0x0000001, 0x68, 0, PutAll },
448 { "PLP", 0x0000001, 0x28, 0, PutAll },
449 { "PLX", 0x0000001, 0xfa, 0, PutAll },
450 { "PLY", 0x0000001, 0x7a, 0, PutAll },
451 { "RMB0", 0x0000004, 0x07, 1, PutAll },
452 { "RMB1", 0x0000004, 0x17, 1, PutAll },
453 { "RMB2", 0x0000004, 0x27, 1, PutAll },
454 { "RMB3", 0x0000004, 0x37, 1, PutAll },
455 { "RMB4", 0x0000004, 0x47, 1, PutAll },
456 { "RMB5", 0x0000004, 0x57, 1, PutAll },
457 { "RMB6", 0x0000004, 0x67, 1, PutAll },
458 { "RMB7", 0x0000004, 0x77, 1, PutAll },
459 { "ROL", 0x000006F, 0x22, 1, PutAll },
460 { "ROR", 0x000006F, 0x62, 1, PutAll },
461 { "RTI", 0x0000001, 0x40, 0, PutAll },
462 { "RTS", 0x0000001, 0x60, 0, PutAll },
463 { "SBC", 0x080A66C, 0xe0, 0, PutAll },
464 { "SEC", 0x0000001, 0x38, 0, PutAll },
465 { "SED", 0x0000001, 0xf8, 0, PutAll },
466 { "SEI", 0x0000001, 0x78, 0, PutAll },
467 { "SMB0", 0x0000004, 0x87, 1, PutAll },
468 { "SMB1", 0x0000004, 0x97, 1, PutAll },
469 { "SMB2", 0x0000004, 0xA7, 1, PutAll },
470 { "SMB3", 0x0000004, 0xB7, 1, PutAll },
471 { "SMB4", 0x0000004, 0xC7, 1, PutAll },
472 { "SMB5", 0x0000004, 0xD7, 1, PutAll },
473 { "SMB6", 0x0000004, 0xE7, 1, PutAll },
474 { "SMB7", 0x0000004, 0xF7, 1, PutAll },
475 { "STA", 0x000A66C, 0x80, 0, PutAll },
476 { "STP", 0x0000001, 0xdb, 0, PutAll },
477 { "STX", 0x000010c, 0x82, 1, PutAll },
478 { "STY", 0x000002c, 0x80, 1, PutAll },
479 { "STZ", 0x000006c, 0x04, 5, PutAll },
480 { "TAX", 0x0000001, 0xaa, 0, PutAll },
481 { "TAY", 0x0000001, 0xa8, 0, PutAll },
482 { "TRB", 0x000000c, 0x10, 1, PutAll },
483 { "TSB", 0x000000c, 0x00, 1, PutAll },
484 { "TSX", 0x0000001, 0xba, 0, PutAll },
485 { "TXA", 0x0000001, 0x8a, 0, PutAll },
486 { "TXS", 0x0000001, 0x9a, 0, PutAll },
487 { "TYA", 0x0000001, 0x98, 0, PutAll },
488 { "WAI", 0x0000001, 0xcb, 0, PutAll }
489 }
490};
491
492/* Instruction table for the 4510 */
493static const struct {
494 unsigned Count;
495 InsDesc Ins[133];
496} InsTab4510 = {
497 sizeof (InsTab4510.Ins) / sizeof (InsTab4510.Ins[0]),
498 {
499 { "ADC", 0x080A66C, 0x60, 0, PutAll },
500 { "AND", 0x080A66C, 0x20, 0, PutAll },
501 { "ASL", 0x000006e, 0x02, 1, PutAll },
502 { "ASR", 0x0000026, 0x43, 0, Put4510 },
503 { "ASW", 0x0000008, 0xcb, 6, PutAll },
504 { "BBR0", 0x0000000, 0x0F, 0, PutBitBranch },
505 { "BBR1", 0x0000000, 0x1F, 0, PutBitBranch },
506 { "BBR2", 0x0000000, 0x2F, 0, PutBitBranch },
507 { "BBR3", 0x0000000, 0x3F, 0, PutBitBranch },
508 { "BBR4", 0x0000000, 0x4F, 0, PutBitBranch },
509 { "BBR5", 0x0000000, 0x5F, 0, PutBitBranch },
510 { "BBR6", 0x0000000, 0x6F, 0, PutBitBranch },
511 { "BBR7", 0x0000000, 0x7F, 0, PutBitBranch },
512 { "BBS0", 0x0000000, 0x8F, 0, PutBitBranch },
513 { "BBS1", 0x0000000, 0x9F, 0, PutBitBranch },
514 { "BBS2", 0x0000000, 0xAF, 0, PutBitBranch },
515 { "BBS3", 0x0000000, 0xBF, 0, PutBitBranch },
516 { "BBS4", 0x0000000, 0xCF, 0, PutBitBranch },
517 { "BBS5", 0x0000000, 0xDF, 0, PutBitBranch },
518 { "BBS6", 0x0000000, 0xEF, 0, PutBitBranch },
519 { "BBS7", 0x0000000, 0xFF, 0, PutBitBranch },
520 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
521 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
522 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
523 { "BIT", 0x0A0006C, 0x00, 2, PutAll },
524 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
525 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
526 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
527 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
528 { "BRK", 0x0000001, 0x00, 0, PutAll },
529 { "BSR", 0x0040000, 0x63, 0, PutPCRel4510 },
530 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
531 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
532 { "CLC", 0x0000001, 0x18, 0, PutAll },
533 { "CLD", 0x0000001, 0xd8, 0, PutAll },
534 { "CLE", 0x0000001, 0x02, 0, PutAll },
535 { "CLI", 0x0000001, 0x58, 0, PutAll },
536 { "CLV", 0x0000001, 0xb8, 0, PutAll },
537 { "CMP", 0x080A66C, 0xc0, 0, PutAll },
538 { "CPX", 0x080000C, 0xe0, 1, PutAll },
539 { "CPY", 0x080000C, 0xc0, 1, PutAll },
540 { "CPZ", 0x080000C, 0xd0, 1, Put4510 },
541 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
542 { "DEC", 0x000006F, 0x00, 3, PutAll },
543 { "DEW", 0x0000004, 0xc3, 9, PutAll },
544 { "DEX", 0x0000001, 0xca, 0, PutAll },
545 { "DEY", 0x0000001, 0x88, 0, PutAll },
546 { "DEZ", 0x0000001, 0x3B, 0, PutAll },
547 { "EOM", 0x0000001, 0xea, 0, PutAll },
548 { "EOR", 0x080A66C, 0x40, 0, PutAll },
549 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
550 { "INC", 0x000006f, 0x00, 4, PutAll },
551 { "INW", 0x0000004, 0xe3, 9, PutAll },
552 { "INX", 0x0000001, 0xe8, 0, PutAll },
553 { "INY", 0x0000001, 0xc8, 0, PutAll },
554 { "INZ", 0x0000001, 0x1B, 0, PutAll },
555 { "JMP", 0x0010808, 0x4c, 6, PutAll },
556 { "JSR", 0x0010808, 0x20, 7, Put4510 },
557 { "LBCC", 0x0040000, 0x93, 0, PutPCRel4510 },
558 { "LBCS", 0x0040000, 0xb3, 0, PutPCRel4510 },
559 { "LBEQ", 0x0040000, 0xf3, 0, PutPCRel4510 },
560 { "LBMI", 0x0040000, 0x33, 0, PutPCRel4510 },
561 { "LBNE", 0x0040000, 0xd3, 0, PutPCRel4510 },
562 { "LBPL", 0x0040000, 0x13, 0, PutPCRel4510 },
563 { "LBRA", 0x0040000, 0x83, 0, PutPCRel4510 },
564 { "LBVC", 0x0040000, 0x53, 0, PutPCRel4510 },
565 { "LBVS", 0x0040000, 0x73, 0, PutPCRel4510 },
566 { "LDA", 0x090A66C, 0xa0, 0, Put4510 },
567 { "LDX", 0x080030C, 0xa2, 1, PutAll },
568 { "LDY", 0x080006C, 0xa0, 1, PutAll },
569 { "LDZ", 0x0800048, 0xa3, 1, Put4510 },
570 { "LSR", 0x000006F, 0x42, 1, PutAll },
571 { "MAP", 0x0000001, 0x5C, 0, PutAll },
572 { "NEG", 0x0000001, 0x42, 0, PutAll },
573 { "NOP", 0x0000001, 0xea, 0, PutAll }, /* == EOM */
574 { "ORA", 0x080A66C, 0x00, 0, PutAll },
575 { "PHA", 0x0000001, 0x48, 0, PutAll },
576 { "PHD", 0x8000008, 0xf4, 1, PutAll }, /* == PHW */
577 { "PHP", 0x0000001, 0x08, 0, PutAll },
578 { "PHW", 0x8000008, 0xf4, 1, PutAll },
579 { "PHX", 0x0000001, 0xda, 0, PutAll },
580 { "PHY", 0x0000001, 0x5a, 0, PutAll },
581 { "PHZ", 0x0000001, 0xdb, 0, PutAll },
582 { "PLA", 0x0000001, 0x68, 0, PutAll },
583 { "PLP", 0x0000001, 0x28, 0, PutAll },
584 { "PLX", 0x0000001, 0xfa, 0, PutAll },
585 { "PLY", 0x0000001, 0x7a, 0, PutAll },
586 { "PLZ", 0x0000001, 0xfb, 0, PutAll },
587 { "RMB0", 0x0000004, 0x07, 1, PutAll },
588 { "RMB1", 0x0000004, 0x17, 1, PutAll },
589 { "RMB2", 0x0000004, 0x27, 1, PutAll },
590 { "RMB3", 0x0000004, 0x37, 1, PutAll },
591 { "RMB4", 0x0000004, 0x47, 1, PutAll },
592 { "RMB5", 0x0000004, 0x57, 1, PutAll },
593 { "RMB6", 0x0000004, 0x67, 1, PutAll },
594 { "RMB7", 0x0000004, 0x77, 1, PutAll },
595 { "ROL", 0x000006F, 0x22, 1, PutAll },
596 { "ROR", 0x000006F, 0x62, 1, PutAll },
597 { "ROW", 0x0000008, 0xeb, 6, PutAll },
598 { "RTI", 0x0000001, 0x40, 0, PutAll },
599 { "RTN", 0x0800000, 0x62, 1, PutAll },
600 { "RTS", 0x0000001, 0x60, 0, PutAll },
601 { "SBC", 0x080A66C, 0xe0, 0, PutAll },
602 { "SEC", 0x0000001, 0x38, 0, PutAll },
603 { "SED", 0x0000001, 0xf8, 0, PutAll },
604 { "SEE", 0x0000001, 0x03, 0, PutAll },
605 { "SEI", 0x0000001, 0x78, 0, PutAll },
606 { "SMB0", 0x0000004, 0x87, 1, PutAll },
607 { "SMB1", 0x0000004, 0x97, 1, PutAll },
608 { "SMB2", 0x0000004, 0xA7, 1, PutAll },
609 { "SMB3", 0x0000004, 0xB7, 1, PutAll },
610 { "SMB4", 0x0000004, 0xC7, 1, PutAll },
611 { "SMB5", 0x0000004, 0xD7, 1, PutAll },
612 { "SMB6", 0x0000004, 0xE7, 1, PutAll },
613 { "SMB7", 0x0000004, 0xF7, 1, PutAll },
614 { "STA", 0x010A66C, 0x80, 0, Put4510 },
615 { "STX", 0x000030c, 0x82, 1, Put4510 },
616 { "STY", 0x000006c, 0x80, 1, Put4510 },
617 { "STZ", 0x000006c, 0x04, 5, PutAll },
618 { "TAB", 0x0000001, 0x5b, 0, PutAll },
619 { "TAX", 0x0000001, 0xaa, 0, PutAll },
620 { "TAY", 0x0000001, 0xa8, 0, PutAll },
621 { "TAZ", 0x0000001, 0x4b, 0, PutAll },
622 { "TBA", 0x0000001, 0x7b, 0, PutAll },
623 { "TRB", 0x000000c, 0x10, 1, PutAll },
624 { "TSB", 0x000000c, 0x00, 1, PutAll },
625 { "TSX", 0x0000001, 0xba, 0, PutAll },
626 { "TSY", 0x0000001, 0x0b, 0, PutAll },
627 { "TXA", 0x0000001, 0x8a, 0, PutAll },
628 { "TXS", 0x0000001, 0x9a, 0, PutAll },
629 { "TYA", 0x0000001, 0x98, 0, PutAll },
630 { "TYS", 0x0000001, 0x2b, 0, PutAll },
631 { "TZA", 0x0000001, 0x6b, 0, PutAll },
632 }
633};
634
635/* Instruction table for the 65816 */
636static const struct {
637 unsigned Count;
638 InsDesc Ins[100];
639} InsTab65816 = {
640 sizeof (InsTab65816.Ins) / sizeof (InsTab65816.Ins[0]),
641 {
642 { "ADC", 0x0b8f6fc, 0x60, 0, PutAll },
643 { "AND", 0x0b8f6fc, 0x20, 0, PutAll },
644 { "ASL", 0x000006e, 0x02, 1, PutAll },
645 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
646 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
647 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
648 { "BIT", 0x0a0006c, 0x00, 2, PutAll },
649 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
650 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
651 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
652 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
653 { "BRK", 0x0000005, 0x00, 6, PutAll },
654 { "BRL", 0x0040000, 0x82, 0, PutPCRel16 },
655 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
656 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
657 { "CLC", 0x0000001, 0x18, 0, PutAll },
658 { "CLD", 0x0000001, 0xd8, 0, PutAll },
659 { "CLI", 0x0000001, 0x58, 0, PutAll },
660 { "CLV", 0x0000001, 0xb8, 0, PutAll },
661 { "CMP", 0x0b8f6fc, 0xc0, 0, PutAll },
662 { "COP", 0x0000004, 0x02, 6, PutAll },
663 { "CPA", 0x0b8f6fc, 0xc0, 0, PutAll }, /* == CMP */
664 { "CPX", 0x0c0000c, 0xe0, 1, PutAll },
665 { "CPY", 0x0c0000c, 0xc0, 1, PutAll },
666 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
667 { "DEC", 0x000006F, 0x00, 3, PutAll },
668 { "DEX", 0x0000001, 0xca, 0, PutAll },
669 { "DEY", 0x0000001, 0x88, 0, PutAll },
670 { "EOR", 0x0b8f6fc, 0x40, 0, PutAll },
671 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
672 { "INC", 0x000006F, 0x00, 4, PutAll },
673 { "INX", 0x0000001, 0xe8, 0, PutAll },
674 { "INY", 0x0000001, 0xc8, 0, PutAll },
675 { "JML", 0x4000010, 0x5c, 1, PutAll },
676 { "JMP", 0x4010818, 0x4c, 6, PutAll },
677 { "JSL", 0x0000010, 0x20, 7, PutAll },
678 { "JSR", 0x0010018, 0x20, 7, PutAll },
679 { "LDA", 0x0b8f6fc, 0xa0, 0, PutAll },
680 { "LDX", 0x0c0030c, 0xa2, 1, PutAll },
681 { "LDY", 0x0c0006c, 0xa0, 1, PutAll },
682 { "LSR", 0x000006F, 0x42, 1, PutAll },
683 { "MVN", 0x1000000, 0x54, 0, PutBlockMove },
684 { "MVP", 0x1000000, 0x44, 0, PutBlockMove },
685 { "NOP", 0x0000001, 0xea, 0, PutAll },
686 { "ORA", 0x0b8f6fc, 0x00, 0, PutAll },
687 { "PEA", 0x0000008, 0xf4, 6, PutAll },
688 { "PEI", 0x0000400, 0xd4, 1, PutAll },
689 { "PER", 0x0040000, 0x62, 0, PutPCRel16 },
690 { "PHA", 0x0000001, 0x48, 0, PutAll },
691 { "PHB", 0x0000001, 0x8b, 0, PutAll },
692 { "PHD", 0x0000001, 0x0b, 0, PutAll },
693 { "PHK", 0x0000001, 0x4b, 0, PutAll },
694 { "PHP", 0x0000001, 0x08, 0, PutAll },
695 { "PHX", 0x0000001, 0xda, 0, PutAll },
696 { "PHY", 0x0000001, 0x5a, 0, PutAll },
697 { "PLA", 0x0000001, 0x68, 0, PutAll },
698 { "PLB", 0x0000001, 0xab, 0, PutAll },
699 { "PLD", 0x0000001, 0x2b, 0, PutAll },
700 { "PLP", 0x0000001, 0x28, 0, PutAll },
701 { "PLX", 0x0000001, 0xfa, 0, PutAll },
702 { "PLY", 0x0000001, 0x7a, 0, PutAll },
703 { "REP", 0x0800000, 0xc2, 1, PutREP },
704 { "ROL", 0x000006F, 0x22, 1, PutAll },
705 { "ROR", 0x000006F, 0x62, 1, PutAll },
706 { "RTI", 0x0000001, 0x40, 0, PutAll },
707 { "RTL", 0x0000001, 0x6b, 0, PutAll },
708 { "RTS", 0x0000001, 0x60, 0, PutRTS },
709 { "SBC", 0x0b8f6fc, 0xe0, 0, PutAll },
710 { "SEC", 0x0000001, 0x38, 0, PutAll },
711 { "SED", 0x0000001, 0xf8, 0, PutAll },
712 { "SEI", 0x0000001, 0x78, 0, PutAll },
713 { "SEP", 0x0800000, 0xe2, 1, PutSEP },
714 { "STA", 0x018f6fc, 0x80, 0, PutAll },
715 { "STP", 0x0000001, 0xdb, 0, PutAll },
716 { "STX", 0x000010c, 0x82, 1, PutAll },
717 { "STY", 0x000002c, 0x80, 1, PutAll },
718 { "STZ", 0x000006c, 0x04, 5, PutAll },
719 { "SWA", 0x0000001, 0xeb, 0, PutAll }, /* == XBA */
720 { "TAD", 0x0000001, 0x5b, 0, PutAll }, /* == TCD */
721 { "TAS", 0x0000001, 0x1b, 0, PutAll }, /* == TCS */
722 { "TAX", 0x0000001, 0xaa, 0, PutAll },
723 { "TAY", 0x0000001, 0xa8, 0, PutAll },
724 { "TCD", 0x0000001, 0x5b, 0, PutAll },
725 { "TCS", 0x0000001, 0x1b, 0, PutAll },
726 { "TDA", 0x0000001, 0x7b, 0, PutAll }, /* == TDC */
727 { "TDC", 0x0000001, 0x7b, 0, PutAll },
728 { "TRB", 0x000000c, 0x10, 1, PutAll },
729 { "TSA", 0x0000001, 0x3b, 0, PutAll }, /* == TSC */
730 { "TSB", 0x000000c, 0x00, 1, PutAll },
731 { "TSC", 0x0000001, 0x3b, 0, PutAll },
732 { "TSX", 0x0000001, 0xba, 0, PutAll },
733 { "TXA", 0x0000001, 0x8a, 0, PutAll },
734 { "TXS", 0x0000001, 0x9a, 0, PutAll },
735 { "TXY", 0x0000001, 0x9b, 0, PutAll },
736 { "TYA", 0x0000001, 0x98, 0, PutAll },
737 { "TYX", 0x0000001, 0xbb, 0, PutAll },
738 { "WAI", 0x0000001, 0xcb, 0, PutAll },
739 { "WDM", 0x0000004, 0x42, 6, PutAll },
740 { "XBA", 0x0000001, 0xeb, 0, PutAll },
741 { "XCE", 0x0000001, 0xfb, 0, PutAll }
742 }
743};
744
745/* Instruction table for the SWEET16 pseudo CPU */
746static const struct {
747 unsigned Count;
748 InsDesc Ins[26];
749} InsTabSweet16 = {
750 sizeof (InsTabSweet16.Ins) / sizeof (InsTabSweet16.Ins[0]),
751 {
752 { "ADD", AMSW16_REG, 0xA0, 0, PutSweet16 },
753 { "BC", AMSW16_BRA, 0x03, 0, PutSweet16Branch },
754 { "BK", AMSW16_IMP, 0x0A, 0, PutSweet16 },
755 { "BM", AMSW16_BRA, 0x05, 0, PutSweet16Branch },
756 { "BM1", AMSW16_BRA, 0x08, 0, PutSweet16Branch },
757 { "BNC", AMSW16_BRA, 0x02, 0, PutSweet16Branch },
758 { "BNM1", AMSW16_BRA, 0x09, 0, PutSweet16Branch },
759 { "BNZ", AMSW16_BRA, 0x07, 0, PutSweet16Branch },
760 { "BP", AMSW16_BRA, 0x04, 0, PutSweet16Branch },
761 { "BR", AMSW16_BRA, 0x01, 0, PutSweet16Branch },
762 { "BS", AMSW16_BRA, 0x0C, 0, PutSweet16Branch },
763 { "BZ", AMSW16_BRA, 0x06, 0, PutSweet16Branch },
764 { "CPR", AMSW16_REG, 0xD0, 0, PutSweet16 },
765 { "DCR", AMSW16_REG, 0xF0, 0, PutSweet16 },
766 { "INR", AMSW16_REG, 0xE0, 0, PutSweet16 },
767 { "LD", AMSW16_REG | AMSW16_IND, 0x00, 1, PutSweet16 },
768 { "LDD", AMSW16_IND, 0x60, 0, PutSweet16 },
769 { "POP", AMSW16_IND, 0x80, 0, PutSweet16 },
770 { "POPD", AMSW16_IND, 0xC0, 0, PutSweet16 },
771 { "RS", AMSW16_IMP, 0x0B, 0, PutSweet16 },
772 { "RTN", AMSW16_IMP, 0x00, 0, PutSweet16 },
773 { "SET", AMSW16_IMM, 0x10, 0, PutSweet16 },
774 { "ST", AMSW16_REG | AMSW16_IND, 0x10, 1, PutSweet16 },
775 { "STD", AMSW16_IND, 0x70, 0, PutSweet16 },
776 { "STP", AMSW16_IND, 0x90, 0, PutSweet16 },
777 { "SUB", AMSW16_REG, 0xB0, 0, PutSweet16 },
778 }
779};
780
781/* Instruction table for the HuC6280 (the CPU used in the PC engine) */
782static const struct {
783 unsigned Count;
784 InsDesc Ins[135];
785} InsTabHuC6280 = {
786 sizeof (InsTabHuC6280.Ins) / sizeof (InsTabHuC6280.Ins[0]),
787 {
788 { "ADC", 0x080A66C, 0x60, 0, PutAll },
789 { "AND", 0x080A66C, 0x20, 0, PutAll },
790 { "ASL", 0x000006e, 0x02, 1, PutAll },
791 { "BBR0", 0x0000000, 0x0F, 0, PutBitBranch },
792 { "BBR1", 0x0000000, 0x1F, 0, PutBitBranch },
793 { "BBR2", 0x0000000, 0x2F, 0, PutBitBranch },
794 { "BBR3", 0x0000000, 0x3F, 0, PutBitBranch },
795 { "BBR4", 0x0000000, 0x4F, 0, PutBitBranch },
796 { "BBR5", 0x0000000, 0x5F, 0, PutBitBranch },
797 { "BBR6", 0x0000000, 0x6F, 0, PutBitBranch },
798 { "BBR7", 0x0000000, 0x7F, 0, PutBitBranch },
799 { "BBS0", 0x0000000, 0x8F, 0, PutBitBranch },
800 { "BBS1", 0x0000000, 0x9F, 0, PutBitBranch },
801 { "BBS2", 0x0000000, 0xAF, 0, PutBitBranch },
802 { "BBS3", 0x0000000, 0xBF, 0, PutBitBranch },
803 { "BBS4", 0x0000000, 0xCF, 0, PutBitBranch },
804 { "BBS5", 0x0000000, 0xDF, 0, PutBitBranch },
805 { "BBS6", 0x0000000, 0xEF, 0, PutBitBranch },
806 { "BBS7", 0x0000000, 0xFF, 0, PutBitBranch },
807 { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
808 { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
809 { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
810 { "BIT", 0x0A0006C, 0x00, 2, PutAll },
811 { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
812 { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
813 { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
814 { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
815 { "BRK", 0x0000001, 0x00, 0, PutAll },
816 { "BSR", 0x0020000, 0x44, 0, PutPCRel8 },
817 { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
818 { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
819 { "CLA", 0x0000001, 0x62, 0, PutAll },
820 { "CLC", 0x0000001, 0x18, 0, PutAll },
821 { "CLD", 0x0000001, 0xd8, 0, PutAll },
822 { "CLI", 0x0000001, 0x58, 0, PutAll },
823 { "CLV", 0x0000001, 0xb8, 0, PutAll },
824 { "CLX", 0x0000001, 0x82, 0, PutAll },
825 { "CLY", 0x0000001, 0xc2, 0, PutAll },
826 { "CMP", 0x080A66C, 0xc0, 0, PutAll },
827 { "CPX", 0x080000C, 0xe0, 1, PutAll },
828 { "CPY", 0x080000C, 0xc0, 1, PutAll },
829 { "CSH", 0x0000001, 0xd4, 0, PutAll },
830 { "CSL", 0x0000001, 0x54, 0, PutAll },
831 { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
832 { "DEC", 0x000006F, 0x00, 3, PutAll },
833 { "DEX", 0x0000001, 0xca, 0, PutAll },
834 { "DEY", 0x0000001, 0x88, 0, PutAll },
835 { "EOR", 0x080A66C, 0x40, 0, PutAll },
836 { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
837 { "INC", 0x000006f, 0x00, 4, PutAll },
838 { "INX", 0x0000001, 0xe8, 0, PutAll },
839 { "INY", 0x0000001, 0xc8, 0, PutAll },
840 { "JMP", 0x0010808, 0x4c, 6, PutAll },
841 { "JSR", 0x0000008, 0x20, 7, PutAll },
842 { "LDA", 0x080A66C, 0xa0, 0, PutAll },
843 { "LDX", 0x080030C, 0xa2, 1, PutAll },
844 { "LDY", 0x080006C, 0xa0, 1, PutAll },
845 { "LSR", 0x000006F, 0x42, 1, PutAll },
846 { "NOP", 0x0000001, 0xea, 0, PutAll },
847 { "ORA", 0x080A66C, 0x00, 0, PutAll },
848 { "PHA", 0x0000001, 0x48, 0, PutAll },
849 { "PHP", 0x0000001, 0x08, 0, PutAll },
850 { "PHX", 0x0000001, 0xda, 0, PutAll },
851 { "PHY", 0x0000001, 0x5a, 0, PutAll },
852 { "PLA", 0x0000001, 0x68, 0, PutAll },
853 { "PLP", 0x0000001, 0x28, 0, PutAll },
854 { "PLX", 0x0000001, 0xfa, 0, PutAll },
855 { "PLY", 0x0000001, 0x7a, 0, PutAll },
856 { "RMB0", 0x0000004, 0x07, 1, PutAll },
857 { "RMB1", 0x0000004, 0x17, 1, PutAll },
858 { "RMB2", 0x0000004, 0x27, 1, PutAll },
859 { "RMB3", 0x0000004, 0x37, 1, PutAll },
860 { "RMB4", 0x0000004, 0x47, 1, PutAll },
861 { "RMB5", 0x0000004, 0x57, 1, PutAll },
862 { "RMB6", 0x0000004, 0x67, 1, PutAll },
863 { "RMB7", 0x0000004, 0x77, 1, PutAll },
864 { "ROL", 0x000006F, 0x22, 1, PutAll },
865 { "ROR", 0x000006F, 0x62, 1, PutAll },
866 { "RTI", 0x0000001, 0x40, 0, PutAll },
867 { "RTS", 0x0000001, 0x60, 0, PutAll },
868 { "SAX", 0x0000001, 0x22, 0, PutAll },
869 { "SAY", 0x0000001, 0x42, 0, PutAll },
870 { "SBC", 0x080A66C, 0xe0, 0, PutAll },
871 { "SEC", 0x0000001, 0x38, 0, PutAll },
872 { "SED", 0x0000001, 0xf8, 0, PutAll },
873 { "SEI", 0x0000001, 0x78, 0, PutAll },
874 { "SET", 0x0000001, 0xf4, 0, PutAll },
875 { "SMB0", 0x0000004, 0x87, 1, PutAll },
876 { "SMB1", 0x0000004, 0x97, 1, PutAll },
877 { "SMB2", 0x0000004, 0xA7, 1, PutAll },
878 { "SMB3", 0x0000004, 0xB7, 1, PutAll },
879 { "SMB4", 0x0000004, 0xC7, 1, PutAll },
880 { "SMB5", 0x0000004, 0xD7, 1, PutAll },
881 { "SMB6", 0x0000004, 0xE7, 1, PutAll },
882 { "SMB7", 0x0000004, 0xF7, 1, PutAll },
883 { "ST0", 0x0800000, 0x03, 1, PutAll },
884 { "ST1", 0x0800000, 0x13, 1, PutAll },
885 { "ST2", 0x0800000, 0x23, 1, PutAll },
886 { "STA", 0x000A66C, 0x80, 0, PutAll },
887 { "STX", 0x000010c, 0x82, 1, PutAll },
888 { "STY", 0x000002c, 0x80, 1, PutAll },
889 { "STZ", 0x000006c, 0x04, 5, PutAll },
890 { "SXY", 0x0000001, 0x02, 0, PutAll },
891 { "TAI", 0x2000000, 0xf3, 0, PutBlockTransfer },
892 { "TAM", 0x0800000, 0x53, 1, PutAll },
893 { "TAM0", 0x0000001, 0x01, 0, PutTAMn},
894 { "TAM1", 0x0000001, 0x02, 0, PutTAMn},
895 { "TAM2", 0x0000001, 0x04, 0, PutTAMn},
896 { "TAM3", 0x0000001, 0x08, 0, PutTAMn},
897 { "TAM4", 0x0000001, 0x10, 0, PutTAMn},
898 { "TAM5", 0x0000001, 0x20, 0, PutTAMn},
899 { "TAM6", 0x0000001, 0x40, 0, PutTAMn},
900 { "TAM7", 0x0000001, 0x80, 0, PutTAMn},
901 { "TAX", 0x0000001, 0xaa, 0, PutAll },
902 { "TAY", 0x0000001, 0xa8, 0, PutAll },
903 { "TDD", 0x2000000, 0xc3, 0, PutBlockTransfer },
904 { "TIA", 0x2000000, 0xe3, 0, PutBlockTransfer },
905 { "TII", 0x2000000, 0x73, 0, PutBlockTransfer },
906 { "TIN", 0x2000000, 0xD3, 0, PutBlockTransfer },
907 { "TMA", 0x0800000, 0x43, 1, PutTMA },
908 { "TMA0", 0x0000001, 0x01, 0, PutTMAn},
909 { "TMA1", 0x0000001, 0x02, 0, PutTMAn},
910 { "TMA2", 0x0000001, 0x04, 0, PutTMAn},
911 { "TMA3", 0x0000001, 0x08, 0, PutTMAn},
912 { "TMA4", 0x0000001, 0x10, 0, PutTMAn},
913 { "TMA5", 0x0000001, 0x20, 0, PutTMAn},
914 { "TMA6", 0x0000001, 0x40, 0, PutTMAn},
915 { "TMA7", 0x0000001, 0x80, 0, PutTMAn},
916 { "TRB", 0x000000c, 0x10, 1, PutAll },
917 { "TSB", 0x000000c, 0x00, 1, PutAll },
918 { "TST", 0x000006c, 0x83, 9, PutTST },
919 { "TSX", 0x0000001, 0xba, 0, PutAll },
920 { "TXA", 0x0000001, 0x8a, 0, PutAll },
921 { "TXS", 0x0000001, 0x9a, 0, PutAll },
922 { "TYA", 0x0000001, 0x98, 0, PutAll }
923 }
924};
925
926
927
928/* An array with instruction tables */
929static const InsTable* InsTabs[CPU_COUNT] = {
930 (const InsTable*) &InsTabNone,
931 (const InsTable*) &InsTab6502,
932 (const InsTable*) &InsTab6502X,
933 (const InsTable*) &InsTab65SC02,
934 (const InsTable*) &InsTab65C02,
935 (const InsTable*) &InsTab65816,
936 (const InsTable*) &InsTabSweet16,
937 (const InsTable*) &InsTabHuC6280,
938 0, /* Mitsubishi 740 */
939 (const InsTable*) &InsTab4510,
940};
941const InsTable* InsTab = (const InsTable*) &InsTab6502;
942
943/* Table to build the effective 65xx opcode from a base opcode and an
944** addressing mode. (The value in the table is ORed with the base opcode)
945*/
946static unsigned char EATab[12][AM65I_COUNT] = {
947 { /* Table 0 */
948 0x00, 0x00, 0x05, 0x0D, 0x0F, 0x15, 0x1D, 0x1F,
949 0x00, 0x19, 0x12, 0x00, 0x07, 0x11, 0x17, 0x01,
950 0x00, 0x00, 0x00, 0x03, 0x13, 0x09, 0x00, 0x09,
951 0x00, 0x00, 0x00, 0x00
952 },
953 { /* Table 1 */
954 0x08, 0x08, 0x04, 0x0C, 0x00, 0x14, 0x1C, 0x00,
955 0x14, 0x1C, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00,
956 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
957 0x00, 0x00, 0x80, 0x00
958 },
959 { /* Table 2 */
960 0x00, 0x00, 0x24, 0x2C, 0x0F, 0x34, 0x3C, 0x00,
961 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
962 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00,
963 0x00, 0x00, 0x00, 0x00
964 },
965 { /* Table 3 */
966 0x3A, 0x3A, 0xC6, 0xCE, 0x00, 0xD6, 0xDE, 0x00,
967 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
968 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
969 0x00, 0x00, 0x00, 0x00
970 },
971 { /* Table 4 */
972 0x1A, 0x1A, 0xE6, 0xEE, 0x00, 0xF6, 0xFE, 0x00,
973 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
974 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
975 0x00, 0x00, 0x00, 0x00
976 },
977 { /* Table 5 */
978 0x00, 0x00, 0x60, 0x98, 0x00, 0x70, 0x9E, 0x00,
979 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
980 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
981 0x00, 0x00, 0x00, 0x00
982 },
983 { /* Table 6 */
984 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
985 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
986 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
987 0x00, 0x00, 0x90, 0x00
988 },
989 { /* Table 7 (Subroutine opcodes) */
990 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
991 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
992 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
993 0x00, 0x00, 0x00, 0x00
994 },
995 { /* Table 8 */
996 0x00, 0x40, 0x01, 0x41, 0x00, 0x09, 0x49, 0x00,
997 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00,
998 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
999 0x00, 0x00, 0x00, 0x00
1000 },
1001 { /* Table 9 */
1002 0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x30, 0x00,
1003 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1004 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1005 0x00, 0x00, 0x00, 0x00
1006 },
1007 { /* Table 10 (NOPs) */
1008 0xea, 0x00, 0x04, 0x0c, 0x00, 0x14, 0x1c, 0x00,
1009 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1010 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
1011 0x00, 0x00, 0x00, 0x00
1012 },
1013 { /* Table 11 (LAX) */
1014 0x08, 0x08, 0x04, 0x0C, 0x00, 0x14, 0x1C, 0x00,
1015 0x14, 0x1C, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00,
1016 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
1017 0x00, 0x00, 0x80, 0x00
1018 },
1019};
1020
1021/* Table to build the effective SWEET16 opcode from a base opcode and an
1022** addressing mode.
1023*/
1024static unsigned char Sweet16EATab[2][AMSW16I_COUNT] = {
1025 { /* Table 0 */
1026 0x00, 0x00, 0x00, 0x00, 0x00,
1027 },
1028 { /* Table 1 */
1029 0x00, 0x00, 0x00, 0x40, 0x20,
1030 },
1031};
1032
1033/* Table that encodes the additional bytes for each 65xx instruction */
1034unsigned char ExtBytes[AM65I_COUNT] = {
1035 0, /* Implicit */
1036 0, /* Accu */
1037 1, /* Direct */
1038 2, /* Absolute */
1039 3, /* Absolute long */
1040 1, /* Direct,X */
1041 2, /* Absolute,X */
1042 3, /* Absolute long,X */
1043 1, /* Direct,Y */
1044 2, /* Absolute,Y */
1045 1, /* (Direct) */
1046 2, /* (Absolute) */
1047 1, /* [Direct] */
1048 1, /* (Direct),Y */
1049 1, /* [Direct],Y */
1050 1, /* (Direct,X) */
1051 2, /* (Absolute,X) */
1052 1, /* Relative short */
1053 2, /* Relative long */
1054 1, /* r,s */
1055 1, /* (r,s),y */
1056 1, /* Immidiate accu */
1057 1, /* Immidiate index */
1058 1, /* Immidiate byte */
1059 2, /* Blockmove (65816) */
1060 7, /* Block transfer (HuC6280) */
1061 2, /* Absolute Indirect long */
1062 2, /* Immidiate word */
1063};
1064
1065/* Table that encodes the additional bytes for each SWEET16 instruction */
1066static unsigned char Sweet16ExtBytes[AMSW16I_COUNT] = {
1067 0, /* AMSW16_IMP */
1068 1, /* AMSW16_BRA */
1069 2, /* AMSW16_IMM */
1070 0, /* AMSW16_IND */
1071 0, /* AMSW16_REG */
1072};
1073
1074
1075
1076/*****************************************************************************/
1077/* Handler functions for 6502 derivates */
1078/*****************************************************************************/
1079
1080
1081
1082static int EvalEA (const InsDesc* Ins, EffAddr* A)
1083/* Evaluate the effective address. All fields in A will be valid after calling
1084** this function. The function returns true on success and false on errors.
1085*/
1086{
1087 /* Get the set of possible addressing modes */
1088 GetEA (A);
1089
1090 /* From the possible addressing modes, remove the ones that are invalid
1091 ** for this instruction or CPU.
1092 */
1093 A->AddrModeSet &= Ins->AddrMode;
1094
1095 /* If we have an expression, check it and remove any addressing modes that
1096 ** are too small for the expression size. Since we have to study the
1097 ** expression anyway, do also replace it by a simpler one if possible.
1098 */
1099 if (A->Expr) {
1100 ExprDesc ED;
1101 ED_Init (&ED);
1102
1103 /* Study the expression */
1104 StudyExpr (A->Expr, &ED);
1105
1106 /* Simplify it if possible */
1107 A->Expr = SimplifyExpr (A->Expr, &ED);
1108
1109 if (ED.AddrSize == ADDR_SIZE_DEFAULT) {
1110 /* We don't know how big the expression is. If the instruction
1111 ** allows just one addressing mode, assume this as address size
1112 ** for the expression. Otherwise assume the default address size
1113 ** for data.
1114 */
1115 if ((A->AddrModeSet & ~AM65_ALL_ZP) == 0) {
1116 ED.AddrSize = ADDR_SIZE_ZP;
1117 } else if ((A->AddrModeSet & ~AM65_ALL_ABS) == 0) {
1118 ED.AddrSize = ADDR_SIZE_ABS;
1119 } else if ((A->AddrModeSet & ~AM65_ALL_FAR) == 0) {
1120 ED.AddrSize = ADDR_SIZE_FAR;
1121 } else {
1122 ED.AddrSize = DataAddrSize;
1123 /* If the default address size of the data segment is unequal
1124 ** to zero page addressing, but zero page addressing is
1125 ** allowed by the instruction, mark all symbols in the
1126 ** expression tree. This mark will be checked at end of
1127 ** assembly, and a warning is issued, if a zero page symbol
1128 ** was guessed wrong here.
1129 */
1130 if (ED.AddrSize > ADDR_SIZE_ZP && (A->AddrModeSet & AM65_SET_ZP)) {
1131 ExprGuessedAddrSize (A->Expr, ADDR_SIZE_ZP);
1132 }
1133 }
1134 }
1135
1136 /* Check the size */
1137 switch (ED.AddrSize) {
1138
1139 case ADDR_SIZE_ABS:
1140 A->AddrModeSet &= ~AM65_SET_ZP;
1141 break;
1142
1143 case ADDR_SIZE_FAR:
1144 A->AddrModeSet &= ~(AM65_SET_ZP | AM65_SET_ABS);
1145 break;
1146 }
1147
1148 /* Free any resource associated with the expression desc */
1149 ED_Done (&ED);
1150 }
1151
1152 /* Check if we have any adressing modes left */
1153 if (A->AddrModeSet == 0) {
1154 Error ("Illegal addressing mode");
1155 return 0;
1156 }
1157 A->AddrMode = BitFind (A->AddrModeSet);
1158 A->AddrModeBit = (0x01UL << A->AddrMode);
1159
1160 /* If the instruction has a one byte operand and immediate addressing is
1161 ** allowed but not used, check for an operand expression in the form
1162 ** <label or >label, where label is a far or absolute label. If found,
1163 ** emit a warning. This warning protects against a typo, where the '#'
1164 ** for the immediate operand is omitted.
1165 */
1166 if (A->Expr && (Ins->AddrMode & AM65_ALL_IMM) &&
1167 (A->AddrModeSet & (AM65_DIR | AM65_ABS | AM65_ABS_LONG)) &&
1168 ExtBytes[A->AddrMode] == 1) {
1169
1170 /* Found, check the expression */
1171 ExprNode* Left = A->Expr->Left;
1172 if ((A->Expr->Op == EXPR_BYTE0 || A->Expr->Op == EXPR_BYTE1) &&
1173 Left->Op == EXPR_SYMBOL &&
1174 GetSymAddrSize (Left->V.Sym) != ADDR_SIZE_ZP) {
1175
1176 /* Output a warning */
1177 Warning (1, "Suspicious address expression");
1178 }
1179 }
1180
1181 /* Build the opcode */
1182 A->Opcode = Ins->BaseCode | EATab[Ins->ExtCode][A->AddrMode];
1183
1184 /* If feature force_range is active, and we have immediate addressing mode,
1185 ** limit the expression to the maximum possible value.
1186 */
1187 if (A->AddrMode == AM65I_IMM_ACCU || A->AddrMode == AM65I_IMM_INDEX ||
1188 A->AddrMode == AM65I_IMM_IMPLICIT || A->AddrMode == AM65I_IMM_IMPLICIT_WORD) {
1189 if (ForceRange && A->Expr) {
1190 A->Expr = MakeBoundedExpr (A->Expr, ExtBytes[A->AddrMode]);
1191 }
1192 }
1193
1194 /* Success */
1195 return 1;
1196}
1197
1198
1199
1200static void EmitCode (EffAddr* A)
1201/* Output code for the data in A */
1202{
1203 /* Check how many extension bytes are needed and output the instruction */
1204 switch (ExtBytes[A->AddrMode]) {
1205
1206 case 0:
1207 Emit0 (A->Opcode);
1208 break;
1209
1210 case 1:
1211 Emit1 (A->Opcode, A->Expr);
1212 break;
1213
1214 case 2:
1215 if (CPU == CPU_65816 && (A->AddrModeBit & (AM65_ABS | AM65_ABS_X | AM65_ABS_Y))) {
1216 /* This is a 16 bit mode that uses an address. If in 65816,
1217 ** mode, force this address into 16 bit range to allow
1218 ** addressing inside a 64K segment.
1219 */
1220 Emit2 (A->Opcode, GenNearAddrExpr (A->Expr));
1221 } else {
1222 Emit2 (A->Opcode, A->Expr);
1223 }
1224 break;
1225
1226 case 3:
1227 /* Far argument */
1228 Emit3 (A->Opcode, A->Expr);
1229 break;
1230
1231 default:
1232 Internal ("Invalid operand byte count: %u", ExtBytes[A->AddrMode]);
1233
1234 }
1235}
1236
1237
1238
1239static long PutImmed8 (const InsDesc* Ins)
1240/* Parse and emit an immediate 8 bit instruction. Return the value of the
1241** operand if it's available and const.
1242*/
1243{
1244 EffAddr A;
1245 long Val = -1;
1246
1247 /* Evaluate the addressing mode */
1248 if (EvalEA (Ins, &A) == 0) {
1249 /* An error occurred */
1250 return -1L;
1251 }
1252
1253 /* If we have an expression and it's const, get it's value */
1254 if (A.Expr) {
1255 (void) IsConstExpr (A.Expr, &Val);
1256 }
1257
1258 /* Check how many extension bytes are needed and output the instruction */
1259 switch (ExtBytes[A.AddrMode]) {
1260
1261 case 1:
1262 Emit1 (A.Opcode, A.Expr);
1263 break;
1264
1265 default:
1266 Internal ("Invalid operand byte count: %u", ExtBytes[A.AddrMode]);
1267 }
1268
1269 /* Return the expression value */
1270 return Val;
1271}
1272
1273
1274
1275static void PutPCRel8 (const InsDesc* Ins)
1276/* Handle branches with a 8 bit distance */
1277{
1278 EmitPCRel (Ins->BaseCode, GenBranchExpr (2), 1);
1279}
1280
1281
1282
1283static void PutPCRel16 (const InsDesc* Ins)
1284/* Handle branches with an 16 bit distance and PER */
1285{
1286 EmitPCRel (Ins->BaseCode, GenBranchExpr (3), 2);
1287}
1288
1289
1290
1291static void PutPCRel4510 (const InsDesc* Ins)
1292/* Handle branches with a 16 bit distance */
1293{
1294 /* 16 bit branch opcode is 8 bit branch opcode or'ed with 0x03 */
1295 EmitPCRel (Ins->BaseCode, GenBranchExpr (2), 2);
1296}
1297
1298
1299
1300static void PutBlockMove (const InsDesc* Ins)
1301/* Handle the blockmove instructions (65816) */
1302{
1303 ExprNode* Arg1;
1304 ExprNode* Arg2;
1305
1306 Emit0 (Ins->BaseCode);
1307
1308 if (CurTok.Tok == TOK_HASH) {
1309 /* The operand is a bank-byte expression. */
1310 NextTok ();
1311 Arg1 = Expression ();
1312 } else {
1313 /* The operand is a far-address expression.
1314 ** Use only its bank part.
1315 */
1316 Arg1 = FuncBankByte ();
1317 }
1318 ConsumeComma ();
1319
1320 if (CurTok.Tok == TOK_HASH) {
1321 NextTok ();
1322 Arg2 = Expression ();
1323 } else {
1324 Arg2 = FuncBankByte ();
1325 }
1326
1327 /* The operands are written in Assembly code as source, destination;
1328 ** but, they're assembled as <destination> <source>.
1329 */
1330 EmitByte (Arg2);
1331 EmitByte (Arg1);
1332}
1333
1334
1335
1336static void PutBlockTransfer (const InsDesc* Ins)
1337/* Handle the block transfer instructions (HuC6280) */
1338{
1339 Emit0 (Ins->BaseCode);
1340 EmitWord (Expression ());
1341 ConsumeComma ();
1342 EmitWord (Expression ());
1343 ConsumeComma ();
1344 EmitWord (Expression ());
1345}
1346
1347
1348
1349static void PutBitBranch (const InsDesc* Ins)
1350/* Handle 65C02 branch on bit condition */
1351{
1352 Emit0 (Ins->BaseCode);
1353 EmitByte (Expression ());
1354 ConsumeComma ();
1355 EmitSigned (GenBranchExpr (1), 1);
1356}
1357
1358
1359
1360static void PutREP (const InsDesc* Ins)
1361/* Emit a REP instruction, track register sizes */
1362{
1363 /* Use the generic handler */
1364 long Val = PutImmed8 (Ins);
1365
1366 /* We track the status only for the 816 CPU and in smart mode */
1367 if (CPU == CPU_65816 && SmartMode) {
1368
1369 /* Check the range for Val. */
1370 if (Val < 0) {
1371 /* We had an error */
1372 Warning (1, "Cannot track processor status byte");
1373 } else {
1374 if (Val & 0x10) {
1375 /* Index registers to 16 bit */
1376 ExtBytes[AM65I_IMM_INDEX] = 2;
1377 }
1378 if (Val & 0x20) {
1379 /* Accu to 16 bit */
1380 ExtBytes[AM65I_IMM_ACCU] = 2;
1381 }
1382 }
1383 }
1384}
1385
1386
1387
1388static void PutSEP (const InsDesc* Ins)
1389/* Emit a SEP instruction (65816), track register sizes */
1390{
1391 /* Use the generic handler */
1392 long Val = PutImmed8 (Ins);
1393
1394 /* We track the status only for the 816 CPU and in smart mode */
1395 if (CPU == CPU_65816 && SmartMode) {
1396
1397 /* Check the range for Val. */
1398 if (Val < 0) {
1399 /* We had an error */
1400 Warning (1, "Cannot track processor status byte");
1401 } else {
1402 if (Val & 0x10) {
1403 /* Index registers to 8 bit */
1404 ExtBytes[AM65I_IMM_INDEX] = 1;
1405 }
1406 if (Val & 0x20) {
1407 /* Accu to 8 bit */
1408 ExtBytes[AM65I_IMM_ACCU] = 1;
1409 }
1410 }
1411 }
1412}
1413
1414
1415
1416static void PutTAMn (const InsDesc* Ins)
1417/* Emit a TAMn instruction (HuC6280). Since this is a two byte instruction with
1418** implicit addressing mode, the opcode byte in the table is actually the
1419** second operand byte. The TAM instruction is the more generic form, it takes
1420** an immediate argument.
1421*/
1422{
1423 /* Emit the TAM opcode itself */
1424 Emit0 (0x53);
1425
1426 /* Emit the argument, which is the opcode from the table */
1427 Emit0 (Ins->BaseCode);
1428}
1429
1430
1431
1432static void PutTMA (const InsDesc* Ins)
1433/* Emit a TMA instruction (HuC6280) with an immediate argument. Only one bit
1434** in the argument byte may be set.
1435*/
1436{
1437 /* Use the generic handler */
1438 long Val = PutImmed8 (Ins);
1439
1440 /* Check the range for Val. */
1441 if (Val < 0) {
1442 /* We had an error */
1443 Warning (1, "Cannot check argument of TMA instruction");
1444 } else {
1445 /* Make sure just one bit is set */
1446 if ((Val & (Val - 1)) != 0) {
1447 Error ("Argument to TAM must be a power of two");
1448 }
1449 }
1450}
1451
1452
1453
1454static void PutTMAn (const InsDesc* Ins)
1455/* Emit a TMAn instruction (HuC6280). Since this is a two byte instruction with
1456** implicit addressing mode, the opcode byte in the table is actually the
1457** second operand byte. The TAM instruction is the more generic form, it takes
1458** an immediate argument.
1459*/
1460{
1461 /* Emit the TMA opcode itself */
1462 Emit0 (0x43);
1463
1464 /* Emit the argument, which is the opcode from the table */
1465 Emit0 (Ins->BaseCode);
1466}
1467
1468
1469
1470static void PutTST (const InsDesc* Ins)
1471/* Emit a TST instruction (HuC6280). */
1472{
1473 ExprNode* Arg1;
1474 EffAddr A;
1475
1476 /* The first argument is always an immediate byte */
1477 if (CurTok.Tok != TOK_HASH) {
1478 ErrorSkip ("Invalid addressing mode");
1479 return;
1480 }
1481 NextTok ();
1482 Arg1 = Expression ();
1483
1484 /* Second argument follows */
1485 ConsumeComma ();
1486
1487 /* For the second argument, we use the standard function */
1488 if (EvalEA (Ins, &A)) {
1489
1490 /* No error, output code */
1491 Emit1 (A.Opcode, Arg1);
1492
1493 /* Check how many extension bytes are needed and output the instruction */
1494 switch (ExtBytes[A.AddrMode]) {
1495
1496 case 1:
1497 EmitByte (A.Expr);
1498 break;
1499
1500 case 2:
1501 EmitWord (A.Expr);
1502 break;
1503 }
1504 }
1505}
1506
1507
1508
1509static void PutJMP (const InsDesc* Ins)
1510/* Handle the jump instruction for the 6502. Problem is that these chips have
1511** a bug: If the address crosses a page, the upper byte gets not corrected and
1512** the instruction will fail. The PutJmp function will add a linker assertion
1513** to check for this case and is otherwise identical to PutAll.
1514*/
1515{
1516 EffAddr A;
1517
1518 /* Evaluate the addressing mode used */
1519 if (EvalEA (Ins, &A)) {
1520
1521 /* Check for indirect addressing */
1522 if (A.AddrModeBit & AM65_ABS_IND) {
1523
1524 /* Compare the low byte of the expression to 0xFF to check for
1525 ** a page cross. Be sure to use a copy of the expression otherwise
1526 ** things will go weird later.
1527 */
1528 ExprNode* E = GenNE (GenByteExpr (CloneExpr (A.Expr)), 0xFF);
1529
1530 /* Generate the message */
1531 unsigned Msg = GetStringId ("\"jmp (abs)\" across page border");
1532
1533 /* Generate the assertion */
1534 AddAssertion (E, ASSERT_ACT_WARN, Msg);
1535 }
1536
1537 /* No error, output code */
1538 EmitCode (&A);
1539 }
1540}
1541
1542
1543
1544static void PutRTS (const InsDesc* Ins attribute ((unused)))
1545/* Handle the RTS instruction for the 816. In smart mode emit a RTL opcode if
1546** the enclosing scope is FAR.
1547*/
1548{
1549 if (SmartMode && CurrentScope->AddrSize == ADDR_SIZE_FAR) {
1550 Emit0 (0x6B); /* RTL */
1551 } else {
1552 Emit0 (0x60); /* RTS */
1553 }
1554}
1555
1556
1557
1558static void PutAll (const InsDesc* Ins)
1559/* Handle all other instructions */
1560{
1561 EffAddr A;
1562
1563 /* Evaluate the addressing mode used */
1564 if (EvalEA (Ins, &A)) {
1565 /* No error, output code */
1566 EmitCode (&A);
1567 }
1568}
1569
1570
1571
1572static void Put4510 (const InsDesc* Ins)
1573/* Handle all other instructions, with modifications for 4510 */
1574{
1575 /* The 4510 uses all 256 possible opcodes, so the last ones were crammed
1576 ** in where an opcode was still undefined. As a result, some of those
1577 ** don't follow any rules for encoding the addressmodes. So the EATab
1578 ** approach does not work always. In this function, the wrongly calculated
1579 ** opcode is replaced by the correct one "on the fly". Suggestions for a
1580 ** better approach are welcome.
1581 **
1582 ** These are:
1583 ** $47 -> $44 : ASR $12
1584 ** $57 -> $54 : ASR $12,X
1585 ** $93 -> $82 : STA ($12,SP),Y
1586 ** $9c -> $8b : STY $1234,X
1587 ** $9e -> $9b : STX $1234,Y
1588 ** $af -> $ab : LDZ $1234
1589 ** $bf -> $bb : LDZ $1234,X
1590 ** $b3 -> $e2 : LDA ($12,SP),Y
1591 ** $d0 -> $c2 : CPZ #$00
1592 ** $fc -> $23 : JSR ($1234,X)
1593 */
1594 EffAddr A;
1595
1596 /* Evaluate the addressing mode used */
1597 if (EvalEA (Ins, &A)) {
1598 switch (A.Opcode) {
1599 case 0x47: A.Opcode = 0x44; break;
1600 case 0x57: A.Opcode = 0x54; break;
1601 case 0x93: A.Opcode = 0x82; break;
1602 case 0x9C: A.Opcode = 0x8B; break;
1603 case 0x9E: A.Opcode = 0x9B; break;
1604 case 0xAF: A.Opcode = 0xAB; break;
1605 case 0xBF: A.Opcode = 0xBB; break;
1606 case 0xB3: A.Opcode = 0xE2; break;
1607 case 0xD0: A.Opcode = 0xC2; break;
1608 case 0xFC: A.Opcode = 0x23; break;
1609 default: /* Keep opcode as it is */ break;
1610 }
1611
1612 /* No error, output code */
1613 EmitCode (&A);
1614 }
1615}
1616
1617
1618
1619/*****************************************************************************/
1620/* Handler functions for SWEET16 */
1621/*****************************************************************************/
1622
1623
1624
1625static void PutSweet16 (const InsDesc* Ins)
1626/* Handle a generic sweet16 instruction */
1627{
1628 EffAddr A;
1629
1630 /* Evaluate the addressing mode used */
1631 GetSweet16EA (&A);
1632
1633 /* From the possible addressing modes, remove the ones that are invalid
1634 ** for this instruction or CPU.
1635 */
1636 A.AddrModeSet &= Ins->AddrMode;
1637
1638 /* Check if we have any adressing modes left */
1639 if (A.AddrModeSet == 0) {
1640 Error ("Illegal addressing mode");
1641 return;
1642 }
1643 A.AddrMode = BitFind (A.AddrModeSet);
1644 A.AddrModeBit = (0x01UL << A.AddrMode);
1645
1646 /* Build the opcode */
1647 A.Opcode = Ins->BaseCode | Sweet16EATab[Ins->ExtCode][A.AddrMode] | A.Reg;
1648
1649 /* Check how many extension bytes are needed and output the instruction */
1650 switch (Sweet16ExtBytes[A.AddrMode]) {
1651
1652 case 0:
1653 Emit0 (A.Opcode);
1654 break;
1655
1656 case 1:
1657 Emit1 (A.Opcode, A.Expr);
1658 break;
1659
1660 case 2:
1661 Emit2 (A.Opcode, A.Expr);
1662 break;
1663
1664 default:
1665 Internal ("Invalid operand byte count: %u", Sweet16ExtBytes[A.AddrMode]);
1666
1667 }
1668}
1669
1670
1671
1672static void PutSweet16Branch (const InsDesc* Ins)
1673/* Handle a sweet16 branch instruction */
1674{
1675 EmitPCRel (Ins->BaseCode, GenBranchExpr (2), 1);
1676}
1677
1678
1679
1680/*****************************************************************************/
1681/* Code */
1682/*****************************************************************************/
1683
1684
1685
1686static int CmpName (const void* Key, const void* Instr)
1687/* Compare function for bsearch */
1688{
1689 return strcmp ((const char*)Key, ((const InsDesc*) Instr)->Mnemonic);
1690}
1691
1692
1693
1694void SetCPU (cpu_t NewCPU)
1695/* Set a new CPU */
1696{
1697 /* Make sure the parameter is correct */
1698 CHECK (NewCPU < CPU_COUNT);
1699
1700 /* Check if we have support for the new CPU, if so, use it */
1701 if (NewCPU != CPU_UNKNOWN && InsTabs[NewCPU]) {
1702 CPU = NewCPU;
1703 InsTab = InsTabs[CPU];
1704 } else {
1705 Error ("CPU not supported");
1706 }
1707}
1708
1709
1710
1711cpu_t GetCPU (void)
1712/* Return the current CPU */
1713{
1714 return CPU;
1715}
1716
1717
1718
1719int FindInstruction (const StrBuf* Ident)
1720/* Check if Ident is a valid mnemonic. If so, return the index in the
1721** instruction table. If not, return -1.
1722*/
1723{
1724 unsigned I;
1725 const InsDesc* ID;
1726 char Key[sizeof (ID->Mnemonic)];
1727
1728 /* Shortcut for the "none" CPU: If there are no instructions to search
1729 ** for, bail out early.
1730 */
1731 if (InsTab->Count == 0) {
1732 /* Not found */
1733 return -1;
1734 }
1735
1736 /* Make a copy, and uppercase that copy */
1737 I = 0;
1738 while (I < SB_GetLen (Ident)) {
1739 /* If the identifier is longer than the longest mnemonic, it cannot
1740 ** be one.
1741 */
1742 if (I >= sizeof (Key) - 1) {
1743 /* Not found, no need for further action */
1744 return -1;
1745 }
1746 Key[I] = toupper ((unsigned char)SB_AtUnchecked (Ident, I));
1747 ++I;
1748 }
1749 Key[I] = '\0';
1750
1751 /* Search for the key */
1752 ID = bsearch (Key, InsTab->Ins, InsTab->Count, sizeof (InsDesc), CmpName);
1753 if (ID == 0) {
1754 /* Not found */
1755 return -1;
1756 } else {
1757 /* Found, return the entry */
1758 return ID - InsTab->Ins;
1759 }
1760}
1761
1762
1763
1764void HandleInstruction (unsigned Index)
1765/* Handle the mnemonic with the given index */
1766{
1767 /* Safety check */
1768 PRECONDITION (Index < InsTab->Count);
1769
1770 /* Skip the mnemonic token */
1771 NextTok ();
1772
1773 /* Call the handler */
1774 InsTab->Ins[Index].Emit (&InsTab->Ins[Index]);
1775}
1776