1 | /*****************************************************************************/ |
2 | /* */ |
3 | /* coptc02.h */ |
4 | /* */ |
5 | /* 65C02 specific optimizations */ |
6 | /* */ |
7 | /* */ |
8 | /* */ |
9 | /* (C) 2001-2012, Ullrich von Bassewitz */ |
10 | /* Roeerstrasse 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 <string.h> |
37 | |
38 | /* cc65 */ |
39 | #include "codeent.h" |
40 | #include "codeinfo.h" |
41 | #include "error.h" |
42 | #include "coptc02.h" |
43 | |
44 | |
45 | |
46 | /*****************************************************************************/ |
47 | /* Data */ |
48 | /*****************************************************************************/ |
49 | |
50 | |
51 | |
52 | /*****************************************************************************/ |
53 | /* Helper functions */ |
54 | /*****************************************************************************/ |
55 | |
56 | |
57 | |
58 | /*****************************************************************************/ |
59 | /* Code */ |
60 | /*****************************************************************************/ |
61 | |
62 | |
63 | |
64 | unsigned Opt65C02Ind (CodeSeg* S) |
65 | /* Try to use the indirect addressing mode where possible */ |
66 | { |
67 | unsigned Changes = 0; |
68 | unsigned I; |
69 | |
70 | /* Walk over the entries */ |
71 | I = 0; |
72 | while (I < CS_GetEntryCount (S)) { |
73 | |
74 | /* Get next entry */ |
75 | CodeEntry* E = CS_GetEntry (S, I); |
76 | |
77 | /* Check for addressing mode indirect indexed Y where Y is zero. |
78 | ** Note: All opcodes that are available as (zp),y are also available |
79 | ** as (zp), so we can ignore the actual opcode here. |
80 | */ |
81 | if (E->AM == AM65_ZP_INDY && E->RI->In.RegY == 0) { |
82 | |
83 | /* Replace it by indirect addressing mode */ |
84 | CodeEntry* X = NewCodeEntry (E->OPC, AM65_ZP_IND, E->Arg, 0, E->LI); |
85 | CS_InsertEntry (S, X, I+1); |
86 | CS_DelEntry (S, I); |
87 | |
88 | /* We had changes */ |
89 | ++Changes; |
90 | |
91 | } |
92 | |
93 | /* Next entry */ |
94 | ++I; |
95 | |
96 | } |
97 | |
98 | /* Return the number of changes made */ |
99 | return Changes; |
100 | } |
101 | |
102 | |
103 | |
104 | unsigned Opt65C02BitOps (CodeSeg* S) |
105 | /* Use special bit op instructions of the C02 */ |
106 | { |
107 | unsigned Changes = 0; |
108 | unsigned I; |
109 | |
110 | /* Walk over the entries */ |
111 | I = 0; |
112 | while (I < CS_GetEntryCount (S)) { |
113 | |
114 | CodeEntry* L[3]; |
115 | |
116 | /* Get next entry */ |
117 | L[0] = CS_GetEntry (S, I); |
118 | |
119 | /* Check for the sequence */ |
120 | if (L[0]->OPC == OP65_LDA && |
121 | (L[0]->AM == AM65_ZP || L[0]->AM == AM65_ABS) && |
122 | !CS_RangeHasLabel (S, I+1, 2) && |
123 | CS_GetEntries (S, L+1, I+1, 2) && |
124 | (L[1]->OPC == OP65_AND || L[1]->OPC == OP65_ORA) && |
125 | CE_IsConstImm (L[1]) && |
126 | L[2]->OPC == OP65_STA && |
127 | L[2]->AM == L[0]->AM && |
128 | strcmp (L[2]->Arg, L[0]->Arg) == 0 && |
129 | !RegAUsed (S, I+3)) { |
130 | |
131 | char Buf[32]; |
132 | CodeEntry* X; |
133 | |
134 | /* Use TRB for AND and TSB for ORA */ |
135 | if (L[1]->OPC == OP65_AND) { |
136 | |
137 | /* LDA #XX */ |
138 | sprintf (Buf, "$%02X" , (int) ((~L[1]->Num) & 0xFF)); |
139 | X = NewCodeEntry (OP65_LDA, AM65_IMM, Buf, 0, L[1]->LI); |
140 | CS_InsertEntry (S, X, I+3); |
141 | |
142 | /* TRB */ |
143 | X = NewCodeEntry (OP65_TRB, L[0]->AM, L[0]->Arg, 0, L[0]->LI); |
144 | CS_InsertEntry (S, X, I+4); |
145 | |
146 | } else { |
147 | |
148 | /* LDA #XX */ |
149 | sprintf (Buf, "$%02X" , (int) L[1]->Num); |
150 | X = NewCodeEntry (OP65_LDA, AM65_IMM, Buf, 0, L[1]->LI); |
151 | CS_InsertEntry (S, X, I+3); |
152 | |
153 | /* TSB */ |
154 | X = NewCodeEntry (OP65_TSB, L[0]->AM, L[0]->Arg, 0, L[0]->LI); |
155 | CS_InsertEntry (S, X, I+4); |
156 | } |
157 | |
158 | /* Delete the old stuff */ |
159 | CS_DelEntries (S, I, 3); |
160 | |
161 | /* We had changes */ |
162 | ++Changes; |
163 | } |
164 | |
165 | /* Next entry */ |
166 | ++I; |
167 | |
168 | } |
169 | |
170 | /* Return the number of changes made */ |
171 | return Changes; |
172 | } |
173 | |
174 | |
175 | |
176 | unsigned Opt65C02Stores (CodeSeg* S) |
177 | /* Use STZ where possible */ |
178 | { |
179 | unsigned Changes = 0; |
180 | unsigned I; |
181 | |
182 | /* Walk over the entries */ |
183 | I = 0; |
184 | while (I < CS_GetEntryCount (S)) { |
185 | |
186 | /* Get next entry */ |
187 | CodeEntry* E = CS_GetEntry (S, I); |
188 | |
189 | /* Check for a store with a register value of zero and an addressing |
190 | ** mode available with STZ. |
191 | */ |
192 | if (((E->OPC == OP65_STA && E->RI->In.RegA == 0) || |
193 | (E->OPC == OP65_STX && E->RI->In.RegX == 0) || |
194 | (E->OPC == OP65_STY && E->RI->In.RegY == 0)) && |
195 | (E->AM == AM65_ZP || E->AM == AM65_ABS || |
196 | E->AM == AM65_ZPX || E->AM == AM65_ABSX)) { |
197 | |
198 | /* Replace by STZ */ |
199 | CodeEntry* X = NewCodeEntry (OP65_STZ, E->AM, E->Arg, 0, E->LI); |
200 | CS_InsertEntry (S, X, I+1); |
201 | |
202 | /* Delete the old stuff */ |
203 | CS_DelEntry (S, I); |
204 | |
205 | /* We had changes */ |
206 | ++Changes; |
207 | } |
208 | |
209 | /* Next entry */ |
210 | ++I; |
211 | |
212 | } |
213 | |
214 | /* Return the number of changes made */ |
215 | return Changes; |
216 | } |
217 | |