Statistics
| Branch: | Revision:

root / hw / ppc.c @ 34e538ae

History | View | Annotate | Download (6.2 kB)

1 a541f297 bellard
/*
2 a541f297 bellard
 * QEMU generic PPC hardware System Emulator
3 a541f297 bellard
 * 
4 a541f297 bellard
 * Copyright (c) 2003-2004 Jocelyn Mayer
5 a541f297 bellard
 * 
6 a541f297 bellard
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 a541f297 bellard
 * of this software and associated documentation files (the "Software"), to deal
8 a541f297 bellard
 * in the Software without restriction, including without limitation the rights
9 a541f297 bellard
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 a541f297 bellard
 * copies of the Software, and to permit persons to whom the Software is
11 a541f297 bellard
 * furnished to do so, subject to the following conditions:
12 a541f297 bellard
 *
13 a541f297 bellard
 * The above copyright notice and this permission notice shall be included in
14 a541f297 bellard
 * all copies or substantial portions of the Software.
15 a541f297 bellard
 *
16 a541f297 bellard
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 a541f297 bellard
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 a541f297 bellard
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 a541f297 bellard
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 a541f297 bellard
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 a541f297 bellard
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 a541f297 bellard
 * THE SOFTWARE.
23 a541f297 bellard
 */
24 a541f297 bellard
#include "vl.h"
25 a541f297 bellard
26 a541f297 bellard
void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device,
27 a541f297 bellard
                    DisplayState *ds, const char **fd_filename, int snapshot,
28 a541f297 bellard
                    const char *kernel_filename, const char *kernel_cmdline,
29 a541f297 bellard
                    const char *initrd_filename);
