Statistics
| Branch: | Revision:

root / dyngen.h @ b67d5959

History | View | Annotate | Download (5.3 kB)

1
/*
2
 * dyngen helpers
3
 * 
4
 *  Copyright (c) 2003 Fabrice Bellard
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
 */
20

    
21
int __op_param1, __op_param2, __op_param3;
22
int __op_jmp0, __op_jmp1;
23

    
24
#ifdef __i386__
25
static inline void flush_icache_range(unsigned long start, unsigned long stop)
26
{
27
}
28
#endif
29

    
30
#ifdef __s390__
31
static inline void flush_icache_range(unsigned long start, unsigned long stop)
32
{
33
}
34
#endif
35

    
36
#ifdef __ia64__
37
static inline void flush_icache_range(unsigned long start, unsigned long stop)
38
{
39
}
40
#endif
41

    
42
#ifdef __powerpc__
43

    
44
#define MIN_CACHE_LINE_SIZE 8 /* conservative value */
45

    
46
static void inline flush_icache_range(unsigned long start, unsigned long stop)
47
{
48
    unsigned long p;
49

    
50
    p = start & ~(MIN_CACHE_LINE_SIZE - 1);
51
    stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1);
52
    
53
    for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
54
        asm volatile ("dcbst 0,%0" : : "r"(p) : "memory");
55
    }
56
    asm volatile ("sync" : : : "memory");
57
    for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
58
        asm volatile ("icbi 0,%0" : : "r"(p) : "memory");
59
    }
60
    asm volatile ("sync" : : : "memory");
61
    asm volatile ("isync" : : : "memory");
62
}
63
#endif
64

    
65
#ifdef __alpha__
66
static inline void flush_icache_range(unsigned long start, unsigned long stop)
67
{
68
    asm ("imb");
69
}
70
#endif
71

    
72
#ifdef __sparc__
73

    
74
static void inline flush_icache_range(unsigned long start, unsigned long stop)
75
{
76
        unsigned long p;
77

    
78
        p = start & ~(8UL - 1UL);
79
        stop = (stop + (8UL - 1UL)) & ~(8UL - 1UL);
80

    
81
        for (; p < stop; p += 8)
82
                __asm__ __volatile__("flush\t%0" : : "r" (p));
83
}
84

    
85
#endif
86

    
87
#ifdef __arm__
88
static inline void flush_icache_range(unsigned long start, unsigned long stop)
89
{
90
    register unsigned long _beg __asm ("a1") = start;
91
    register unsigned long _end __asm ("a2") = stop;
92
    register unsigned long _flg __asm ("a3") = 0;
93
    __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg));
94
}
95
#endif
96

    
97
#ifdef __mc68000
98
#include <asm/cachectl.h>
99
static inline void flush_icache_range(unsigned long start, unsigned long stop)
100
{
101
    cacheflush(start,FLUSH_SCOPE_LINE,FLUSH_CACHE_BOTH,stop-start+16);
102
}
103
#endif
104

    
105
#ifdef __alpha__
106

    
107
register int gp asm("$29");
108

    
109
static inline void immediate_ldah(void *p, int val) {
110
    uint32_t *dest = p;
111
    long high = ((val >> 16) + ((val >> 15) & 1)) & 0xffff;
112

    
113
    *dest &= ~0xffff;
114
    *dest |= high;
115
    *dest |= 31 << 16;
116
}
117
static inline void immediate_lda(void *dest, int val) {
118
    *(uint16_t *) dest = val;
119
}
120
void fix_bsr(void *p, int offset) {
121
    uint32_t *dest = p;
122
    *dest &= ~((1 << 21) - 1);
123
    *dest |= (offset >> 2) & ((1 << 21) - 1);
124
}
125

    
126
#endif /* __alpha__ */
127

    
128
#ifdef __arm__
129

    
130
#define MAX_OP_SIZE    (128 * 4) /* in bytes */
131
/* max size of the code that can be generated without calling arm_flush_ldr */
132
#define MAX_FRAG_SIZE  (1024 * 4) 
133
//#define MAX_FRAG_SIZE  (135 * 4) /* for testing */ 
134

    
135
typedef struct LDREntry {
136
    uint8_t *ptr;
137
    uint32_t *data_ptr;
138
} LDREntry;
139

    
140
static LDREntry arm_ldr_table[1024];
141
static uint32_t arm_data_table[1024];
142

    
143
extern char exec_loop;
144

    
145
static inline void arm_reloc_pc24(uint32_t *ptr, uint32_t insn, int val)
146
{
147
    *ptr = (insn & ~0xffffff) | ((insn + ((val - (int)ptr) >> 2)) & 0xffffff);
148
}
149

    
150
static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
151
                              LDREntry *ldr_start, LDREntry *ldr_end, 
152
                              uint32_t *data_start, uint32_t *data_end, 
153
                              int gen_jmp)
154
{
155
    LDREntry *le;
156
    uint32_t *ptr;
157
    int offset, data_size, target;
158
    uint8_t *data_ptr;
159
    uint32_t insn;
160
 
161
    data_size = (uint8_t *)data_end - (uint8_t *)data_start;
162

    
163
    if (gen_jmp) {
164
        /* generate branch to skip the data */
165
        if (data_size == 0)
166
            return gen_code_ptr;
167
        target = (long)gen_code_ptr + data_size + 4;
168
        arm_reloc_pc24((uint32_t *)gen_code_ptr, 0xeafffffe, target);
169
        gen_code_ptr += 4;
170
    }
171
   
172
    /* copy the data */
173
    data_ptr = gen_code_ptr;
174
    memcpy(gen_code_ptr, data_start, data_size);
175
    gen_code_ptr += data_size;
176
    
177
    /* patch the ldr to point to the data */
178
    for(le = ldr_start; le < ldr_end; le++) {
179
        ptr = (uint32_t *)le->ptr;
180
        offset = ((unsigned long)(le->data_ptr) - (unsigned long)data_start) + 
181
            (unsigned long)data_ptr - 
182
            (unsigned long)ptr - 8;
183
        insn = *ptr & ~(0xfff | 0x00800000);
184
        if (offset < 0) {
185
            offset = - offset;
186
        } else {
187
            insn |= 0x00800000;
188
        }
189
        if (offset > 0xfff) {
190
            fprintf(stderr, "Error ldr offset\n");
191
            abort();
192
        }
193
        insn |= offset;
194
        *ptr = insn;
195
    }
196
    return gen_code_ptr;
197
}
198

    
199
#endif /* __arm__ */
200

    
201
                       
202