]> git.sur5r.net Git - cc65/blob - src/cc65/opcodes.c
b9e51903644285b5040f77cc5a61ca197fe0e18f
[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[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              },
65     { OPC_BIT, "bit", 0, REG_A,    REG_NONE, OF_NONE                        },
66     { OPC_BMI, "bmi", 2, REG_NONE, REG_NONE, OF_CBRA                        },
67     { OPC_BNE, "bne", 2, REG_NONE, REG_NONE, OF_CBRA | OF_ZBRA              },
68     { OPC_BPL, "bpl", 2, REG_NONE, REG_NONE, OF_CBRA                        },
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    },
92     { OPC_JMI, "jmi", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA              },
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    },
95     { OPC_JPL, "jpl", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA              },
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_NONE                        },
125     { OPC_TAY, "tay", 1, REG_A,    REG_Y,    OF_NONE                        },
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_NONE                        },
129     { OPC_TXA, "txa", 1, REG_X,    REG_A,    OF_NONE                        },
130     { OPC_TXS, "txs", 1, REG_X,    REG_NONE, OF_NONE                        },
131     { OPC_TYA, "tya", 1, REG_A,    REG_A,    OF_NONE                        },
132 };
133
134
135
136 /*****************************************************************************/
137 /*                                   Code                                    */
138 /*****************************************************************************/
139
140
141
142 static int Compare (const void* Key, const void* Desc)
143 /* Compare function for bsearch */
144 {
145     return strcmp (Key, ((OPCDesc*)Desc)->Mnemo);
146 }
147
148
149
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.
153  */
154 {
155     unsigned I;
156     unsigned Len;
157
158     /* Check the length of the given string, then copy it into local
159      * storage, converting it to upper case.
160      */
161     char Mnemo[sizeof (OPCTable[0].Mnemo)];
162     Len = strlen (M);
163     if (Len >= sizeof (OPCTable[0].Mnemo)) {
164         /* Invalid length means invalid opcode */
165         return 0;
166     }
167     for (I = 0; I < Len; ++I) {
168         Mnemo[I] = tolower (M[I]);
169     }
170     Mnemo[I] = '\0';
171
172     /* Search for the mnemonic in the table and return the result */
173     return bsearch (Mnemo, OPCTable, OPC_COUNT, sizeof (OPCTable[0]), Compare);
174 }
175
176
177
178 unsigned GetInsnSize (opc_t OPC, am_t AM)
179 /* Return the size of the given instruction */
180 {
181     /* Get the opcode desc and check the size given there */
182     const OPCDesc* D = &OPCTable[OPC];
183     if (D->Size != 0) {
184         return D->Size;
185     }
186
187     /* Check the addressing mode. */
188     switch (AM) {
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;
200         default:          FAIL ("Invalid addressing mode");
201     }
202 }
203
204
205
206 unsigned char GetAMUseInfo (am_t AM)
207 /* Get usage info for the given addressing mode (addressing modes that use
208  * index registers return REG_r info for these registers).
209  */
210 {
211     /* Check the addressing mode. */
212     switch (AM) {
213         case AM_ACC:      return REG_A;
214         case AM_ZPX:      return REG_X;
215         case AM_ABSX:     return REG_X;
216         case AM_ABSY:     return REG_Y;
217         case AM_ZPX_IND:  return REG_X;
218         case AM_ZP_INDY:  return REG_Y;
219         default:          return REG_NONE;
220     }
221 }
222
223
224
225 opc_t GetInverseBranch (opc_t OPC)
226 /* Return a branch that reverse the condition of the branch given in OPC */
227 {
228     switch (OPC) {
229         case OPC_BCC:   return OPC_BCS;
230         case OPC_BCS:   return OPC_BCC;
231         case OPC_BEQ:   return OPC_BNE;
232         case OPC_BMI:   return OPC_BPL;
233         case OPC_BNE:   return OPC_BEQ;
234         case OPC_BPL:   return OPC_BMI;
235         case OPC_BVC:   return OPC_BVS;
236         case OPC_BVS:   return OPC_BVC;
237         case OPC_JCC:   return OPC_JCS;
238         case OPC_JCS:   return OPC_JCC;
239         case OPC_JEQ:   return OPC_JNE;
240         case OPC_JMI:   return OPC_JPL;
241         case OPC_JNE:   return OPC_JEQ;
242         case OPC_JPL:   return OPC_JMI;
243         case OPC_JVC:   return OPC_JVS;
244         case OPC_JVS:   return OPC_JVC;
245         default:        Internal ("GetInverseBranch: Invalid opcode: %d", OPC);
246     }
247 }
248
249
250
251 opc_t MakeShortBranch (opc_t OPC)
252 /* Return the short version of the given branch. If the branch is already
253  * a short branch, return the opcode unchanged.
254  */
255 {
256     switch (OPC) {
257         case OPC_BCC:
258         case OPC_JCC:   return OPC_BCC;
259         case OPC_BCS:
260         case OPC_JCS:   return OPC_BCS;
261         case OPC_BEQ:
262         case OPC_JEQ:   return OPC_BEQ;
263         case OPC_BMI:
264         case OPC_JMI:   return OPC_BMI;
265         case OPC_BNE:
266         case OPC_JNE:   return OPC_BNE;
267         case OPC_BPL:
268         case OPC_JPL:   return OPC_BPL;
269         case OPC_BVC:
270         case OPC_JVC:   return OPC_BVC;
271         case OPC_BVS:
272         case OPC_JVS:   return OPC_BVS;
273         case OPC_BRA:
274         case OPC_JMP:   return (CPU == CPU_65C02)? OPC_BRA : OPC_JMP;
275         default:        Internal ("GetShortBranch: Invalid opcode: %d", OPC);
276     }
277 }
278
279
280
281 opc_t MakeLongBranch (opc_t OPC)
282 /* Return the long version of the given branch. If the branch is already
283  * a long branch, return the opcode unchanged.
284  */
285 {
286     switch (OPC) {
287         case OPC_BCC:
288         case OPC_JCC:   return OPC_JCC;
289         case OPC_BCS:
290         case OPC_JCS:   return OPC_JCS;
291         case OPC_BEQ:
292         case OPC_JEQ:   return OPC_JEQ;
293         case OPC_BMI:
294         case OPC_JMI:   return OPC_JMI;
295         case OPC_BNE:
296         case OPC_JNE:   return OPC_JNE;
297         case OPC_BPL:
298         case OPC_JPL:   return OPC_JPL;
299         case OPC_BVC:
300         case OPC_JVC:   return OPC_JVC;
301         case OPC_BVS:
302         case OPC_JVS:   return OPC_JVS;
303         case OPC_BRA:
304         case OPC_JMP:   return OPC_JMP;
305         default:        Internal ("GetShortBranch: Invalid opcode: %d", OPC);
306     }
307 }
308
309
310
311 bc_t GetBranchCond (opc_t OPC)
312 /* Get the condition for the conditional branch in OPC */
313 {
314     switch (OPC) {
315         case OPC_BCC:   return BC_CC;
316         case OPC_BCS:   return BC_CS;
317         case OPC_BEQ:   return BC_EQ;
318         case OPC_BMI:   return BC_MI;
319         case OPC_BNE:   return BC_NE;
320         case OPC_BPL:   return BC_PL;
321         case OPC_BVC:   return BC_VC;
322         case OPC_BVS:   return BC_VS;
323         case OPC_JCC:   return BC_CC;
324         case OPC_JCS:   return BC_CS;
325         case OPC_JEQ:   return BC_EQ;
326         case OPC_JMI:   return BC_MI;
327         case OPC_JNE:   return BC_NE;
328         case OPC_JPL:   return BC_PL;
329         case OPC_JVC:   return BC_VC;
330         case OPC_JVS:   return BC_VS;
331         default:        Internal ("GetBranchCond: Invalid opcode: %d", OPC);
332     }
333 }
334
335
336
337 bc_t GetInverseCond (bc_t BC)
338 /* Return the inverse condition of the given one */
339 {
340     switch (BC) {
341         case BC_CC:     return BC_CS;
342         case BC_CS:     return BC_CC;
343         case BC_EQ:     return BC_NE;
344         case BC_MI:     return BC_PL;
345         case BC_NE:     return BC_EQ;
346         case BC_PL:     return BC_MI;
347         case BC_VC:     return BC_VS;
348         case BC_VS:     return BC_VC;
349         default:        Internal ("GetInverseCond: Invalid condition: %d", BC);
350     }
351 }
352
353
354
355 opc_t GetLongBranch (bc_t BC)
356 /* Return a long branch for the given branch condition */
357 {
358     switch (BC) {
359         case BC_CC:     return OPC_JCC;
360         case BC_CS:     return OPC_JCS;
361         case BC_EQ:     return OPC_JEQ;
362         case BC_MI:     return OPC_JMI;
363         case BC_NE:     return OPC_JNE;
364         case BC_PL:     return OPC_JPL;
365         case BC_VC:     return OPC_JVC;
366         case BC_VS:     return OPC_JVS;
367         default:        Internal ("GetLongBranch: Invalid condition: %d", BC);
368     }
369 }
370
371
372
373 opc_t GetShortBranch (bc_t BC)
374 /* Return a short branch for the given branch condition */
375 {
376     switch (BC) {
377         case BC_CC:     return OPC_BCC;
378         case BC_CS:     return OPC_BCS;
379         case BC_EQ:     return OPC_BEQ;
380         case BC_MI:     return OPC_BMI;
381         case BC_NE:     return OPC_BNE;
382         case BC_PL:     return OPC_BPL;
383         case BC_VC:     return OPC_BVC;
384         case BC_VS:     return OPC_BVS;
385         default:        Internal ("GetShortBranch: Invalid condition: %d", BC);
386     }
387 }
388
389
390