]> git.sur5r.net Git - cc65/blob - src/cc65/opcodes.c
Working on the backend
[cc65] / src / cc65 / opcodes.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 opcodes.c                                 */
4 /*                                                                           */
5 /*                  Opcode and addressing mode definitions                   */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2001      Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
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 "check.h"
42
43 /* cc65 */
44 #include "codeinfo.h"
45 #include "cpu.h"
46 #include "error.h"
47 #include "opcodes.h"
48
49
50
51 /*****************************************************************************/
52 /*                                   Data                                    */
53 /*****************************************************************************/
54
55
56
57 /* Opcode description table */
58 const OPCDesc OPCTable[OPCODE_COUNT] = {
59
60     /* 65XX opcodes */
61     { OP65_ADC, "adc", 0, REG_A,    REG_A,    OF_NONE                       },
62     { OP65_AND, "and", 0, REG_A,    REG_A,    OF_NONE                       },
63     { OP65_ASL, "asl", 0, REG_A,    REG_A,    OF_NONE                       },
64     { OP65_BCC, "bcc", 2, REG_NONE, REG_NONE, OF_CBRA                       },
65     { OP65_BCS, "bcs", 2, REG_NONE, REG_NONE, OF_CBRA                       },
66     { OP65_BEQ, "beq", 2, REG_NONE, REG_NONE, OF_CBRA | OF_ZBRA | OF_FBRA    },
67     { OP65_BIT, "bit", 0, REG_A,    REG_NONE, OF_NONE                       },
68     { OP65_BMI, "bmi", 2, REG_NONE, REG_NONE, OF_CBRA | OF_FBRA                     },
69     { OP65_BNE, "bne", 2, REG_NONE, REG_NONE, OF_CBRA | OF_ZBRA | OF_FBRA    },
70     { OP65_BPL, "bpl", 2, REG_NONE, REG_NONE, OF_CBRA | OF_FBRA                     },
71     { OP65_BRA, "bra", 2, REG_NONE, REG_NONE, OF_UBRA                       },
72     { OP65_BRK, "brk", 1, REG_NONE, REG_NONE, OF_NONE                       },
73     { OP65_BVC, "bvc", 2, REG_NONE, REG_NONE, OF_CBRA                       },
74     { OP65_BVS, "bvs", 2, REG_NONE, REG_NONE, OF_CBRA                       },
75     { OP65_CLC, "clc", 1, REG_NONE, REG_NONE, OF_NONE                       },
76     { OP65_CLD, "cld", 1, REG_NONE, REG_NONE, OF_NONE                       },
77     { OP65_CLI, "cli", 1, REG_NONE, REG_NONE, OF_NONE                       },
78     { OP65_CLV, "clv", 1, REG_NONE, REG_NONE, OF_NONE                       },
79     { OP65_CMP, "cmp", 0, REG_A,    REG_NONE, OF_NONE                       },
80     { OP65_CPX, "cpx", 0, REG_X,    REG_NONE, OF_NONE                       },
81     { OP65_CPY, "cpy", 0, REG_Y,    REG_NONE, OF_NONE                       },
82     { OP65_DEA, "dea", 1, REG_A,    REG_A,    OF_NONE                       },
83     { OP65_DEC, "dec", 0, REG_NONE, REG_NONE, OF_NONE                       },
84     { OP65_DEX, "dex", 1, REG_X,    REG_X,    OF_NONE                       },
85     { OP65_DEY, "dey", 1, REG_Y,    REG_Y,    OF_NONE                       },
86     { OP65_EOR, "eor", 0, REG_A,    REG_A,    OF_NONE                       },
87     { OP65_INA, "ina", 1, REG_A,    REG_A,    OF_NONE                       },
88     { OP65_INC, "inc", 0, REG_NONE, REG_NONE, OF_NONE                       },
89     { OP65_INX, "inx", 1, REG_X,    REG_X,    OF_NONE                       },
90     { OP65_INY, "iny", 1, REG_Y,    REG_Y,    OF_NONE                       },
91     { OP65_JCC, "jcc", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA             },
92     { OP65_JCS, "jcs", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA             },
93     { OP65_JEQ, "jeq", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA | OF_ZBRA | OF_FBRA },
94     { OP65_JMI, "jmi", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA | OF_FBRA    },
95     { OP65_JMP, "jmp", 3, REG_NONE, REG_NONE, OF_UBRA | OF_LBRA             },
96     { OP65_JNE, "jne", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA | OF_ZBRA | OF_FBRA },
97     { OP65_JPL, "jpl", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA | OF_FBRA    },
98     { OP65_JSR, "jsr", 3, REG_NONE, REG_NONE, OF_CALL                       },
99     { OP65_JVC, "jvc", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA             },
100     { OP65_JVS, "jvs", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA             },
101     { OP65_LDA, "lda", 0, REG_NONE, REG_A,    OF_LOAD                               },
102     { OP65_LDX, "ldx", 0, REG_NONE, REG_X,    OF_LOAD                       },
103     { OP65_LDY, "ldy", 0, REG_NONE, REG_Y,    OF_LOAD                       },
104     { OP65_LSR, "lsr", 0, REG_A,    REG_A,    OF_NONE                       },
105     { OP65_NOP, "nop", 1, REG_NONE, REG_NONE, OF_NONE                       },
106     { OP65_ORA, "ora", 0, REG_A,    REG_A,    OF_NONE                       },
107     { OP65_PHA, "pha", 1, REG_A,    REG_NONE, OF_NONE                       },
108     { OP65_PHP, "php", 1, REG_NONE, REG_NONE, OF_NONE                       },
109     { OP65_PHX, "phx", 1, REG_X,    REG_NONE, OF_NONE                       },
110     { OP65_PHY, "phy", 1, REG_Y,    REG_NONE, OF_NONE                       },
111     { OP65_PLA, "pla", 1, REG_NONE, REG_A,    OF_NONE                       },
112     { OP65_PLP, "plp", 1, REG_NONE, REG_NONE, OF_NONE                       },
113     { OP65_PLX, "plx", 1, REG_NONE, REG_X,    OF_NONE                       },
114     { OP65_PLY, "ply", 1, REG_NONE, REG_Y,    OF_NONE                       },
115     { OP65_ROL, "rol", 0, REG_A,    REG_A,    OF_NONE                       },
116     { OP65_ROR, "ror", 0, REG_A,    REG_A,    OF_NONE                       },
117     { OP65_RTI, "rti", 1, REG_NONE, REG_NONE, OF_RET                        },
118     { OP65_RTS, "rts", 1, REG_NONE, REG_NONE, OF_RET                        },
119     { OP65_SBC, "sbc", 0, REG_A,    REG_A,    OF_NONE                       },
120     { OP65_SEC, "sec", 1, REG_NONE, REG_NONE, OF_NONE                       },
121     { OP65_SED, "sed", 1, REG_NONE, REG_NONE, OF_NONE                       },
122     { OP65_SEI, "sei", 1, REG_NONE, REG_NONE, OF_NONE                       },
123     { OP65_STA, "sta", 0, REG_A,    REG_NONE, OF_NONE                       },
124     { OP65_STX, "stx", 0, REG_X,    REG_NONE, OF_NONE                       },
125     { OP65_STY, "sty", 0, REG_Y,    REG_NONE, OF_NONE                       },
126     { OP65_TAX, "tax", 1, REG_A,    REG_X,    OF_XFR                        },
127     { OP65_TAY, "tay", 1, REG_A,    REG_Y,    OF_XFR                        },
128     { OP65_TRB, "trb", 0, REG_A,    REG_NONE, OF_NONE                       },
129     { OP65_TSB, "tsb", 0, REG_A,    REG_NONE, OF_NONE                       },
130     { OP65_TSX, "tsx", 1, REG_NONE, REG_X,    OF_XFR                        },
131     { OP65_TXA, "txa", 1, REG_X,    REG_A,    OF_XFR                        },
132     { OP65_TXS, "txs", 1, REG_X,    REG_NONE, OF_XFR                        },
133     { OP65_TYA, "tya", 1, REG_A,    REG_A,    OF_XFR                        },
134 };
135
136
137
138 /*****************************************************************************/
139 /*                                   Code                                    */
140 /*****************************************************************************/
141
142
143
144 static int Compare (const void* Key, const void* Desc)
145 /* Compare function for bsearch */
146 {
147     return strcmp (Key, ((OPCDesc*)Desc)->Mnemo);
148 }
149
150
151
152 const OPCDesc* FindOpcode (const char* M)
153 /* Find the given opcode and return the opcode number. If the opcode was not
154  * found, return OP65_INVALID.
155  */
156 {
157     unsigned I;
158     unsigned Len;
159
160     /* Check the length of the given string, then copy it into local
161      * storage, converting it to upper case.
162      */
163     char Mnemo[sizeof (OPCTable[0].Mnemo)];
164     Len = strlen (M);
165     if (Len >= sizeof (OPCTable[0].Mnemo)) {
166         /* Invalid length means invalid opcode */
167         return 0;
168     }
169     for (I = 0; I < Len; ++I) {
170         Mnemo[I] = tolower (M[I]);
171     }
172     Mnemo[I] = '\0';
173
174     /* Search for the mnemonic in the table and return the result */
175     return bsearch (Mnemo, OPCTable, OPCODE_COUNT, sizeof (OPCTable[0]), Compare);
176 }
177
178
179
180 unsigned GetInsnSize (opc_t OPC, am_t AM)
181 /* Return the size of the given instruction */
182 {
183     /* Get the opcode desc and check the size given there */
184     const OPCDesc* D = &OPCTable[OPC];
185     if (D->Size != 0) {
186         return D->Size;
187     }
188
189     /* Check the addressing mode. */
190     switch (AM) {
191         case AM65_IMP:     return 1;
192         case AM65_ACC:     return 1;
193         case AM65_IMM:     return 2;
194         case AM65_ZP:      return 2;
195         case AM65_ZPX:     return 2;
196         case AM65_ABS:     return 3;
197         case AM65_ABSX:    return 3;
198         case AM65_ABSY:    return 3;
199         case AM65_ZPX_IND: return 2;
200         case AM65_ZP_INDY: return 2;
201         case AM65_ZP_IND:  return 2;
202         default:
203             Internal ("Invalid addressing mode");
204             return 0;
205     }
206 }
207
208
209
210 unsigned char GetAMUseInfo (am_t AM)
211 /* Get usage info for the given addressing mode (addressing modes that use
212  * index registers return REG_r info for these registers).
213  */
214 {
215     /* Check the addressing mode. */
216     switch (AM) {
217         case AM65_ACC:     return REG_A;
218         case AM65_ZPX:     return REG_X;
219         case AM65_ABSX:    return REG_X;
220         case AM65_ABSY:    return REG_Y;
221         case AM65_ZPX_IND: return REG_X;
222         case AM65_ZP_INDY: return REG_Y;
223         default:           return REG_NONE;
224     }
225 }
226
227
228
229 opc_t GetInverseBranch (opc_t OPC)
230 /* Return a branch that reverse the condition of the branch given in OPC */
231 {
232     switch (OPC) {
233         case OP65_BCC:  return OP65_BCS;
234         case OP65_BCS:  return OP65_BCC;
235         case OP65_BEQ:  return OP65_BNE;
236         case OP65_BMI:  return OP65_BPL;
237         case OP65_BNE:  return OP65_BEQ;
238         case OP65_BPL:  return OP65_BMI;
239         case OP65_BVC:          return OP65_BVS;
240         case OP65_BVS:  return OP65_BVC;
241         case OP65_JCC:          return OP65_JCS;
242         case OP65_JCS:          return OP65_JCC;
243         case OP65_JEQ:          return OP65_JNE;
244         case OP65_JMI:          return OP65_JPL;
245         case OP65_JNE:          return OP65_JEQ;
246         case OP65_JPL:          return OP65_JMI;
247         case OP65_JVC:          return OP65_JVS;
248         case OP65_JVS:          return OP65_JVC;
249         default:
250             Internal ("GetInverseBranch: Invalid opcode: %d", OPC);
251             return 0;
252     }
253 }
254
255
256
257 opc_t MakeShortBranch (opc_t OPC)
258 /* Return the short version of the given branch. If the branch is already
259  * a short branch, return the opcode unchanged.
260  */
261 {
262     switch (OPC) {
263         case OP65_BCC:
264         case OP65_JCC:          return OP65_BCC;
265         case OP65_BCS:
266         case OP65_JCS:          return OP65_BCS;
267         case OP65_BEQ:
268         case OP65_JEQ:          return OP65_BEQ;
269         case OP65_BMI:
270         case OP65_JMI:          return OP65_BMI;
271         case OP65_BNE:
272         case OP65_JNE:          return OP65_BNE;
273         case OP65_BPL:
274         case OP65_JPL:          return OP65_BPL;
275         case OP65_BVC:
276         case OP65_JVC:          return OP65_BVC;
277         case OP65_BVS:
278         case OP65_JVS:          return OP65_BVS;
279         case OP65_BRA:
280         case OP65_JMP:  return (CPU == CPU_65C02)? OP65_BRA : OP65_JMP;
281         default:
282             Internal ("MakeShortBranch: Invalid opcode: %d", OPC);
283             return 0;
284     }
285 }
286
287
288
289 opc_t MakeLongBranch (opc_t OPC)
290 /* Return the long version of the given branch. If the branch is already
291  * a long branch, return the opcode unchanged.
292  */
293 {
294     switch (OPC) {
295         case OP65_BCC:
296         case OP65_JCC:          return OP65_JCC;
297         case OP65_BCS:
298         case OP65_JCS:          return OP65_JCS;
299         case OP65_BEQ:
300         case OP65_JEQ:          return OP65_JEQ;
301         case OP65_BMI:
302         case OP65_JMI:          return OP65_JMI;
303         case OP65_BNE:
304         case OP65_JNE:          return OP65_JNE;
305         case OP65_BPL:
306         case OP65_JPL:          return OP65_JPL;
307         case OP65_BVC:
308         case OP65_JVC:          return OP65_JVC;
309         case OP65_BVS:
310         case OP65_JVS:          return OP65_JVS;
311         case OP65_BRA:
312         case OP65_JMP:  return OP65_JMP;
313         default:
314             Internal ("MakeLongBranch: Invalid opcode: %d", OPC);
315             return 0;
316     }
317 }
318
319
320
321 bc_t GetBranchCond (opc_t OPC)
322 /* Get the condition for the conditional branch in OPC */
323 {
324     switch (OPC) {
325         case OP65_BCC:          return BC_CC;
326         case OP65_BCS:          return BC_CS;
327         case OP65_BEQ:          return BC_EQ;
328         case OP65_BMI:          return BC_MI;
329         case OP65_BNE:          return BC_NE;
330         case OP65_BPL:          return BC_PL;
331         case OP65_BVC:          return BC_VC;
332         case OP65_BVS:          return BC_VS;
333         case OP65_JCC:          return BC_CC;
334         case OP65_JCS:          return BC_CS;
335         case OP65_JEQ:          return BC_EQ;
336         case OP65_JMI:          return BC_MI;
337         case OP65_JNE:          return BC_NE;
338         case OP65_JPL:          return BC_PL;
339         case OP65_JVC:          return BC_VC;
340         case OP65_JVS:          return BC_VS;
341         default:
342             Internal ("GetBranchCond: Invalid opcode: %d", OPC);
343             return 0;
344     }
345 }
346
347
348
349 bc_t GetInverseCond (bc_t BC)
350 /* Return the inverse condition of the given one */
351 {
352     switch (BC) {
353         case BC_CC:     return BC_CS;
354         case BC_CS:     return BC_CC;
355         case BC_EQ:     return BC_NE;
356         case BC_MI:     return BC_PL;
357         case BC_NE:     return BC_EQ;
358         case BC_PL:     return BC_MI;
359         case BC_VC:     return BC_VS;
360         case BC_VS:     return BC_VC;
361         default:
362             Internal ("GetInverseCond: Invalid condition: %d", BC);
363             return 0;
364     }
365 }
366
367
368