30 a541f297 bellard
31 9fddaa0c bellard
/*****************************************************************************/
32 9fddaa0c bellard
/* PPC time base and decrementer emulation */
33 9fddaa0c bellard
//#define DEBUG_TB
34 9fddaa0c bellard
35 9fddaa0c bellard
struct ppc_tb_t {
36 9fddaa0c bellard
    /* Time base management */
37 9fddaa0c bellard
    int64_t  tb_offset;    /* Compensation               */
38 9fddaa0c bellard
    uint32_t tb_freq;      /* TB frequency               */
39 9fddaa0c bellard
    /* Decrementer management */
40 9fddaa0c bellard
    uint64_t decr_next;    /* Tick for next decr interrupt  */
41 9fddaa0c bellard
    struct QEMUTimer *decr_timer;
42 9fddaa0c bellard
};
43 9fddaa0c bellard
44 9fddaa0c bellard
static inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env)
45 9fddaa0c bellard
{
46 9fddaa0c bellard
    /* TB time in tb periods */
47 9fddaa0c bellard
    return muldiv64(qemu_get_clock(vm_clock) + tb_env->tb_offset,
48 9fddaa0c bellard
                    tb_env->tb_freq, ticks_per_sec);
49 9fddaa0c bellard
}
50 9fddaa0c bellard
51 9fddaa0c bellard
uint32_t cpu_ppc_load_tbl (CPUState *env)
52 9fddaa0c bellard
{
53 9fddaa0c bellard
    ppc_tb_t *tb_env = env->tb_env;
54 9fddaa0c bellard
    uint64_t tb;
55 9fddaa0c bellard
56 9fddaa0c bellard
    tb = cpu_ppc_get_tb(tb_env);
57 9fddaa0c bellard
#ifdef DEBUG_TB
58 9fddaa0c bellard
    {
59 9fddaa0c bellard
         static int last_time;
60 9fddaa0c bellard
         int now;
61 9fddaa0c bellard
         now = time(NULL);
62 9fddaa0c bellard
         if (last_time != now) {
63 9fddaa0c bellard
             last_time = now;
64 9fddaa0c bellard
             printf("%s: tb=0x%016lx %d %08lx\n",
65 9fddaa0c bellard
                    __func__, tb, now, tb_env->tb_offset);
66 9fddaa0c bellard
         }
67 9fddaa0c bellard
    }
68 9fddaa0c bellard
#endif
69 9fddaa0c bellard
70 9fddaa0c bellard
    return tb & 0xFFFFFFFF;
71 9fddaa0c bellard
}
72 9fddaa0c bellard
73 9fddaa0c bellard
uint32_t cpu_ppc_load_tbu (CPUState *env)
74 9fddaa0c bellard
{
75 9fddaa0c bellard
    ppc_tb_t *tb_env = env->tb_env;
76 9fddaa0c bellard
    uint64_t tb;
77 9fddaa0c bellard
78 9fddaa0c bellard
    tb = cpu_ppc_get_tb(tb_env);
79 9fddaa0c bellard
#ifdef DEBUG_TB
80 9fddaa0c bellard
    printf("%s: tb=0x%016lx\n", __func__, tb);
81 9fddaa0c bellard
#endif
82 9fddaa0c bellard
    return tb >> 32;
83 9fddaa0c bellard
}
84 9fddaa0c bellard
85 9fddaa0c bellard
static void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t value)
86 9fddaa0c bellard
{
87 9fddaa0c bellard
    tb_env->tb_offset = muldiv64(value, ticks_per_sec, tb_env->tb_freq)
88 9fddaa0c bellard
        - qemu_get_clock(vm_clock);
89 9fddaa0c bellard
#ifdef DEBUG_TB
90 9fddaa0c bellard
    printf("%s: tb=0x%016lx offset=%08x\n", __func__, value);
91 9fddaa0c bellard
#endif
92 9fddaa0c bellard
}
93 9fddaa0c bellard
94 9fddaa0c bellard
void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
95 9fddaa0c bellard
{
96 9fddaa0c bellard
    ppc_tb_t *tb_env = env->tb_env;
97 9fddaa0c bellard
98 9fddaa0c bellard
    cpu_ppc_store_tb(tb_env,
99 9fddaa0c bellard
                     ((uint64_t)value << 32) | cpu_ppc_load_tbl(env));
100 9fddaa0c bellard
}
101 9fddaa0c bellard
102 9fddaa0c bellard
void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
103 9fddaa0c bellard
{
104 9fddaa0c bellard
    ppc_tb_t *tb_env = env->tb_env;
105 9fddaa0c bellard
106 9fddaa0c bellard
    cpu_ppc_store_tb(tb_env,
107 9fddaa0c bellard
                     ((uint64_t)cpu_ppc_load_tbu(env) << 32) | value);
108 9fddaa0c bellard
}
109 9fddaa0c bellard
110 9fddaa0c bellard
uint32_t cpu_ppc_load_decr (CPUState *env)
111 9fddaa0c bellard
{
112 9fddaa0c bellard
    ppc_tb_t *tb_env = env->tb_env;
113 9fddaa0c bellard
    uint32_t decr;
114 9fddaa0c bellard
115 9fddaa0c bellard
    decr = muldiv64(tb_env->decr_next - qemu_get_clock(vm_clock),
116 9fddaa0c bellard
                    tb_env->tb_freq, ticks_per_sec);
117 9fddaa0c bellard
#ifdef DEBUG_TB
118 9fddaa0c bellard
    printf("%s: 0x%08x\n", __func__, decr);
119 9fddaa0c bellard
#endif
120 9fddaa0c bellard
121 9fddaa0c bellard
    return decr;
122 9fddaa0c bellard
}
123 9fddaa0c bellard
124 9fddaa0c bellard
/* When decrementer expires,
125 9fddaa0c bellard
 * all we need to do is generate or queue a CPU exception
126 9fddaa0c bellard
 */
127 9fddaa0c bellard
static inline void cpu_ppc_decr_excp (CPUState *env)
128 9fddaa0c bellard
{
129 9fddaa0c bellard
    /* Raise it */
130 9fddaa0c bellard
#ifdef DEBUG_TB
131 9fddaa0c bellard
    printf("raise decrementer exception\n");
132 9fddaa0c bellard
#endif
133 9fddaa0c bellard
    cpu_interrupt(env, CPU_INTERRUPT_TIMER);
134 9fddaa0c bellard
}
135 9fddaa0c bellard
136 9fddaa0c bellard
static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr,
137 9fddaa0c bellard
                                 uint32_t value, int is_excp)
