1 /*****************************************************************************/
5 /* Opcode and addressing mode definitions */
9 /* (C) 2001 Ullrich von Bassewitz */
11 /* D-70597 Stuttgart */
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 /*****************************************************************************/
51 /*****************************************************************************/
53 /*****************************************************************************/
57 /* Opcode description table */
58 const OPCDesc OPCTable[OPC_COUNT] = {
59 { OPC_ADC, "adc", 0, REG_A, REG_A, OF_NONE },
60 { OPC_AND, "and", 0, REG_A, REG_A, OF_NONE },
61 { OPC_ASL, "asl", 0, REG_A, REG_A, OF_NONE },
62 { OPC_BCC, "bcc", 2, REG_NONE, REG_NONE, OF_CBRA },
63 { OPC_BCS, "bcs", 2, REG_NONE, REG_NONE, OF_CBRA },
64 { OPC_BEQ, "beq", 2, REG_NONE, REG_NONE, OF_CBRA | OF_ZBRA | OF_FBRA },
65 { OPC_BIT, "bit", 0, REG_A, REG_NONE, OF_NONE },
66 { OPC_BMI, "bmi", 2, REG_NONE, REG_NONE, OF_CBRA | OF_FBRA },
67 { OPC_BNE, "bne", 2, REG_NONE, REG_NONE, OF_CBRA | OF_ZBRA | OF_FBRA },
68 { OPC_BPL, "bpl", 2, REG_NONE, REG_NONE, OF_CBRA | OF_FBRA },
69 { OPC_BRA, "bra", 2, REG_NONE, REG_NONE, OF_UBRA },
70 { OPC_BRK, "brk", 1, REG_NONE, REG_NONE, OF_NONE },
71 { OPC_BVC, "bvc", 2, REG_NONE, REG_NONE, OF_CBRA },
72 { OPC_BVS, "bvs", 2, REG_NONE, REG_NONE, OF_CBRA },
73 { OPC_CLC, "clc", 1, REG_NONE, REG_NONE, OF_NONE },
74 { OPC_CLD, "cld", 1, REG_NONE, REG_NONE, OF_NONE },
75 { OPC_CLI, "cli", 1, REG_NONE, REG_NONE, OF_NONE },
76 { OPC_CLV, "clv", 1, REG_NONE, REG_NONE, OF_NONE },
77 { OPC_CMP, "cmp", 0, REG_A, REG_NONE, OF_NONE },
78 { OPC_CPX, "cpx", 0, REG_X, REG_NONE, OF_NONE },
79 { OPC_CPY, "cpy", 0, REG_Y, REG_NONE, OF_NONE },
80 { OPC_DEA, "dea", 1, REG_A, REG_A, OF_NONE },
81 { OPC_DEC, "dec", 0, REG_NONE, REG_NONE, OF_NONE },
82 { OPC_DEX, "dex", 1, REG_X, REG_X, OF_NONE },
83 { OPC_DEY, "dey", 1, REG_Y, REG_Y, OF_NONE },
84 { OPC_EOR, "eor", 0, REG_A, REG_A, OF_NONE },
85 { OPC_INA, "ina", 1, REG_A, REG_A, OF_NONE },
86 { OPC_INC, "inc", 0, REG_NONE, REG_NONE, OF_NONE },
87 { OPC_INX, "inx", 1, REG_X, REG_X, OF_NONE },
88 { OPC_INY, "iny", 1, REG_Y, REG_Y, OF_NONE },
89 { OPC_JCC, "jcc", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
90 { OPC_JCS, "jcs", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
91 { OPC_JEQ, "jeq", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA | OF_ZBRA | OF_FBRA },
92 { OPC_JMI, "jmi", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA | OF_FBRA },
93 { OPC_JMP, "jmp", 3, REG_NONE, REG_NONE, OF_UBRA | OF_LBRA },
94 { OPC_JNE, "jne", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA | OF_ZBRA | OF_FBRA },
95 { OPC_JPL, "jpl", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA | OF_FBRA },
96 { OPC_JSR, "jsr", 3, REG_NONE, REG_NONE, OF_NONE },
97 { OPC_JVC, "jvc", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
98 { OPC_JVS, "jvs", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
99 { OPC_LDA, "lda", 0, REG_NONE, REG_A, OF_LOAD },
100 { OPC_LDX, "ldx", 0, REG_NONE, REG_X, OF_LOAD },
101 { OPC_LDY, "ldy", 0, REG_NONE, REG_Y, OF_LOAD },
102 { OPC_LSR, "lsr", 0, REG_A, REG_A, OF_NONE },
103 { OPC_NOP, "nop", 1, REG_NONE, REG_NONE, OF_NONE },
104 { OPC_ORA, "ora", 0, REG_A, REG_A, OF_NONE },
105 { OPC_PHA, "pha", 1, REG_A, REG_NONE, OF_NONE },
106 { OPC_PHP, "php", 1, REG_NONE, REG_NONE, OF_NONE },
107 { OPC_PHX, "phx", 1, REG_X, REG_NONE, OF_NONE },
108 { OPC_PHY, "phy", 1, REG_Y, REG_NONE, OF_NONE },
109 { OPC_PLA, "pla", 1, REG_NONE, REG_A, OF_NONE },
110 { OPC_PLP, "plp", 1, REG_NONE, REG_NONE, OF_NONE },
111 { OPC_PLX, "plx", 1, REG_NONE, REG_X, OF_NONE },
112 { OPC_PLY, "ply", 1, REG_NONE, REG_Y, OF_NONE },
113 { OPC_ROL, "rol", 0, REG_A, REG_A, OF_NONE },
114 { OPC_ROR, "ror", 0, REG_A, REG_A, OF_NONE },
115 { OPC_RTI, "rti", 1, REG_NONE, REG_NONE, OF_RET },
116 { OPC_RTS, "rts", 1, REG_NONE, REG_NONE, OF_RET },
117 { OPC_SBC, "sbc", 0, REG_A, REG_A, OF_NONE },
118 { OPC_SEC, "sec", 1, REG_NONE, REG_NONE, OF_NONE },
119 { OPC_SED, "sed", 1, REG_NONE, REG_NONE, OF_NONE },
120 { OPC_SEI, "sei", 1, REG_NONE, REG_NONE, OF_NONE },
121 { OPC_STA, "sta", 0, REG_A, REG_NONE, OF_NONE },
122 { OPC_STX, "stx", 0, REG_X, REG_NONE, OF_NONE },
123 { OPC_STY, "sty", 0, REG_Y, REG_NONE, OF_NONE },
124 { OPC_TAX, "tax", 1, REG_A, REG_X, OF_XFR },
125 { OPC_TAY, "tay", 1, REG_A, REG_Y, OF_XFR },
126 { OPC_TRB, "trb", 0, REG_A, REG_NONE, OF_NONE },
127 { OPC_TSB, "tsb", 0, REG_A, REG_NONE, OF_NONE },
128 { OPC_TSX, "tsx", 1, REG_NONE, REG_X, OF_XFR },
129 { OPC_TXA, "txa", 1, REG_X, REG_A, OF_XFR },
130 { OPC_TXS, "txs", 1, REG_X, REG_NONE, OF_XFR },
131 { OPC_TYA, "tya", 1, REG_A, REG_A, OF_XFR },
136 /*****************************************************************************/
138 /*****************************************************************************/
142 static int Compare (const void* Key, const void* Desc)
143 /* Compare function for bsearch */
145 return strcmp (Key, ((OPCDesc*)Desc)->Mnemo);
150 const OPCDesc* FindOpcode (const char* M)
151 /* Find the given opcode and return the opcode number. If the opcode was not
152 * found, return OPC_INVALID.
158 /* Check the length of the given string, then copy it into local
159 * storage, converting it to upper case.
161 char Mnemo[sizeof (OPCTable[0].Mnemo)];
163 if (Len >= sizeof (OPCTable[0].Mnemo)) {
164 /* Invalid length means invalid opcode */
167 for (I = 0; I < Len; ++I) {
168 Mnemo[I] = tolower (M[I]);
172 /* Search for the mnemonic in the table and return the result */
173 return bsearch (Mnemo, OPCTable, OPC_COUNT, sizeof (OPCTable[0]), Compare);
178 unsigned GetInsnSize (opc_t OPC, am_t AM)
179 /* Return the size of the given instruction */
181 /* Get the opcode desc and check the size given there */
182 const OPCDesc* D = &OPCTable[OPC];
187 /* Check the addressing mode. */
189 case AM_IMP: return 1;
190 case AM_ACC: return 1;
191 case AM_IMM: return 2;
192 case AM_ZP: return 2;
193 case AM_ZPX: return 2;
194 case AM_ABS: return 3;
195 case AM_ABSX: return 3;
196 case AM_ABSY: return 3;
197 case AM_ZPX_IND: return 2;
198 case AM_ZP_INDY: return 2;
199 case AM_ZP_IND: return 2;
201 Internal ("Invalid addressing mode");
208 unsigned char GetAMUseInfo (am_t AM)
209 /* Get usage info for the given addressing mode (addressing modes that use
210 * index registers return REG_r info for these registers).
213 /* Check the addressing mode. */
215 case AM_ACC: return REG_A;
216 case AM_ZPX: return REG_X;
217 case AM_ABSX: return REG_X;
218 case AM_ABSY: return REG_Y;
219 case AM_ZPX_IND: return REG_X;
220 case AM_ZP_INDY: return REG_Y;
221 default: return REG_NONE;
227 opc_t GetInverseBranch (opc_t OPC)
228 /* Return a branch that reverse the condition of the branch given in OPC */
231 case OPC_BCC: return OPC_BCS;
232 case OPC_BCS: return OPC_BCC;
233 case OPC_BEQ: return OPC_BNE;
234 case OPC_BMI: return OPC_BPL;
235 case OPC_BNE: return OPC_BEQ;
236 case OPC_BPL: return OPC_BMI;
237 case OPC_BVC: return OPC_BVS;
238 case OPC_BVS: return OPC_BVC;
239 case OPC_JCC: return OPC_JCS;
240 case OPC_JCS: return OPC_JCC;
241 case OPC_JEQ: return OPC_JNE;
242 case OPC_JMI: return OPC_JPL;
243 case OPC_JNE: return OPC_JEQ;
244 case OPC_JPL: return OPC_JMI;
245 case OPC_JVC: return OPC_JVS;
246 case OPC_JVS: return OPC_JVC;
248 Internal ("GetInverseBranch: Invalid opcode: %d", OPC);
255 opc_t MakeShortBranch (opc_t OPC)
256 /* Return the short version of the given branch. If the branch is already
257 * a short branch, return the opcode unchanged.
262 case OPC_JCC: return OPC_BCC;
264 case OPC_JCS: return OPC_BCS;
266 case OPC_JEQ: return OPC_BEQ;
268 case OPC_JMI: return OPC_BMI;
270 case OPC_JNE: return OPC_BNE;
272 case OPC_JPL: return OPC_BPL;
274 case OPC_JVC: return OPC_BVC;
276 case OPC_JVS: return OPC_BVS;
278 case OPC_JMP: return (CPU == CPU_65C02)? OPC_BRA : OPC_JMP;
280 Internal ("GetShortBranch: Invalid opcode: %d", OPC);
287 opc_t MakeLongBranch (opc_t OPC)
288 /* Return the long version of the given branch. If the branch is already
289 * a long branch, return the opcode unchanged.
294 case OPC_JCC: return OPC_JCC;
296 case OPC_JCS: return OPC_JCS;
298 case OPC_JEQ: return OPC_JEQ;
300 case OPC_JMI: return OPC_JMI;
302 case OPC_JNE: return OPC_JNE;
304 case OPC_JPL: return OPC_JPL;
306 case OPC_JVC: return OPC_JVC;
308 case OPC_JVS: return OPC_JVS;
310 case OPC_JMP: return OPC_JMP;
312 Internal ("GetShortBranch: Invalid opcode: %d", OPC);
319 bc_t GetBranchCond (opc_t OPC)
320 /* Get the condition for the conditional branch in OPC */
323 case OPC_BCC: return BC_CC;
324 case OPC_BCS: return BC_CS;
325 case OPC_BEQ: return BC_EQ;
326 case OPC_BMI: return BC_MI;
327 case OPC_BNE: return BC_NE;
328 case OPC_BPL: return BC_PL;
329 case OPC_BVC: return BC_VC;
330 case OPC_BVS: return BC_VS;
331 case OPC_JCC: return BC_CC;
332 case OPC_JCS: return BC_CS;
333 case OPC_JEQ: return BC_EQ;
334 case OPC_JMI: return BC_MI;
335 case OPC_JNE: return BC_NE;
336 case OPC_JPL: return BC_PL;
337 case OPC_JVC: return BC_VC;
338 case OPC_JVS: return BC_VS;
340 Internal ("GetBranchCond: Invalid opcode: %d", OPC);
347 bc_t GetInverseCond (bc_t BC)
348 /* Return the inverse condition of the given one */
351 case BC_CC: return BC_CS;
352 case BC_CS: return BC_CC;
353 case BC_EQ: return BC_NE;
354 case BC_MI: return BC_PL;
355 case BC_NE: return BC_EQ;
356 case BC_PL: return BC_MI;
357 case BC_VC: return BC_VS;
358 case BC_VS: return BC_VC;
360 Internal ("GetInverseCond: Invalid condition: %d", BC);
367 opc_t GetLongBranch (bc_t BC)
368 /* Return a long branch for the given branch condition */
371 case BC_CC: return OPC_JCC;
372 case BC_CS: return OPC_JCS;
373 case BC_EQ: return OPC_JEQ;
374 case BC_MI: return OPC_JMI;
375 case BC_NE: return OPC_JNE;
376 case BC_PL: return OPC_JPL;
377 case BC_VC: return OPC_JVC;
378 case BC_VS: return OPC_JVS;
380 Internal ("GetLongBranch: Invalid condition: %d", BC);
387 opc_t GetShortBranch (bc_t BC)
388 /* Return a short branch for the given branch condition */
391 case BC_CC: return OPC_BCC;
392 case BC_CS: return OPC_BCS;
393 case BC_EQ: return OPC_BEQ;
394 case BC_MI: return OPC_BMI;
395 case BC_NE: return OPC_BNE;
396 case BC_PL: return OPC_BPL;
397 case BC_VC: return OPC_BVC;
398 case BC_VS: return OPC_BVS;
400 Internal ("GetShortBranch: Invalid condition: %d", BC);