cc15090d287cca6f2cc61278356e6ae4aacf5f1e
[cacao.git] / src / vm / jit / alpha / md.c
1 /* src/vm/jit/alpha/md.c - machine dependent Alpha functions
2
3    Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25 */
26
27
28 #include "config.h"
29
30 #include <assert.h>
31 #include <stdint.h>
32 #include <ucontext.h>
33
34 #if defined(__LINUX__)
35 # include <asm/fpu.h>
36
37 extern unsigned long ieee_get_fp_control();
38 extern void ieee_set_fp_control(unsigned long fp_control);
39 #endif
40
41 #include "vm/types.h"
42
43 #include "vm/jit/alpha/codegen.h"
44 #include "vm/jit/alpha/md-abi.h"
45
46 #include "vm/exceptions.h"
47
48 #include "vm/jit/asmpart.h"
49 #include "vm/jit/codegen-common.h"
50 #include "vm/jit/jit.h"
51 #include "vm/jit/md.h"
52
53
54 /* global variables ***********************************************************/
55
56 bool has_ext_instr_set = false;             /* has instruction set extensions */
57
58
59 /* md_init *********************************************************************
60
61    Do some machine dependent initialization.
62
63 *******************************************************************************/
64
65 void md_init(void)
66 {
67 #if defined(__LINUX__)
68         unsigned long int fpcw;
69 #endif
70
71         /* check for extended instruction set */
72
73         has_ext_instr_set = !asm_md_init();
74
75 #if defined(__LINUX__)
76         /* Linux on Digital Alpha needs an initialisation of the ieee
77            floating point control for IEEE compliant arithmetic (option
78            -mieee of GCC). Under Digital Unix this is done
79            automatically. */
80
81         /* initialize floating point control */
82
83         fpcw = ieee_get_fp_control();
84
85         fpcw = fpcw
86                 & ~IEEE_TRAP_ENABLE_INV
87                 & ~IEEE_TRAP_ENABLE_DZE
88                 /* We dont want underflow. */
89 /*              & ~IEEE_TRAP_ENABLE_UNF */
90                 & ~IEEE_TRAP_ENABLE_OVF;
91
92 /*      fpcw = fpcw */
93 /*              | IEEE_TRAP_ENABLE_INV */
94 /*              | IEEE_TRAP_ENABLE_DZE */
95 /*              | IEEE_TRAP_ENABLE_OVF */
96 /*              | IEEE_TRAP_ENABLE_UNF */
97 /*              | IEEE_TRAP_ENABLE_INE */
98 /*              | IEEE_TRAP_ENABLE_DNO; */
99
100         ieee_set_fp_control(fpcw);
101 #endif
102 }
103
104
105 /* md_stacktrace_get_returnaddress *********************************************
106
107    Returns the return address of the current stackframe, specified by
108    the passed stack pointer and the stack frame size.
109
110 *******************************************************************************/
111
112 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
113 {
114         u1 *ra;
115
116         /* on Alpha the return address is located on the top of the stackframe */
117
118         ra = *((u1 **) (sp + framesize - SIZEOF_VOID_P));
119
120         return ra;
121 }
122
123
124 /* md_jit_method_patch_address *************************************************
125
126    Gets the patch address of the currently compiled method. The offset
127    is extracted from the load instruction(s) before the jump and added
128    to the right base address (PV or REG_METHODPTR).
129
130    INVOKESTATIC/SPECIAL:
131
132    a77bffb8    ldq     pv,-72(pv)
133    6b5b4000    jsr     (pv)
134
135    INVOKEVIRTUAL:
136
137    a7900000    ldq     at,0(a0)
138    a77c0000    ldq     pv,0(at)
139    6b5b4000    jsr     (pv)
140
141    INVOKEINTERFACE:
142
143    a7900000    ldq     at,0(a0)
144    a79cff98    ldq     at,-104(at)
145    a77c0018    ldq     pv,24(at)
146    6b5b4000    jsr     (pv)
147
148 *******************************************************************************/
149
150 void *md_jit_method_patch_address(void *pv, void *ra, void *mptr)
151 {
152         uint32_t *pc;
153         uint32_t  mcode;
154         int       opcode;
155         int       base;
156         int32_t   disp;
157         void     *pa;                       /* patch address                      */
158
159         /* Go back to the load instruction (2 instructions). */
160
161         pc = ((uint32_t *) ra) - 2;
162
163         /* Get first instruction word. */
164
165         mcode = pc[0];
166
167         /* Get opcode, base register and displacement. */
168
169         opcode = M_MEM_GET_Opcode(mcode);
170         base   = M_MEM_GET_Rb(mcode);
171         disp   = M_MEM_GET_Memory_disp(mcode);
172
173         /* Check for short or long load (2 instructions). */
174
175         switch (opcode) {
176         case 0x29: /* LDQ: TODO use define */
177                 switch (base) {
178                 case REG_PV:
179                         /* Calculate the data segment address. */
180
181                         pa = ((uint8_t *) pv) + disp;
182                         break;
183
184                 case REG_METHODPTR:
185                         /* Return NULL if no mptr was specified (used for
186                            replacement). */
187
188                         if (mptr == NULL)
189                                 return NULL;
190
191                         /* Calculate the address in the vftbl. */
192
193                         pa = ((uint8_t *) mptr) + disp;
194                         break;
195
196                 default:
197                         vm_abort_disassemble(pc, 2, "md_jit_method_patch_address: unknown instruction %x", mcode);
198                         return NULL;
199                 }
200                 break;
201
202         case 0x09: /* LDAH: TODO use define */
203                 /* XXX write a regression for this */
204
205                 vm_abort("md_jit_method_patch_address: IMPLEMENT ME!");
206
207                 pa = NULL;
208                 break;
209
210         default:
211                 vm_abort_disassemble(pc, 2, "md_jit_method_patch_address: unknown instruction %x", mcode);
212                 return NULL;
213         }
214
215         return pa;
216 }
217
218
219 /* md_codegen_get_pv_from_pc ***************************************************
220
221    Machine code:
222
223    6b5b4000    jsr     (pv)
224    277afffe    ldah    pv,-2(ra)
225    237ba61c    lda     pv,-23012(pv)
226
227 *******************************************************************************/
228
229 u1 *md_codegen_get_pv_from_pc(u1 *ra)
230 {
231         uint32_t *pc;
232         uint32_t  mcode;
233         int       opcode;
234         int32_t   disp;
235         void     *pv;
236
237         pc = (uint32_t *) ra;
238
239         /* Get first instruction word after jump. */
240
241         mcode = pc[0];
242
243         /* Get opcode and displacement. */
244
245         opcode = M_MEM_GET_Opcode(mcode);
246         disp   = M_MEM_GET_Memory_disp(mcode);
247
248         /* Check for short or long load (2 instructions). */
249
250         switch (opcode) {
251         case 0x08: /* LDA: TODO use define */
252                 assert((mcode >> 16) == 0x237a);
253
254                 pv = ((uint8_t *) pc) + disp;
255                 break;
256
257         case 0x09: /* LDAH: TODO use define */
258                 pv = ((uint8_t *) pc) + (disp << 16);
259
260                 /* Get displacement of second instruction (LDA). */
261
262                 mcode = pc[1];
263
264                 assert((mcode >> 16) == 0x237b);
265
266                 disp = M_MEM_GET_Memory_disp(mcode);
267
268                 pv = ((uint8_t *) pv) + disp;
269                 break;
270
271         default:
272                 vm_abort_disassemble(pc, 2, "md_codegen_get_pv_from_pc: unknown instruction %x", mcode);
273                 return NULL;
274         }
275
276         return pv;
277 }
278
279
280 /* md_cacheflush ***************************************************************
281
282    Calls the system's function to flush the instruction and data
283    cache.
284
285 *******************************************************************************/
286
287 void md_cacheflush(u1 *addr, s4 nbytes)
288 {
289         asm_cacheflush(addr, nbytes);
290 }
291
292
293 /* md_icacheflush **************************************************************
294
295    Calls the system's function to flush the instruction cache.
296
297 *******************************************************************************/
298
299 void md_icacheflush(u1 *addr, s4 nbytes)
300 {
301         asm_cacheflush(addr, nbytes);
302 }
303
304
305 /* md_dcacheflush **************************************************************
306
307    Calls the system's function to flush the data cache.
308
309 *******************************************************************************/
310
311 void md_dcacheflush(u1 *addr, s4 nbytes)
312 {
313         /* do nothing */
314 }
315
316
317 /* md_patch_replacement_point **************************************************
318
319    Patch the given replacement point.
320
321 *******************************************************************************/
322
323 #if defined(ENABLE_REPLACEMENT)
324 void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert)
325 {
326         u4 mcode;
327
328         if (revert) {
329                 /* restore the patched-over instruction */
330                 *(u4*)(pc) = *(u4*)(savedmcode);
331         }
332         else {
333                 /* save the current machine code */
334                 *(u4*)(savedmcode) = *(u4*)(pc);
335
336                 /* build the machine code for the patch */
337                 mcode = (0xa41f0000 | (EXCEPTION_HARDWARE_PATCHER));
338
339                 /* write the new machine code */
340                 *(u4*)(pc) = mcode;
341         }
342         
343         /* flush instruction cache */
344     md_icacheflush(pc,4);
345 }
346 #endif /* defined(ENABLE_REPLACEMENT) */
347
348
349 /*
350  * These are local overrides for various environment variables in Emacs.
351  * Please do not remove this and leave it at the end of the file, where
352  * Emacs will automagically detect them.
353  * ---------------------------------------------------------------------
354  * Local variables:
355  * mode: c
356  * indent-tabs-mode: t
357  * c-basic-offset: 4
358  * tab-width: 4
359  * End:
360  * vim:noexpandtab:sw=4:ts=4:
361  */