138 9fddaa0c bellard
{
139 9fddaa0c bellard
    ppc_tb_t *tb_env = env->tb_env;
140 9fddaa0c bellard
    uint64_t now, next;
141 9fddaa0c bellard
142 9fddaa0c bellard
#ifdef DEBUG_TB
143 9fddaa0c bellard
    printf("%s: 0x%08x => 0x%08x\n", __func__, decr, value);
144 9fddaa0c bellard
#endif
145 9fddaa0c bellard
    now = qemu_get_clock(vm_clock);
146 9fddaa0c bellard
    next = now + muldiv64(value, ticks_per_sec, tb_env->tb_freq);
147 9fddaa0c bellard
    if (is_excp)
148 9fddaa0c bellard
        next += tb_env->decr_next - now;
149 9fddaa0c bellard
    if (next == now)
150 9fddaa0c bellard
        next++;
151 9fddaa0c bellard
    tb_env->decr_next = next;
152 9fddaa0c bellard
    /* Adjust timer */
153 9fddaa0c bellard
    qemu_mod_timer(tb_env->decr_timer, next);
154 9fddaa0c bellard
    /* If we set a negative value and the decrementer was positive,
155 9fddaa0c bellard
     * raise an exception.
156 9fddaa0c bellard
     */
157 9fddaa0c bellard
    if ((value & 0x80000000) && !(decr & 0x80000000))
158 9fddaa0c bellard
        cpu_ppc_decr_excp(env);
159 9fddaa0c bellard
}
160 9fddaa0c bellard
161 9fddaa0c bellard
void cpu_ppc_store_decr (CPUState *env, uint32_t value)
162 9fddaa0c bellard
{
163 9fddaa0c bellard
    _cpu_ppc_store_decr(env, cpu_ppc_load_decr(env), value, 0);
164 9fddaa0c bellard
}
165 9fddaa0c bellard
166 9fddaa0c bellard
static void cpu_ppc_decr_cb (void *opaque)
167 9fddaa0c bellard
{
168 9fddaa0c bellard
    _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1);
169 9fddaa0c bellard
}
170 9fddaa0c bellard
171 9fddaa0c bellard
/* Set up (once) timebase frequency (in Hz) */
172 9fddaa0c bellard
ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq)
173 9fddaa0c bellard
{
174 9fddaa0c bellard
    ppc_tb_t *tb_env;
175 9fddaa0c bellard
176 9fddaa0c bellard
    tb_env = qemu_mallocz(sizeof(ppc_tb_t));
177 9fddaa0c bellard
    if (tb_env == NULL)
178 9fddaa0c bellard
        return NULL;
179 9fddaa0c bellard
    env->tb_env = tb_env;
180 9fddaa0c bellard
    if (tb_env->tb_freq == 0 || 1) {
181 9fddaa0c bellard
        tb_env->tb_freq = freq;
182 9fddaa0c bellard
        /* Create new timer */
183 9fddaa0c bellard
        tb_env->decr_timer =
184 9fddaa0c bellard
            qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env);
185 9fddaa0c bellard
        /* There is a bug in  2.4 kernels:
186 9fddaa0c bellard
         * if a decrementer exception is pending when it enables msr_ee,
187 9fddaa0c bellard
         * it's not ready to handle it...
188 9fddaa0c bellard
         */
189 9fddaa0c bellard
        _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
190 9fddaa0c bellard
    }
191 9fddaa0c bellard
192 9fddaa0c bellard
    return tb_env;
193 9fddaa0c bellard
}
194 9fddaa0c bellard
195 9fddaa0c bellard
#if 0
196 9fddaa0c bellard
/*****************************************************************************/
197 9fddaa0c bellard
/* Handle system reset (for now, just stop emulation) */
198 9fddaa0c bellard
void cpu_ppc_reset (CPUState *env)
199 9fddaa0c bellard
{
200 9fddaa0c bellard
    printf("Reset asked... Stop emulation\n");
201 9fddaa0c bellard
    abort();
202 9fddaa0c bellard
}
203 9fddaa0c bellard
#endif
204 9fddaa0c bellard
205 9fddaa0c bellard
/*****************************************************************************/
206 a541f297 bellard
void ppc_init (int ram_size, int vga_ram_size, int boot_device,
207 a541f297 bellard
               DisplayState *ds, const char **fd_filename, int snapshot,
208 a541f297 bellard
               const char *kernel_filename, const char *kernel_cmdline,
209 a541f297 bellard
               const char *initrd_filename)
210 a541f297 bellard
{
211 a541f297 bellard
    /* For now, only PREP is supported */
212 a541f297 bellard
    return ppc_prep_init(ram_size, vga_ram_size, boot_device, ds, fd_filename,
213 a541f297 bellard
                         snapshot, kernel_filename, kernel_cmdline,
214 a541f297 bellard
                         initrd_filename);
215 a541f297 bellard
}