9ad99b7474b6f982d1c66ea557be178a04f453a7
[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, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27
28 #include <stdint.h>
29 #include <ucontext.h>
30
31 #if defined(__LINUX__)
32 # include <asm/fpu.h>
33
34 extern unsigned long ieee_get_fp_control();
35 extern void ieee_set_fp_control(unsigned long fp_control);
36 #endif
37
38 #include "vm/jit/alpha/codegen.h"
39 #include "vm/jit/alpha/md.h"
40
41 #include "vm/jit/asmpart.h"
42 #include "vm/jit/jit.hpp"
43 #include "vm/jit/trap.h"
44
45
46 /* global variables ***********************************************************/
47
48 bool has_ext_instr_set = false;             /* has instruction set extensions */
49
50
51 /* md_init *********************************************************************
52
53    Do some machine dependent initialization.
54
55 *******************************************************************************/
56
57 void md_init(void)
58 {
59 #if defined(__LINUX__)
60         unsigned long int fpcw;
61 #endif
62
63         /* check for extended instruction set */
64
65         has_ext_instr_set = !asm_md_init();
66
67 #if defined(__LINUX__)
68         /* Linux on Digital Alpha needs an initialisation of the ieee
69            floating point control for IEEE compliant arithmetic (option
70            -mieee of GCC). Under Digital Unix this is done
71            automatically. */
72
73         /* initialize floating point control */
74
75         fpcw = ieee_get_fp_control();
76
77         fpcw = fpcw
78                 & ~IEEE_TRAP_ENABLE_INV
79                 & ~IEEE_TRAP_ENABLE_DZE
80                 /* We dont want underflow. */
81 /*              & ~IEEE_TRAP_ENABLE_UNF */
82                 & ~IEEE_TRAP_ENABLE_OVF;
83
84 /*      fpcw = fpcw */
85 /*              | IEEE_TRAP_ENABLE_INV */
86 /*              | IEEE_TRAP_ENABLE_DZE */
87 /*              | IEEE_TRAP_ENABLE_OVF */
88 /*              | IEEE_TRAP_ENABLE_UNF */
89 /*              | IEEE_TRAP_ENABLE_INE */
90 /*              | IEEE_TRAP_ENABLE_DNO; */
91
92         ieee_set_fp_control(fpcw);
93 #endif
94 }
95
96
97 /* md_jit_method_patch_address *************************************************
98
99    Gets the patch address of the currently compiled method. The offset
100    is extracted from the load instruction(s) before the jump and added
101    to the right base address (PV or REG_METHODPTR).
102
103    INVOKESTATIC/SPECIAL:
104
105    a77bffb8    ldq     pv,-72(pv)
106    6b5b4000    jsr     (pv)
107
108    INVOKEVIRTUAL:
109
110    a7900000    ldq     at,0(a0)
111    a77c0000    ldq     pv,0(at)
112    6b5b4000    jsr     (pv)
113
114    INVOKEINTERFACE:
115
116    a7900000    ldq     at,0(a0)
117    a79cff98    ldq     at,-104(at)
118    a77c0018    ldq     pv,24(at)
119    6b5b4000    jsr     (pv)
120
121 *******************************************************************************/
122
123 void *md_jit_method_patch_address(void *pv, void *ra, void *mptr)
124 {
125         uint32_t *pc;
126         uint32_t  mcode;
127         int       opcode;
128         int       base;
129         int32_t   disp;
130         void     *pa;                       /* patch address                      */
131
132         /* Go back to the load instruction (2 instructions). */
133
134         pc = ((uint32_t *) ra) - 2;
135
136         /* Get first instruction word. */
137
138         mcode = pc[0];
139
140         /* Get opcode, base register and displacement. */
141
142         opcode = M_MEM_GET_Opcode(mcode);
143         base   = M_MEM_GET_Rb(mcode);
144         disp   = M_MEM_GET_Memory_disp(mcode);
145
146         /* Check for short or long load (2 instructions). */
147
148         switch (opcode) {
149         case 0x29: /* LDQ: TODO use define */
150                 switch (base) {
151                 case REG_PV:
152                         /* Calculate the data segment address. */
153
154                         pa = ((uint8_t *) pv) + disp;
155                         break;
156
157                 case REG_METHODPTR:
158                         /* Return NULL if no mptr was specified (used for
159                            replacement). */
160
161                         if (mptr == NULL)
162                                 return NULL;
163
164                         /* Calculate the address in the vftbl. */
165
166                         pa = ((uint8_t *) mptr) + disp;
167                         break;
168
169                 default:
170                         vm_abort_disassemble(pc, 2, "md_jit_method_patch_address: unknown instruction %x", mcode);
171                         return NULL;
172                 }
173                 break;
174
175         case 0x09: /* LDAH: TODO use define */
176                 /* XXX write a regression for this */
177
178                 vm_abort("md_jit_method_patch_address: IMPLEMENT ME!");
179
180                 pa = NULL;
181                 break;
182
183         default:
184                 vm_abort_disassemble(pc, 2, "md_jit_method_patch_address: unknown instruction %x", mcode);
185                 return NULL;
186         }
187
188         return pa;
189 }
190
191
192 /* md_patch_replacement_point **************************************************
193
194    Patch the given replacement point.
195
196 *******************************************************************************/
197
198 #if defined(ENABLE_REPLACEMENT)
199 void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert)
200 {
201         u4 mcode;
202
203         if (revert) {
204                 /* restore the patched-over instruction */
205                 *(u4*)(pc) = *(u4*)(savedmcode);
206         }
207         else {
208                 /* save the current machine code */
209                 *(u4*)(savedmcode) = *(u4*)(pc);
210
211                 /* build the machine code for the patch */
212                 mcode = (0xa41f0000 | (TRAP_PATCHER));
213
214                 /* write the new machine code */
215                 *(u4*)(pc) = mcode;
216         }
217         
218         /* flush instruction cache */
219     md_icacheflush(pc,4);
220 }
221 #endif /* defined(ENABLE_REPLACEMENT) */
222
223
224 /*
225  * These are local overrides for various environment variables in Emacs.
226  * Please do not remove this and leave it at the end of the file, where
227  * Emacs will automagically detect them.
228  * ---------------------------------------------------------------------
229  * Local variables:
230  * mode: c
231  * indent-tabs-mode: t
232  * c-basic-offset: 4
233  * tab-width: 4
234  * End:
235  * vim:noexpandtab:sw=4:ts=4:
236  */