some more optimizations
[picodrive.git] / cpu / Cyclone / Ea.cpp
CommitLineData
cc68a136 1\r
2#include "app.h"\r
3\r
4// some ops use non-standard cycle counts for EAs, so are listed here.\r
5// all constants borrowed from the MUSASHI core by Karl Stenerud.\r
6\r
7/* Extra cycles for JMP instruction (000, 010) */\r
8int g_jmp_cycle_table[8] =\r
9{\r
10 4, /* EA_MODE_AI */\r
11 6, /* EA_MODE_DI */\r
12 10, /* EA_MODE_IX */\r
13 6, /* EA_MODE_AW */\r
14 8, /* EA_MODE_AL */\r
15 6, /* EA_MODE_PCDI */\r
16 10, /* EA_MODE_PCIX */\r
17 0, /* EA_MODE_I */\r
18};\r
19\r
20/* Extra cycles for JSR instruction (000, 010) */\r
21int g_jsr_cycle_table[8] =\r
22{\r
23 4, /* EA_MODE_AI */\r
24 6, /* EA_MODE_DI */\r
25 10, /* EA_MODE_IX */\r
26 6, /* EA_MODE_AW */\r
27 8, /* EA_MODE_AL */\r
28 6, /* EA_MODE_PCDI */\r
29 10, /* EA_MODE_PCIX */\r
30 0, /* EA_MODE_I */\r
31};\r
32\r
33/* Extra cycles for LEA instruction (000, 010) */\r
34int g_lea_cycle_table[8] =\r
35{\r
36 4, /* EA_MODE_AI */\r
37 8, /* EA_MODE_DI */\r
38 12, /* EA_MODE_IX */\r
39 8, /* EA_MODE_AW */\r
40 12, /* EA_MODE_AL */\r
41 8, /* EA_MODE_PCDI */\r
42 12, /* EA_MODE_PCIX */\r
43 0, /* EA_MODE_I */\r
44};\r
45\r
46/* Extra cycles for PEA instruction (000, 010) */\r
47int g_pea_cycle_table[8] =\r
48{\r
49 6, /* EA_MODE_AI */\r
50 10, /* EA_MODE_DI */\r
51 14, /* EA_MODE_IX */\r
52 10, /* EA_MODE_AW */\r
53 14, /* EA_MODE_AL */\r
54 10, /* EA_MODE_PCDI */\r
55 14, /* EA_MODE_PCIX */\r
56 0, /* EA_MODE_I */\r
57};\r
58\r
59/* Extra cycles for MOVEM instruction (000, 010) */\r
60int g_movem_cycle_table[8] =\r
61{\r
62 0, /* EA_MODE_AI */\r
63 4, /* EA_MODE_DI */\r
64 6, /* EA_MODE_IX */\r
65 4, /* EA_MODE_AW */\r
66 8, /* EA_MODE_AL */\r
67 0, /* EA_MODE_PCDI */\r
68 0, /* EA_MODE_PCIX */\r
69 0, /* EA_MODE_I */\r
70};\r
71\r
72// add nonstandard EA\r
73int Ea_add_ns(int *tab, int ea)\r
74{\r
a6785576 75 if(ea<0x10) return 0;\r
76 if((ea&0x38)==0x10) return tab[0]; // (An) (ai)\r
77 if(ea<0x28) return 0;\r
78 if(ea<0x30) return tab[1]; // ($nn,An) (di)\r
79 if(ea<0x38) return tab[2]; // ($nn,An,Rn) (ix)\r
80 if(ea==0x38) return tab[3]; // (aw)\r
81 if(ea==0x39) return tab[4]; // (al)\r
82 if(ea==0x3a) return tab[5]; // ($nn,PC) (pcdi)\r
83 if(ea==0x3b) return tab[6]; // ($nn,pc,Rn) (pcix)\r
84 if(ea==0x3c) return tab[7]; // #$nnnn (i)\r
85 return 0;\r
cc68a136 86}\r
87\r
88\r
89// ---------------------------------------------------------------------------\r
90// Gets the offset of a register for an ea, and puts it in 'r'\r
91// Shifted left by 'shift'\r
92// Doesn't trash anything\r
93static int EaCalcReg(int r,int ea,int mask,int forceor,int shift,int noshift=0)\r
94{\r
95 int i=0,low=0,needor=0;\r
96 int lsl=0;\r
97\r
98 for (i=mask|0x8000; (i&1)==0; i>>=1) low++; // Find out how high up the EA mask is\r
99 mask&=0xf<<low; // This is the max we can do\r
100\r
101 if (ea>=8) needor=1; // Need to OR to access A0-7\r
102\r
103 if ((mask>>low)&8) if (ea&8) needor=0; // Ah - no we don't actually need to or, since the bit is high in r8\r
104\r
105 if (forceor) needor=1; // Special case for 0x30-0x38 EAs ;)\r
106\r
107 ot(" and r%d,r8,#0x%.4x\n",r,mask);\r
108 if (needor) ot(" orr r%d,r%d,#0x%x ;@ A0-7\n",r,r,8<<low);\r
109\r
110 // Find out amount to shift left:\r
111 lsl=shift-low;\r
112\r
113 if (lsl&&!noshift)\r
114 {\r
115 ot(" mov r%d,r%d,",r,r);\r
116 if (lsl>0) ot("lsl #%d\n", lsl);\r
117 else ot("lsr #%d\n",-lsl);\r
118 }\r
119\r
120 return 0;\r
121}\r
122\r
123// EaCalc - ARM Register 'a' = Effective Address\r
124// Trashes r0,r2 and r3\r
125// size values 0, 1, 2 ~ byte, word, long\r
b637c56a 126int EaCalc(int a,int mask,int ea,int size,int top,int sign_extend)\r
cc68a136 127{\r
128 char text[32]="";\r
129 int func=0;\r
130\r
131 DisaPc=2; DisaGetEa(text,ea,size); // Get text version of the effective address\r
132 func=0x68+(size<<2); // Get correct read handler\r
133\r
134 if (ea<0x10)\r
135 {\r
136 int noshift=0;\r
b637c56a 137 if (size>=2||(size==0&&(top||!sign_extend))) noshift=1; // Saves one opcode\r
cc68a136 138\r
139 ot(";@ EaCalc : Get register index into r%d:\n",a);\r
140\r
141 EaCalcReg(a,ea,mask,0,2,noshift);\r
142 return 0;\r
143 }\r
144 \r
145 ot(";@ EaCalc : Get '%s' into r%d:\n",text,a);\r
146 // (An), (An)+, -(An)\r
147 if (ea<0x28)\r
148 {\r
149 int step=1<<size, strr=a;\r
a6785576 150 int low=0,lsl,i;\r
cc68a136 151\r
152 if ((ea&7)==7 && step<2) step=2; // move.b (a7)+ or -(a7) steps by 2 not 1\r
153\r
154 EaCalcReg(2,ea,mask,0,0,1);\r
a6785576 155 if(mask)\r
cc68a136 156 for (i=mask|0x8000; (i&1)==0; i>>=1) low++; // Find out how high up the EA mask is\r
a6785576 157 lsl=2-low; // Having a lsl #x here saves one opcode\r
cc68a136 158 if (lsl>=0) ot(" ldr r%d,[r7,r2,lsl #%i]\n",a,lsl);\r
159 else if (lsl<0) ot(" ldr r%d,[r7,r2,lsr #%i]\n",a,-lsl);\r
160\r
161 if ((ea&0x38)==0x18) // (An)+\r
a6785576 162 {\r
cc68a136 163 ot(" add r3,r%d,#%d ;@ Post-increment An\n",a,step);\r
a6785576 164 strr=3;\r
165 }\r
cc68a136 166\r
167 if ((ea&0x38)==0x20) // -(An)\r
168 ot(" sub r%d,r%d,#%d ;@ Pre-decrement An\n",a,a,step);\r
169\r
170 if ((ea&0x38)==0x18||(ea&0x38)==0x20)\r
a6785576 171 {\r
cc68a136 172 if (lsl>=0) ot(" str r%d,[r7,r2,lsl #%i]\n",strr,lsl);\r
173 else if (lsl<0) ot(" str r%d,[r7,r2,lsr #%i]\n",strr,-lsl);\r
174 }\r
175\r
176 if ((ea&0x38)==0x20) Cycles+=size<2 ? 6:10; // -(An) Extra cycles\r
177 else Cycles+=size<2 ? 4:8; // (An),(An)+ Extra cycles\r
178 return 0;\r
179 }\r
180\r
181 if (ea<0x30) // ($nn,An) (di)\r
182 {\r
cfb3dfa0 183 ot(" ldrsh r0,[r4],#2 ;@ Fetch offset\n"); pc_dirty=1;\r
b637c56a 184 EaCalcReg(2,8,mask,0,0);\r
cc68a136 185 ot(" ldr r2,[r7,r2,lsl #2]\n");\r
186 ot(" add r%d,r0,r2 ;@ Add on offset\n",a);\r
187 Cycles+=size<2 ? 8:12; // Extra cycles\r
188 return 0;\r
189 }\r
190\r
191 if (ea<0x38) // ($nn,An,Rn) (ix)\r
192 {\r
193 ot(";@ Get extension word into r3:\n");\r
cfb3dfa0 194 ot(" ldrh r3,[r4],#2 ;@ ($Disp,PC,Rn)\n"); pc_dirty=1;\r
cc68a136 195 ot(" mov r2,r3,lsr #10\n");\r
196 ot(" tst r3,#0x0800 ;@ Is Rn Word or Long\n");\r
197 ot(" and r2,r2,#0x3c ;@ r2=Index of Rn\n");\r
198 ot(" ldreqsh r2,[r7,r2] ;@ r2=Rn.w\n");\r
199 ot(" ldrne r2,[r7,r2] ;@ r2=Rn.l\n");\r
200 ot(" mov r0,r3,asl #24 ;@ r0=Get 8-bit signed Disp\n");\r
201 ot(" add r3,r2,r0,asr #24 ;@ r3=Disp+Rn\n");\r
202\r
203 EaCalcReg(2,8,mask,1,0);\r
204 ot(" ldr r2,[r7,r2,lsl #2]\n");\r
205 ot(" add r%d,r2,r3 ;@ r%d=Disp+An+Rn\n",a,a);\r
206 Cycles+=size<2 ? 10:14; // Extra cycles\r
207 return 0;\r
208 }\r
209\r
210 if (ea==0x38) // (aw)\r
211 {\r
cfb3dfa0 212 ot(" ldrsh r%d,[r4],#2 ;@ Fetch Absolute Short address\n",a); pc_dirty=1;\r
cc68a136 213 Cycles+=size<2 ? 8:12; // Extra cycles\r
214 return 0;\r
215 }\r
216\r
217 if (ea==0x39) // (al)\r
218 {\r
219 ot(" ldrh r2,[r4],#2 ;@ Fetch Absolute Long address\n");\r
cfb3dfa0 220 ot(" ldrh r0,[r4],#2\n"); pc_dirty=1;\r
cc68a136 221 ot(" orr r%d,r0,r2,lsl #16\n",a);\r
222 Cycles+=size<2 ? 12:16; // Extra cycles\r
223 return 0;\r
224 }\r
225\r
226 if (ea==0x3a) // ($nn,PC) (pcdi)\r
227 {\r
228 ot(" ldr r0,[r7,#0x60] ;@ Get Memory base\n");\r
229 ot(" sub r0,r4,r0 ;@ Real PC\n");\r
cfb3dfa0 230 ot(" ldrsh r2,[r4],#2 ;@ Fetch extension\n"); pc_dirty=1;\r
cc68a136 231 ot(" mov r0,r0,lsl #8\n");\r
232 ot(" add r%d,r2,r0,asr #8 ;@ ($nn,PC)\n",a);\r
233 Cycles+=size<2 ? 8:12; // Extra cycles\r
234 return 0;\r
235 }\r
236\r
237 if (ea==0x3b) // ($nn,pc,Rn) (pcix)\r
238 {\r
239 ot(" ldr r0,[r7,#0x60] ;@ Get Memory base\n");\r
240 ot(" ldrh r3,[r4] ;@ Get extension word\n");\r
241 ot(" sub r0,r4,r0 ;@ r0=PC\n");\r
cfb3dfa0 242 ot(" add r4,r4,#2\n"); pc_dirty=1;\r
cc68a136 243 ot(" mov r0,r0,asl #8 ;@ use only 24bits of PC\n");\r
244 ot(" mov r2,r3,lsr #10\n");\r
245 ot(" tst r3,#0x0800 ;@ Is Rn Word or Long\n");\r
246 ot(" and r2,r2,#0x3c ;@ r2=Index of Rn\n");\r
247 ot(" ldreqsh r2,[r7,r2] ;@ r2=Rn.w\n");\r
248 ot(" ldrne r2,[r7,r2] ;@ r2=Rn.l\n");\r
249 ot(" mov r3,r3,asl #24 ;@ r3=Get 8-bit signed Disp\n");\r
250 ot(" add r2,r2,r3,asr #24 ;@ r2=Disp+Rn\n");\r
251 ot(" add r%d,r2,r0,asr #8 ;@ r%d=Disp+PC+Rn\n",a,a);\r
252 Cycles+=size<2 ? 10:14; // Extra cycles\r
253 return 0;\r
254 }\r
255\r
256 if (ea==0x3c) // #$nnnn (i)\r
257 {\r
258 if (size<2)\r
259 {\r
cfb3dfa0 260 ot(" ldr%s r%d,[r4],#2 ;@ Fetch immediate value\n",Sarm[size&3],a); pc_dirty=1;\r
cc68a136 261 Cycles+=4; // Extra cycles\r
262 return 0;\r
263 }\r
264\r
265 ot(" ldrh r2,[r4],#2 ;@ Fetch immediate value\n");\r
cfb3dfa0 266 ot(" ldrh r0,[r4],#2\n"); pc_dirty=1;\r
cc68a136 267 ot(" orr r%d,r0,r2,lsl #16\n",a);\r
268 Cycles+=8; // Extra cycles\r
269 return 0;\r
270 }\r
271\r
272 return 1;\r
273}\r
274\r
275// ---------------------------------------------------------------------------\r
276// Read effective address in (ARM Register 'a') to ARM register 'v'\r
277// 'a' and 'v' can be anything but 0 is generally best (for both)\r
278// If (ea<0x10) nothing is trashed, else r0-r3 is trashed\r
279// If 'top' is given, the ARM register v shifted to the top, e.g. 0xc000 -> 0xc0000000\r
b637c56a 280// If top is 0 and sign_extend is not, then ARM register v is sign extended,\r
281// e.g. 0xc000 -> 0xffffc000 (else it may or may not be sign extended)\r
cc68a136 282\r
b637c56a 283int EaRead(int a,int v,int ea,int size,int mask,int top,int sign_extend)\r
cc68a136 284{\r
285 char text[32]="";\r
286 int shift=0;\r
3a5e6cf8 287 \r
cc68a136 288 shift=32-(8<<size);\r
289\r
290 DisaPc=2; DisaGetEa(text,ea,size); // Get text version of the effective address\r
291\r
292 if (ea<0x10)\r
293 {\r
3a5e6cf8 294 int lsl=0,low=0,nsarm=size&3,i;\r
b637c56a 295 if (size>=2||(size==0&&(top||!sign_extend))) {\r
a6785576 296 if(mask)\r
cc68a136 297 for (i=mask|0x8000; (i&1)==0; i>>=1) low++; // Find out how high up the EA mask is\r
a6785576 298 lsl=2-low; // Having a lsl #2 here saves one opcode\r
299 }\r
cc68a136 300\r
3a5e6cf8 301 if (top) nsarm=3;\r
302\r
cc68a136 303 ot(";@ EaRead : Read register[r%d] into r%d:\n",a,v);\r
304\r
3a5e6cf8 305 if (lsl>0) ot(" ldr%s r%d,[r7,r%d,lsl #%i]\n",Narm[nsarm],v,a,lsl);\r
306 else if (lsl<0) ot(" ldr%s r%d,[r7,r%d,lsr #%i]\n",Narm[nsarm],v,a,-lsl);\r
307 else ot(" ldr%s r%d,[r7,r%d]\n",Sarm[nsarm],v,a);\r
cc68a136 308\r
3a5e6cf8 309 if (top&&shift) ot(" mov r%d,r%d,asl #%d\n",v,v,shift);\r
cc68a136 310\r
311 ot("\n"); return 0;\r
312 }\r
313\r
314 ot(";@ EaRead : Read '%s' (address in r%d) into r%d:\n",text,a,v);\r
315\r
316 if (ea==0x3c)\r
317 {\r
318 int asl=0;\r
319\r
320 if (top) asl=shift;\r
321\r
b637c56a 322 if (asl) ot(" mov r%d,r%d,asl #%d\n",v,a,asl);\r
323 else if (v!=a) ot(" mov r%d,r%d\n",v,a);\r
cc68a136 324 ot("\n"); return 0;\r
325 }\r
326\r
cfb3dfa0 327 if (ea>=0x3a && ea<=0x3b) MemHandler(2,size,a); // Fetch\r
328 else MemHandler(0,size,a); // Read\r
cc68a136 329\r
b637c56a 330 if (sign_extend)\r
331 {\r
332 int d_reg=0;\r
333 if (shift) {\r
334 ot(" mov r%d,r%d,asl #%d\n",v,d_reg,shift);\r
335 d_reg=v;\r
336 }\r
337 if (!top && shift) {\r
338 ot(" mov r%d,r%d,asr #%d\n",v,d_reg,shift);\r
339 d_reg=v;\r
340 }\r
341 if (d_reg != v)\r
342 ot(" mov r%d,r%d\n",v,d_reg);\r
343 }\r
344 else\r
345 {\r
346 if (top && shift)\r
347 ot(" mov r%d,r0,asl #%d\n",v,shift);\r
348 else if (v!=0)\r
349 ot(" mov r%d,r0\n",v);\r
cc68a136 350 }\r
cc68a136 351\r
352 ot("\n"); return 0;\r
353}\r
354\r
355// Return 1 if we can read this ea\r
356int EaCanRead(int ea,int size)\r
357{\r
358 if (size<0)\r
359 {\r
360 // LEA:\r
361 // These don't make sense?:\r
362 if (ea< 0x10) return 0; // Register\r
363 if (ea==0x3c) return 0; // Immediate\r
364 if (ea>=0x18 && ea<0x28) return 0; // Pre/Post inc/dec An\r
365 }\r
366\r
367 if (ea<=0x3c) return 1;\r
368 return 0;\r
369}\r
370\r
371// ---------------------------------------------------------------------------\r
372// Write effective address (ARM Register 'a') with ARM register 'v'\r
373// Trashes r0-r3,r12,lr; 'a' can be 0 or 2+, 'v' can be 1 or higher\r
374// If a==0 and v==1 it's faster though.\r
b637c56a 375int EaWrite(int a,int v,int ea,int size,int mask,int top,int sign_extend_ea)\r
cc68a136 376{\r
377 char text[32]="";\r
378 int shift=0;\r
379\r
380 if(a == 1) { printf("Error! EaWrite a==1 !\n"); return 1; }\r
381\r
382 if (top) shift=32-(8<<size);\r
383\r
384 DisaPc=2; DisaGetEa(text,ea,size); // Get text version of the effective address\r
385\r
386 if (ea<0x10)\r
387 {\r
388 int lsl=0,low=0,i;\r
b637c56a 389 if (size>=2||(size==0&&(top||!sign_extend_ea))) {\r
a6785576 390 if(mask)\r
cc68a136 391 for (i=mask|0x8000; (i&1)==0; i>>=1) low++; // Find out how high up the EA mask is\r
a6785576 392 lsl=2-low; // Having a lsl #x here saves one opcode\r
393 }\r
cc68a136 394\r
395 ot(";@ EaWrite: r%d into register[r%d]:\n",v,a);\r
396 if (shift) ot(" mov r%d,r%d,asr #%d\n",v,v,shift);\r
397\r
398 if (lsl>0) ot(" str%s r%d,[r7,r%d,lsl #%i]\n",Narm[size&3],v,a,lsl);\r
399 else if (lsl<0) ot(" str%s r%d,[r7,r%d,lsr #%i]\n",Narm[size&3],v,a,-lsl);\r
400 else ot(" str%s r%d,[r7,r%d]\n",Narm[size&3],v,a);\r
401\r
402 ot("\n"); return 0;\r
403 }\r
404\r
405 ot(";@ EaWrite: Write r%d into '%s' (address in r%d):\n",v,text,a);\r
406\r
407 if (ea==0x3c) { ot("Error! Write EA=0x%x\n\n",ea); return 1; }\r
408\r
b637c56a 409 if (shift) ot(" mov r1,r%d,asr #%d\n",v,shift);\r
410 else if (v!=1) ot(" mov r1,r%d\n",v);\r
cc68a136 411\r
cfb3dfa0 412 MemHandler(1,size,a); // Call write handler\r
cc68a136 413\r
414 ot("\n"); return 0;\r
415}\r
416\r
417// Return 1 if we can write this ea\r
418int EaCanWrite(int ea)\r
419{\r
420 if (ea<=0x39) return 1; // 3b?\r
421 return 0;\r
422}\r
423// ---------------------------------------------------------------------------\r
424\r
425// Return 1 if EA is An reg\r
426int EaAn(int ea)\r
427{\r
428 if((ea&0x38)==8) return 1;\r
429 return 0;\r
430}\r
431\r