|
1 /* |
|
2 * Tiny Code Generator for QEMU |
|
3 * |
|
4 * Copyright (c) 2008 Fabrice Bellard |
|
5 * |
|
6 * Permission is hereby granted, free of charge, to any person obtaining a copy |
|
7 * of this software and associated documentation files (the "Software"), to deal |
|
8 * in the Software without restriction, including without limitation the rights |
|
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
10 * copies of the Software, and to permit persons to whom the Software is |
|
11 * furnished to do so, subject to the following conditions: |
|
12 * |
|
13 * The above copyright notice and this permission notice shall be included in |
|
14 * all copies or substantial portions of the Software. |
|
15 * |
|
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
22 * THE SOFTWARE. |
|
23 */ |
|
24 |
|
25 #define TCG_TARGET_HPPA 1 |
|
26 |
|
27 #if defined(_PA_RISC1_1) |
|
28 #define TCG_TARGET_REG_BITS 32 |
|
29 #else |
|
30 #error unsupported |
|
31 #endif |
|
32 |
|
33 #define TCG_TARGET_WORDS_BIGENDIAN |
|
34 |
|
35 #define TCG_TARGET_NB_REGS 32 |
|
36 |
|
37 enum { |
|
38 TCG_REG_R0 = 0, |
|
39 TCG_REG_R1, |
|
40 TCG_REG_RP, |
|
41 TCG_REG_R3, |
|
42 TCG_REG_R4, |
|
43 TCG_REG_R5, |
|
44 TCG_REG_R6, |
|
45 TCG_REG_R7, |
|
46 TCG_REG_R8, |
|
47 TCG_REG_R9, |
|
48 TCG_REG_R10, |
|
49 TCG_REG_R11, |
|
50 TCG_REG_R12, |
|
51 TCG_REG_R13, |
|
52 TCG_REG_R14, |
|
53 TCG_REG_R15, |
|
54 TCG_REG_R16, |
|
55 TCG_REG_R17, |
|
56 TCG_REG_R18, |
|
57 TCG_REG_R19, |
|
58 TCG_REG_R20, |
|
59 TCG_REG_R21, |
|
60 TCG_REG_R22, |
|
61 TCG_REG_R23, |
|
62 TCG_REG_R24, |
|
63 TCG_REG_R25, |
|
64 TCG_REG_R26, |
|
65 TCG_REG_DP, |
|
66 TCG_REG_RET0, |
|
67 TCG_REG_RET1, |
|
68 TCG_REG_SP, |
|
69 TCG_REG_R31, |
|
70 }; |
|
71 |
|
72 /* used for function call generation */ |
|
73 #define TCG_REG_CALL_STACK TCG_REG_SP |
|
74 #define TCG_TARGET_STACK_ALIGN 16 |
|
75 #define TCG_TARGET_STACK_GROWSUP |
|
76 |
|
77 /* optional instructions */ |
|
78 //#define TCG_TARGET_HAS_ext8s_i32 |
|
79 //#define TCG_TARGET_HAS_ext16s_i32 |
|
80 //#define TCG_TARGET_HAS_bswap16_i32 |
|
81 //#define TCG_TARGET_HAS_bswap_i32 |
|
82 |
|
83 /* Note: must be synced with dyngen-exec.h */ |
|
84 #define TCG_AREG0 TCG_REG_R17 |
|
85 #define TCG_AREG1 TCG_REG_R14 |
|
86 #define TCG_AREG2 TCG_REG_R15 |
|
87 #define TCG_AREG3 TCG_REG_R16 |
|
88 |
|
89 static inline void flush_icache_range(unsigned long start, unsigned long stop) |
|
90 { |
|
91 start &= ~31; |
|
92 while (start <= stop) |
|
93 { |
|
94 asm volatile ("fdc 0(%0)\n" |
|
95 "sync\n" |
|
96 "fic 0(%%sr4, %0)\n" |
|
97 "sync\n" |
|
98 : : "r"(start) : "memory"); |
|
99 start += 32; |
|
100 } |
|
101 } |
|
102 |
|
103 /* supplied by libgcc */ |
|
104 extern void *__canonicalize_funcptr_for_compare(void *); |
|
105 |
|
106 /* Field selection types defined by hppa */ |
|
107 #define rnd(x) (((x)+0x1000)&~0x1fff) |
|
108 /* lsel: select left 21 bits */ |
|
109 #define lsel(v,a) (((v)+(a))>>11) |
|
110 /* rsel: select right 11 bits */ |
|
111 #define rsel(v,a) (((v)+(a))&0x7ff) |
|
112 /* lrsel with rounding of addend to nearest 8k */ |
|
113 #define lrsel(v,a) (((v)+rnd(a))>>11) |
|
114 /* rrsel with rounding of addend to nearest 8k */ |
|
115 #define rrsel(v,a) ((((v)+rnd(a))&0x7ff)+((a)-rnd(a))) |
|
116 |
|
117 #define mask(x,sz) ((x) & ~((1<<(sz))-1)) |
|
118 |
|
119 static inline int reassemble_12(int as12) |
|
120 { |
|
121 return (((as12 & 0x800) >> 11) | |
|
122 ((as12 & 0x400) >> 8) | |
|
123 ((as12 & 0x3ff) << 3)); |
|
124 } |
|
125 |
|
126 static inline int reassemble_14(int as14) |
|
127 { |
|
128 return (((as14 & 0x1fff) << 1) | |
|
129 ((as14 & 0x2000) >> 13)); |
|
130 } |
|
131 |
|
132 static inline int reassemble_17(int as17) |
|
133 { |
|
134 return (((as17 & 0x10000) >> 16) | |
|
135 ((as17 & 0x0f800) << 5) | |
|
136 ((as17 & 0x00400) >> 8) | |
|
137 ((as17 & 0x003ff) << 3)); |
|
138 } |
|
139 |
|
140 static inline int reassemble_21(int as21) |
|
141 { |
|
142 return (((as21 & 0x100000) >> 20) | |
|
143 ((as21 & 0x0ffe00) >> 8) | |
|
144 ((as21 & 0x000180) << 7) | |
|
145 ((as21 & 0x00007c) << 14) | |
|
146 ((as21 & 0x000003) << 12)); |
|
147 } |
|
148 |
|
149 static inline void hppa_patch21l(uint32_t *insn, int val, int addend) |
|
150 { |
|
151 val = lrsel(val, addend); |
|
152 *insn = mask(*insn, 21) | reassemble_21(val); |
|
153 } |
|
154 |
|
155 static inline void hppa_patch14r(uint32_t *insn, int val, int addend) |
|
156 { |
|
157 val = rrsel(val, addend); |
|
158 *insn = mask(*insn, 14) | reassemble_14(val); |
|
159 } |
|
160 |
|
161 static inline void hppa_patch17r(uint32_t *insn, int val, int addend) |
|
162 { |
|
163 val = rrsel(val, addend); |
|
164 *insn = (*insn & ~0x1f1ffd) | reassemble_17(val); |
|
165 } |
|
166 |
|
167 |
|
168 static inline void hppa_patch21l_dprel(uint32_t *insn, int val, int addend) |
|
169 { |
|
170 register unsigned int dp asm("r27"); |
|
171 hppa_patch21l(insn, val - dp, addend); |
|
172 } |
|
173 |
|
174 static inline void hppa_patch14r_dprel(uint32_t *insn, int val, int addend) |
|
175 { |
|
176 register unsigned int dp asm("r27"); |
|
177 hppa_patch14r(insn, val - dp, addend); |
|
178 } |
|
179 |
|
180 static inline void hppa_patch17f(uint32_t *insn, int val, int addend) |
|
181 { |
|
182 int dot = (int)insn & ~0x3; |
|
183 int v = ((val + addend) - dot - 8) / 4; |
|
184 if (v > (1 << 16) || v < -(1 << 16)) { |
|
185 printf("cannot fit branch to offset %d [%08x->%08x]\n", v, dot, val); |
|
186 abort(); |
|
187 } |
|
188 *insn = (*insn & ~0x1f1ffd) | reassemble_17(v); |
|
189 } |
|
190 |
|
191 static inline void hppa_load_imm21l(uint32_t *insn, int val, int addend) |
|
192 { |
|
193 /* Transform addil L'sym(%dp) to ldil L'val, %r1 */ |
|
194 *insn = 0x20200000 | reassemble_21(lrsel(val, 0)); |
|
195 } |
|
196 |
|
197 static inline void hppa_load_imm14r(uint32_t *insn, int val, int addend) |
|
198 { |
|
199 /* Transform ldw R'sym(%r1), %rN to ldo R'sym(%r1), %rN */ |
|
200 hppa_patch14r(insn, val, addend); |
|
201 /* HACK */ |
|
202 if (addend == 0) |
|
203 *insn = (*insn & ~0xfc000000) | (0x0d << 26); |
|
204 } |